From 43cb7b49b15f59ae1a0dc468b323e5eb0056a228 Mon Sep 17 00:00:00 2001 From: Arek W Date: Tue, 11 Jan 2022 18:51:10 +0100 Subject: [PATCH] Set internal default property value to undefined instead of null. This will prevent null values being explicitly sent to the database when no value was assigned and instead result in the database setting the column to null, or generating a default value. Properties with an internal value of undefined will still return null when accessed. Setting a previously filled property to undefined will still set it to null in the DB. No ORM tests were broken by this change, and as such, the impact of this should be limited ot a very small number of corner cases. Add PostgreSQL uuid column support. Allow specifying defaultExpression (eg. uuid_generate_v4() for PostgreSQL or uuid() for MySQL) to be executed by the database engine for generating default values. --- Changelog.md | 9 +++ lib/Instance.js | 14 +++- lib/Property.js | 2 +- package-lock.json | 10 +-- package.json | 4 +- test/integration/property-uuid.js | 115 ++++++++++++++++++++++++++++++ 6 files changed, 143 insertions(+), 11 deletions(-) create mode 100644 test/integration/property-uuid.js diff --git a/Changelog.md b/Changelog.md index 18cddeca..747b6bcc 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,12 @@ +### v6.0.0 +- [POSSIBLY BREAKING] Set internal default property value to `undefined` instead of `null` ([855](../../pull/855). + - This will prevent `null` values being explicitly sent to the database when no value was assigned and instead result in the database setting the column to null, or generating a default value. + - Properties with an internal value of `undefined` will still return `null` when accessed. + - Setting a previously filled property to `undefined` will still set it to null in the DB. + - No ORM tests were broken by this change, and as such, the impact of this should be limited to a very small number of corner cases. +- Add PostgreSQL `uuid` column support ([855](../../pull/855). +- Allow specifying `defaultExpression` (eg. `uuid_generate_v4()` for PostgreSQL or `uuid()` for MySQL) to be executed by the database engine for generating default values ([855](../../pull/855). + ### v5.0.9 - Add async versions of driver functions ([851](../../pull/851) diff --git a/lib/Instance.js b/lib/Instance.js index e0778fda..2ad70443 100755 --- a/lib/Instance.js +++ b/lib/Instance.js @@ -153,9 +153,11 @@ function Instance(Model, opts) { prop = Model.allProperties[k]; if (prop) { + /* if (opts.data[k] == null && (prop.type == 'serial' || typeof prop.defaultValue == 'function')) { continue; } + */ if (opts.driver.propertyToValue) { data[k] = opts.driver.propertyToValue(opts.data[k], prop); @@ -484,7 +486,7 @@ function Instance(Model, opts) { } var addInstanceProperty = function (key) { - var defaultValue = null; + var defaultValue = undefined; var prop = Model.allProperties[key]; // This code was first added, and then commented out in a later commit. @@ -502,7 +504,13 @@ function Instance(Model, opts) { Object.defineProperty(instance, key, { get: function () { - return opts.data[key]; + var val = opts.data[key]; + + if (val === undefined) { + return null; + } else { + return opts.data[key]; + } }, set: function (val) { if (prop.key === true) { @@ -731,7 +739,7 @@ function Instance(Model, opts) { if (!asc.reversed && !asc.extension) { for (k in asc.field) { - if (!opts.data.hasOwnProperty(k)) { + if (!instance.hasOwnProperty(k)) { addInstanceProperty(k); } } diff --git a/lib/Property.js b/lib/Property.js index 9fb6ae78..29cab0af 100644 --- a/lib/Property.js +++ b/lib/Property.js @@ -3,7 +3,7 @@ var ORMError = require("./Error"); var KNOWN_TYPES = [ "text", "number", "integer", "boolean", "date", "enum", "object", - "binary", "point", "serial" + "binary", "point", "serial", "uuid" ]; exports.normalize = function (opts) { diff --git a/package-lock.json b/package-lock.json index 63f2cb7e..8f372ea1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "orm", - "version": "5.0.9", + "version": "6.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2905,11 +2905,11 @@ "dev": true }, "sql-ddl-sync": { - "version": "0.3.16", - "resolved": "https://registry.npmjs.org/sql-ddl-sync/-/sql-ddl-sync-0.3.16.tgz", - "integrity": "sha512-6uiVLN1UAkL2UFpFLjACLYZkzdkPjtRYAgN0jeJWGE/oNzMFabdYZF26IFcXBgobVZ0g8GLagQTI+b9GNKOV2w==", + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/sql-ddl-sync/-/sql-ddl-sync-0.3.18.tgz", + "integrity": "sha512-KZ+7qa4MIIoZZWDzWijMGheMLPkn/58WHt9//UzF84P1XFqsJ4Xk5Xfg8LlWovFXhoi2SRynX1nRw7zXTV9Yig==", "requires": { - "lodash": "~4.17.15" + "lodash": "~4.17.21" } }, "sql-query": { diff --git a/package.json b/package.json index 13adb7bf..c0c6b6a1 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "sqlite", "mongodb" ], - "version": "5.0.9", + "version": "6.0.0", "license": "MIT", "homepage": "http://dresende.github.io/node-orm2", "repository": "http://github.com/dresende/node-orm2.git", @@ -67,7 +67,7 @@ "hat": "0.0.3", "lodash": "^4.17.21", "path-is-absolute": "1.0.1", - "sql-ddl-sync": "0.3.16", + "sql-ddl-sync": "0.3.18", "sql-query": "0.1.27" }, "devDependencies": { diff --git a/test/integration/property-uuid.js b/test/integration/property-uuid.js new file mode 100644 index 00000000..2bc60f1b --- /dev/null +++ b/test/integration/property-uuid.js @@ -0,0 +1,115 @@ +var _ = require('lodash'); +var should = require('should'); +var helper = require('../support/spec_helper'); +var common = require('../common'); +var ORM = require('../../'); + +if (common.protocol() !== "postgres") return; + +describe("Property", function() { + describe("type uuid", function () { + var db = null; + + before(function (done) { + helper.connect(function (connection) { + db = connection; + + done(); + }); + }); + + after(function () { + db.close(); + }); + + var Thing = null; + + before(function (done) { + db.driver.execQuery('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";', function (err) { + should.not.exist(err); + + Thing = db.define('thing', { + id: { type: 'uuid', key: true, defaultExpression: 'uuid_generate_v4()' }, + //id: { type: 'serial' }, + name: { type: 'text' } + }); + + helper.dropSync(Thing, done); + }); + }); + + it("should create the table", function () { + should(true); + }); + + var infoSQL = "SELECT * FROM information_schema.columns WHERE table_name = 'thing' AND column_name = 'id'"; + + it("should have the correct type", function (done) { + db.driver.execQuery(infoSQL, function (err, cols) { + should.not.exist(err); + + var uuidCol = cols[0]; + + should.exist(uuidCol); + should.equal(uuidCol.data_type, 'uuid'); + done(); + }); + }); + + it("should have the correct default value", function (done) { + db.driver.execQuery(infoSQL, function (err, cols) { + should.not.exist(err); + + var uuidCol = cols[0]; + + should.exist(uuidCol); + should.equal(uuidCol.column_default, 'uuid_generate_v4()'); + done(); + }); + }); + + it("should set id automatically", function (done) { + var chair = new Thing({ name: 'chair' }); + + chair.save(function (err) { + should.not.exist(err); + + Thing.find().all(function (err, items) { + should.not.exist(err); + should.equal(items.length, 1); + should.equal(items[0].name, 'chair'); + items[0].id.should.match(/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i); + + done(); + }); + }); + }); + + it("should save", function (done) { + var horse = new Thing({ name: 'horse' }); + + horse.save(function (err) { + should.not.exist(err); + + Thing.get(horse.id, function (err, item) { + should.not.exist(err); + + item.name = 'horsey'; + + item.save(function (err) { + should.not.exist(err); + + Thing.get(horse.id, function (err, item) { + should.not.exist(err); + should.equal(item.id, horse.id); + should.equal(item.name, 'horsey'); + + done(); + }); + }); + }); + }); + }); + + }); +});