diff --git a/lib/dialects/abstract/query-generator.js b/lib/dialects/abstract/query-generator.js index f251045dbafd..09a425006976 100644 --- a/lib/dialects/abstract/query-generator.js +++ b/lib/dialects/abstract/query-generator.js @@ -143,7 +143,9 @@ module.exports = (function() { /* Returns an insert into command. Parameters: table name + hash of attribute-value-pairs. */ - insertQuery: function(table, valueHash, modelAttributes) { + insertQuery: function(table, valueHash, modelAttributes, options) { + options = options || {}; + var query , valueQuery = 'INSERT INTO <%= table %> (<%= attributes %>) VALUES (<%= values %>)' , emptyQuery = 'INSERT INTO <%= table %>' @@ -168,7 +170,7 @@ module.exports = (function() { emptyQuery += ' VALUES ()'; } - if (this._dialect.supports['RETURNING']) { + if (this._dialect.supports['RETURNING'] && options.returning) { valueQuery += ' RETURNING *'; emptyQuery += ' RETURNING *'; } @@ -235,7 +237,7 @@ module.exports = (function() { query += ' LIMIT ' + this.escape(options.limit) + ' '; } - if (this._dialect.supports['RETURNING'] && (options.returning || options.returning === undefined)) { + if (this._dialect.supports['RETURNING'] && options.returning) { query += ' RETURNING *'; } diff --git a/lib/dialects/postgres/query-generator.js b/lib/dialects/postgres/query-generator.js index beaf758a22da..0173241679ce 100644 --- a/lib/dialects/postgres/query-generator.js +++ b/lib/dialects/postgres/query-generator.js @@ -253,11 +253,17 @@ module.exports = (function() { }, bulkInsertQuery: function(tableName, attrValueHashes, options, modelAttributes) { - var query = 'INSERT INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %> RETURNING *;' + options = options || {}; + + var query = 'INSERT INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %>' , tuples = [] , serials = [] , allAttributes = []; + if (this._dialect.supports['RETURNING'] && options.returning) { + query += ' RETURNING *'; + } + Utils._.forEach(attrValueHashes, function(attrValueHash) { Utils._.forOwn(attrValueHash, function(value, key) { if (allAttributes.indexOf(key) === -1) { @@ -289,6 +295,8 @@ module.exports = (function() { , tuples: tuples.join(',') }; + query = query + ';'; + return Utils._.template(query)(replacements); }, diff --git a/lib/dialects/postgres/query.js b/lib/dialects/postgres/query.js index 1ef58ea3dbd0..875ba46b7412 100644 --- a/lib/dialects/postgres/query.js +++ b/lib/dialects/postgres/query.js @@ -146,6 +146,10 @@ module.exports = (function() { } else if (self.send('isShowOrDescribeQuery')) { return results; } else if (QueryTypes.BULKUPDATE === self.options.type) { + if (!self.options.returning) { + return result.rowCount; + } + if (!!self.callee && !!self.callee._hasHstoreAttributes) { rows.forEach(function(row) { parseHstoreFields(self.callee, row); diff --git a/lib/model.js b/lib/model.js index 0914edd19cab..4b7bb11b1311 100644 --- a/lib/model.js +++ b/lib/model.js @@ -1341,6 +1341,7 @@ module.exports = (function() { * @param {Boolean} [options.validate=true] Should each row be subject to validation before it is inserted. The whole insert will fail if one row fails validation * @param {Boolean} [options.hooks=true] Run before / after bulk update hooks? * @param {Boolean} [options.individualHooks=false] Run before / after update hooks? + * @param {Boolean} [options.returning=false] Return the affected rows (only for postgres) * @param {Number} [options.limit] How many rows to update (only for mysql and mariadb) * @deprecated The syntax is due for change, in order to make `where` more consistent with the rest of the API * @@ -1353,6 +1354,7 @@ module.exports = (function() { validate: true, hooks: true, individualHooks: false, + returning: false, force: false }, options || {}); @@ -1458,6 +1460,10 @@ module.exports = (function() { // Run query to update all rows return self.QueryInterface.bulkUpdate(self.getTableName(), attrValueHashUse, where, options, self.tableAttributes).then(function(affectedRows) { + if (options.returning) { + return [affectedRows.length, affectedRows]; + } + return [affectedRows]; }); }).tap(function(result) { diff --git a/lib/query-interface.js b/lib/query-interface.js index 94dbda6382cf..bec527cc6fd5 100644 --- a/lib/query-interface.js +++ b/lib/query-interface.js @@ -414,7 +414,7 @@ module.exports = (function() { }; QueryInterface.prototype.insert = function(dao, tableName, values, options) { - var sql = this.QueryGenerator.insertQuery(tableName, values, dao.Model.rawAttributes); + var sql = this.QueryGenerator.insertQuery(tableName, values, dao.Model.rawAttributes, options); return this.sequelize.query(sql, dao, options).then(function(result) { result.isNewRecord = false; diff --git a/test/dao-factory.test.js b/test/dao-factory.test.js index 2119eb850976..5302bf03d7b5 100644 --- a/test/dao-factory.test.js +++ b/test/dao-factory.test.js @@ -257,8 +257,8 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { var titleSetter = sinon.spy() , Task = this.sequelize.define('TaskBuild', { title: { - type: Sequelize.STRING(50), - allowNull: false, + type: Sequelize.STRING(50), + allowNull: false, defaultValue: '' } }, { @@ -783,32 +783,30 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { }) }) - if (dialect === "postgres") { - it('returns the affected rows', function(_done) { - var self = this - , data = [{ username: 'Peter', secretValue: '42' }, - { username: 'Paul', secretValue: '42' }, - { username: 'Bob', secretValue: '43' }] - , done = _.after(2, _done) + it('returns the number of affected rows', function(_done) { + var self = this + , data = [{ username: 'Peter', secretValue: '42' }, + { username: 'Paul', secretValue: '42' }, + { username: 'Bob', secretValue: '43' }] + , done = _.after(2, _done) - this.User.bulkCreate(data).success(function() { - self.User.update({username: 'Bill'}, {secretValue: '42'}).spread(function(affectedRows) { - expect(affectedRows).to.have.length(2) + this.User.bulkCreate(data).success(function() { + self.User.update({username: 'Bill'}, {secretValue: '42'}).spread(function(affectedRows) { + expect(affectedRows).to.equal(2) - done() - }) + done() + }) - self.User.update({username: 'Bill'}, {secretValue: '44'}).spread(function(affectedRows) { - expect(affectedRows).to.have.length(0) + self.User.update({username: 'Bill'}, {secretValue: '44'}).spread(function(affectedRows) { + expect(affectedRows).to.equal(0) - done() - }) + done() }) }) - } + }) - if (dialect !== "postgres") { - it('returns the number of affected rows', function(_done) { + if (dialect === "postgres") { + it('returns the affected rows if `options.returning` is true', function(_done) { var self = this , data = [{ username: 'Peter', secretValue: '42' }, { username: 'Paul', secretValue: '42' }, @@ -816,14 +814,16 @@ describe(Support.getTestDialectTeaser("DAOFactory"), function () { , done = _.after(2, _done) this.User.bulkCreate(data).success(function() { - self.User.update({username: 'Bill'}, {secretValue: '42'}).spread(function(affectedRows) { - expect(affectedRows).to.equal(2) + self.User.update({ username: 'Bill' }, { secretValue: '42' }, { returning: true }).spread(function(count, rows) { + expect(count).to.equal(2) + expect(rows).to.have.length(2) done() }) - self.User.update({username: 'Bill'}, {secretValue: '44'}).spread(function(affectedRows) { - expect(affectedRows).to.equal(0) + self.User.update({ username: 'Bill'}, { secretValue: '44' }, { returning: true }).spread(function(count, rows) { + expect(count).to.equal(0) + expect(rows).to.have.length(0) done() }) diff --git a/test/postgres/dao.test.js b/test/postgres/dao.test.js index 102bf959ab95..198c7dfbe062 100644 --- a/test/postgres/dao.test.js +++ b/test/postgres/dao.test.js @@ -295,16 +295,16 @@ if (dialect.match(/^postgres/)) { .error(console.log) }) - it("should update hstore correctly and return affected rows", function(done) { + it("should update hstore correctly and return the affected rows", function(done) { var self = this this.User .create({ username: 'user', email: ['foo@bar.com'], settings: { created: { test: '"value"' }}}) .success(function(oldUser) { // Update the user and check that the returned object's fields have been parsed by the hstore library - self.User.update({settings: {should: 'update', to: 'this', first: 'place'}}, oldUser.identifiers).spread(function(newUsers) { - expect(newUsers).to.have.length(1); - expect(newUsers[0].settings).to.deep.equal({should: 'update', to: 'this', first: 'place'}) + self.User.update({settings: {should: 'update', to: 'this', first: 'place'}}, oldUser.identifiers, { returning: true }).spread(function(count, users) { + expect(count).to.equal(1); + expect(users[0].settings).to.deep.equal({should: 'update', to: 'this', first: 'place'}) done() }) }) diff --git a/test/postgres/query-generator.test.js b/test/postgres/query-generator.test.js index 99c82a1072c0..e1baddb181f8 100644 --- a/test/postgres/query-generator.test.js +++ b/test/postgres/query-generator.test.js @@ -454,108 +454,111 @@ if (dialect.match(/^postgres/)) { insertQuery: [ { arguments: ['myTable', {}], - expectation: "INSERT INTO \"myTable\" DEFAULT VALUES RETURNING *;" + expectation: "INSERT INTO \"myTable\" DEFAULT VALUES;" }, { arguments: ['myTable', {name: 'foo'}], - expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo');" + }, { + arguments: ['myTable', {name: 'foo'}, {}, { returning: true }], + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;", }, { arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}], - expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;');" }, { arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}], - expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.000 +00:00') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.000 +00:00');" }, { arguments: ['myTable', {data: new Buffer('Sequelize') }], - expectation: "INSERT INTO \"myTable\" (\"data\") VALUES (E'\\\\x53657175656c697a65') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"data\") VALUES (E'\\\\x53657175656c697a65');" }, { arguments: ['myTable', {name: 'foo', numbers: new Uint8Array([1,2,3])}], - expectation: "INSERT INTO \"myTable\" (\"name\",\"numbers\") VALUES ('foo',ARRAY[1,2,3]) RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"numbers\") VALUES ('foo',ARRAY[1,2,3]);" }, { arguments: ['myTable', {name: 'foo', foo: 1}], - expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1) RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1);" }, { arguments: ['myTable', {name: 'foo', nullValue: null}], - expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL) RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL);" }, { arguments: ['myTable', {name: 'foo', nullValue: null}], - expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL) RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL);", context: {options: {omitNull: false}} }, { arguments: ['myTable', {name: 'foo', nullValue: null}], - expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo');", context: {options: {omitNull: true}} }, { arguments: ['myTable', {name: 'foo', nullValue: undefined}], - expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo');", context: {options: {omitNull: true}} }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: 'foo'}], - expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo') RETURNING *;" + expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo');" }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: JSON.stringify({info: 'Look ma a " quote'})}], - expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}') RETURNING *;" + expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}');" }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: "foo';DROP TABLE mySchema.myTable;"}], - expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;') RETURNING *;" + expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;');" }, { arguments: ['myTable', function (sequelize) { return { foo: sequelize.fn('NOW') } }], - expectation: "INSERT INTO \"myTable\" (\"foo\") VALUES (NOW()) RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"foo\") VALUES (NOW());", needsSequelize: true }, // Variants when quoteIdentifiers is false { arguments: ['myTable', {name: 'foo'}], - expectation: "INSERT INTO myTable (name) VALUES ('foo') RETURNING *;", + expectation: "INSERT INTO myTable (name) VALUES ('foo');", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}], - expectation: "INSERT INTO myTable (name) VALUES ('foo'';DROP TABLE myTable;') RETURNING *;", + expectation: "INSERT INTO myTable (name) VALUES ('foo'';DROP TABLE myTable;');", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}], - expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00') RETURNING *;", + expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00');", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', numbers: new Uint8Array([1,2,3])}], - expectation: "INSERT INTO myTable (name,numbers) VALUES ('foo',ARRAY[1,2,3]) RETURNING *;", + expectation: "INSERT INTO myTable (name,numbers) VALUES ('foo',ARRAY[1,2,3]);", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', foo: 1}], - expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1) RETURNING *;", + expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1);", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', nullValue: null}], - expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL) RETURNING *;", + expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL);", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', nullValue: null}], - expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL) RETURNING *;", + expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL);", context: {options: {omitNull: false, quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', nullValue: null}], - expectation: "INSERT INTO myTable (name) VALUES ('foo') RETURNING *;", + expectation: "INSERT INTO myTable (name) VALUES ('foo');", context: {options: {omitNull: true, quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', nullValue: undefined}], - expectation: "INSERT INTO myTable (name) VALUES ('foo') RETURNING *;", + expectation: "INSERT INTO myTable (name) VALUES ('foo');", context: {options: {omitNull: true, quoteIdentifiers: false}} }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: 'foo'}], - expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo') RETURNING *;", + expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo');", context: {options: {quoteIdentifiers: false}} }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: JSON.stringify({info: 'Look ma a " quote'})}], - expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}') RETURNING *;", + expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}');", context: {options: {quoteIdentifiers: false}} }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: "foo';DROP TABLE mySchema.myTable;"}], - expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;') RETURNING *;", + expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;');", context: {options: {quoteIdentifiers: false}} } @@ -564,86 +567,89 @@ if (dialect.match(/^postgres/)) { bulkInsertQuery: [ { arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]], - expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar');" + }, { + arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}], { returning: true }], + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;", }, { arguments: ['myTable', [{name: "foo';DROP TABLE myTable;"}, {name: 'bar'}]], - expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;'),('bar') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;'),('bar');" }, { arguments: ['myTable', [{name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {name: 'bar', birthday: moment("2012-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}]], - expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.000 +00:00'),('bar','2012-03-27 10:01:55.000 +00:00') RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"birthday\") VALUES ('foo','2011-03-27 10:01:55.000 +00:00'),('bar','2012-03-27 10:01:55.000 +00:00');" }, { arguments: ['myTable', [{name: 'foo', foo: 1}, {name: 'bar', foo: 2}]], - expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1),('bar',2) RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"foo\") VALUES ('foo',1),('bar',2);" }, { arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]], - expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;" + expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL);" }, { arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]], - expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL);", context: {options: {omitNull: false}} }, { arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]], - expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL);", context: {options: {omitNull: true}} // Note: We don't honour this because it makes little sense when some rows may have nulls and others not }, { arguments: ['myTable', [{name: 'foo', nullValue: undefined}, {name: 'bar', nullValue: undefined}]], - expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO \"myTable\" (\"name\",\"nullValue\") VALUES ('foo',NULL),('bar',NULL);", context: {options: {omitNull: true}} // Note: As above }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: 'foo'}, {name: 'bar'}]], - expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;" + expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'),('bar');" }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]], - expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;" + expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}');" }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]], - expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;" + expectation: "INSERT INTO \"mySchema\".\"myTable\" (\"name\") VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar');" }, // Variants when quoteIdentifiers is false { arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]], - expectation: "INSERT INTO myTable (name) VALUES ('foo'),('bar') RETURNING *;", + expectation: "INSERT INTO myTable (name) VALUES ('foo'),('bar');", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', [{name: "foo';DROP TABLE myTable;"}, {name: 'bar'}]], - expectation: "INSERT INTO myTable (name) VALUES ('foo'';DROP TABLE myTable;'),('bar') RETURNING *;", + expectation: "INSERT INTO myTable (name) VALUES ('foo'';DROP TABLE myTable;'),('bar');", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', [{name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {name: 'bar', birthday: moment("2012-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}]], - expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00'),('bar','2012-03-27 10:01:55.000 +00:00') RETURNING *;", + expectation: "INSERT INTO myTable (name,birthday) VALUES ('foo','2011-03-27 10:01:55.000 +00:00'),('bar','2012-03-27 10:01:55.000 +00:00');", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', [{name: 'foo', foo: 1}, {name: 'bar', foo: 2}]], - expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1),('bar',2) RETURNING *;", + expectation: "INSERT INTO myTable (name,foo) VALUES ('foo',1),('bar',2);", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]], - expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL);", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]], - expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL);", context: {options: {quoteIdentifiers: false, omitNull: false}}, }, { arguments: ['myTable', [{name: 'foo', nullValue: null}, {name: 'bar', nullValue: null}]], - expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL);", context: {options: {omitNull: true, quoteIdentifiers: false}} // Note: We don't honour this because it makes little sense when some rows may have nulls and others not }, { arguments: ['myTable', [{name: 'foo', nullValue: undefined}, {name: 'bar', nullValue: undefined}]], - expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL) RETURNING *;", + expectation: "INSERT INTO myTable (name,nullValue) VALUES ('foo',NULL),('bar',NULL);", context: {options: {omitNull: true, quoteIdentifiers: false}} // Note: As above }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: 'foo'}, {name: 'bar'}]], - expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'),('bar') RETURNING *;", + expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'),('bar');", context: {options: {quoteIdentifiers: false}} }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: JSON.stringify({info: 'Look ma a " quote'})}, {name: JSON.stringify({info: 'Look ma another " quote'})}]], - expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}') RETURNING *;", + expectation: "INSERT INTO mySchema.myTable (name) VALUES ('{\"info\":\"Look ma a \\\" quote\"}'),('{\"info\":\"Look ma another \\\" quote\"}');", context: {options: {quoteIdentifiers: false}} }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, [{name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'bar'}]], - expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar') RETURNING *;", + expectation: "INSERT INTO mySchema.myTable (name) VALUES ('foo'';DROP TABLE mySchema.myTable;'),('bar');", context: {options: {quoteIdentifiers: false}} } ], @@ -651,47 +657,50 @@ if (dialect.match(/^postgres/)) { updateQuery: [ { arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}], - expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2 RETURNING *" + expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2" }, { arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, 2], - expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2 RETURNING *" + expectation: "UPDATE \"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2" }, { arguments: ['myTable', {bar: 2}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *" + expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo'" + }, { + arguments: ['myTable', {bar: 2}, {name: 'foo'}, { returning: true }], + expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *", }, { arguments: ['myTable', {numbers: new Uint8Array([1,2,3])}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"numbers\"=ARRAY[1,2,3] WHERE \"name\"='foo' RETURNING *" + expectation: "UPDATE \"myTable\" SET \"numbers\"=ARRAY[1,2,3] WHERE \"name\"='foo'" }, { arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"name\"='foo'';DROP TABLE myTable;' WHERE \"name\"='foo' RETURNING *" + expectation: "UPDATE \"myTable\" SET \"name\"='foo'';DROP TABLE myTable;' WHERE \"name\"='foo'" }, { arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=2,\"nullValue\"=NULL WHERE \"name\"='foo' RETURNING *" + expectation: "UPDATE \"myTable\" SET \"bar\"=2,\"nullValue\"=NULL WHERE \"name\"='foo'" }, { arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=2,\"nullValue\"=NULL WHERE \"name\"='foo' RETURNING *", + expectation: "UPDATE \"myTable\" SET \"bar\"=2,\"nullValue\"=NULL WHERE \"name\"='foo'", context: {options: {omitNull: false}} }, { arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *", + expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo'", context: {options: {omitNull: true}} }, { arguments: ['myTable', {bar: 2, nullValue: undefined}, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo' RETURNING *", + expectation: "UPDATE \"myTable\" SET \"bar\"=2 WHERE \"name\"='foo'", context: {options: {omitNull: true}} }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}], - expectation: "UPDATE \"mySchema\".\"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2 RETURNING *" + expectation: "UPDATE \"mySchema\".\"myTable\" SET \"name\"='foo',\"birthday\"='2011-03-27 10:01:55.000 +00:00' WHERE \"id\"=2" }, { arguments: [{tableName: 'myTable', schema: 'mySchema'}, {name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'foo'}], - expectation: "UPDATE \"mySchema\".\"myTable\" SET \"name\"='foo'';DROP TABLE mySchema.myTable;' WHERE \"name\"='foo' RETURNING *" + expectation: "UPDATE \"mySchema\".\"myTable\" SET \"name\"='foo'';DROP TABLE mySchema.myTable;' WHERE \"name\"='foo'" }, { arguments: ['myTable', function (sequelize) { return { bar: sequelize.fn('NOW') } }, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=NOW() WHERE \"name\"='foo' RETURNING *", + expectation: "UPDATE \"myTable\" SET \"bar\"=NOW() WHERE \"name\"='foo'", needsSequelize: true }, { arguments: ['myTable', function (sequelize) { @@ -699,54 +708,54 @@ if (dialect.match(/^postgres/)) { bar: sequelize.col('foo') } }, {name: 'foo'}], - expectation: "UPDATE \"myTable\" SET \"bar\"=\"foo\" WHERE \"name\"='foo' RETURNING *", + expectation: "UPDATE \"myTable\" SET \"bar\"=\"foo\" WHERE \"name\"='foo'", needsSequelize: true }, // Variants when quoteIdentifiers is false { arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}], - expectation: "UPDATE myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *", + expectation: "UPDATE myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, 2], - expectation: "UPDATE myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *", + expectation: "UPDATE myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {bar: 2}, {name: 'foo'}], - expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET bar=2 WHERE name='foo'", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {numbers: new Uint8Array([1,2,3])}, {name: 'foo'}], - expectation: "UPDATE myTable SET numbers=ARRAY[1,2,3] WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET numbers=ARRAY[1,2,3] WHERE name='foo'", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}, {name: 'foo'}], - expectation: "UPDATE myTable SET name='foo'';DROP TABLE myTable;' WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET name='foo'';DROP TABLE myTable;' WHERE name='foo'", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}], - expectation: "UPDATE myTable SET bar=2,nullValue=NULL WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET bar=2,nullValue=NULL WHERE name='foo'", context: {options: {quoteIdentifiers: false}} }, { arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}], - expectation: "UPDATE myTable SET bar=2,nullValue=NULL WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET bar=2,nullValue=NULL WHERE name='foo'", context: {options: {omitNull: false, quoteIdentifiers: false}}, }, { arguments: ['myTable', {bar: 2, nullValue: null}, {name: 'foo'}], - expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET bar=2 WHERE name='foo'", context: {options: {omitNull: true, quoteIdentifiers: false}}, }, { arguments: ['myTable', {bar: 2, nullValue: undefined}, {name: 'foo'}], - expectation: "UPDATE myTable SET bar=2 WHERE name='foo' RETURNING *", + expectation: "UPDATE myTable SET bar=2 WHERE name='foo'", context: {options: {omitNull: true, quoteIdentifiers: false}}, }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, {name: 'foo', birthday: moment("2011-03-27 10:01:55 +0000", "YYYY-MM-DD HH:mm:ss Z").toDate()}, {id: 2}], - expectation: "UPDATE mySchema.myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2 RETURNING *", + expectation: "UPDATE mySchema.myTable SET name='foo',birthday='2011-03-27 10:01:55.000 +00:00' WHERE id=2", context: {options: {quoteIdentifiers: false}} }, { arguments: [{schema: 'mySchema', tableName: 'myTable'}, {name: "foo';DROP TABLE mySchema.myTable;"}, {name: 'foo'}], - expectation: "UPDATE mySchema.myTable SET name='foo'';DROP TABLE mySchema.myTable;' WHERE name='foo' RETURNING *", + expectation: "UPDATE mySchema.myTable SET name='foo'';DROP TABLE mySchema.myTable;' WHERE name='foo'", context: {options: {quoteIdentifiers: false}} } ],