不要怂,就是干,撸起袖子干!

Commit 4e439fa5 by Justin Hinerman Committed by Sushant

feat(postgres): support ignoreDuplicates for postges >= 9.5 (#9954)

1 parent e26f62f2
......@@ -41,6 +41,8 @@ AbstractDialect.prototype.supports = {
},
migrations: true,
upserts: true,
/* dialect specific words for ON CONFLICT DO NOTHING */
onConflictDoNothing: '',
constraints: {
restrict: true,
addConstraint: true,
......
......@@ -82,8 +82,8 @@ const QueryGenerator = {
const fields = [];
const values = [];
let query;
let valueQuery = '<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>)<%= output %> VALUES (<%= values %>)';
let emptyQuery = '<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %><%= output %>';
let valueQuery = '<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>)<%= output %> VALUES (<%= values %>)<%= onConflictDoNothing %>';
let emptyQuery = '<%= tmpTable %>INSERT<%= ignoreDuplicates %> INTO <%= table %><%= output %><%= onConflictDoNothing %>';
let outputFragment;
let identityWrapperRequired = false;
let tmpTable = ''; //tmpTable declaration for trigger
......@@ -193,6 +193,7 @@ const QueryGenerator = {
const replacements = {
ignoreDuplicates: options.ignoreDuplicates ? this._dialect.supports.IGNORE : '',
onConflictDoNothing: options.ignoreDuplicates ? this._dialect.supports.onConflictDoNothing : '',
table: this.quoteTable(table),
attributes: fields.join(','),
output: outputFragment,
......@@ -221,7 +222,7 @@ const QueryGenerator = {
options = options || {};
fieldMappedAttributes = fieldMappedAttributes || {};
const query = 'INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %><%= onDuplicateKeyUpdate %><%= returning %>;';
const query = 'INSERT<%= ignoreDuplicates %> INTO <%= table %> (<%= attributes %>) VALUES <%= tuples %><%= onDuplicateKeyUpdate %><%= onConflictDoNothing %><%= returning %>;';
const tuples = [];
const serials = {};
const allAttributes = [];
......@@ -269,7 +270,8 @@ const QueryGenerator = {
attributes: allAttributes.map(attr => this.quoteIdentifier(attr)).join(','),
tuples: tuples.join(','),
onDuplicateKeyUpdate,
returning: this._dialect.supports.returnValues && options.returning ? ' RETURNING *' : ''
returning: this._dialect.supports.returnValues && options.returning ? ' RETURNING *' : '',
onConflictDoNothing: options.ignoreDuplicates ? this._dialect.supports.onConflictDoNothing : ''
};
return _.template(query, this._templateSettings)(replacements);
......
......@@ -40,6 +40,7 @@ PostgresDialect.prototype.supports = _.merge(_.cloneDeep(AbstractDialect.prototy
using: 2,
where: true
},
onConflictDoNothing: ' ON CONFLICT DO NOTHING',
NUMERIC: true,
ARRAY: true,
RANGE: true,
......
......@@ -2313,7 +2313,7 @@ class Model {
* @param {Boolean} [options.validate=false] 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 create hooks?
* @param {Boolean} [options.individualHooks=false] Run before / after create hooks for each individual Instance? BulkCreate hooks will still be run if options.hooks is true.
* @param {Boolean} [options.ignoreDuplicates=false] Ignore duplicate values for primary keys? (not supported by postgres)
* @param {Boolean} [options.ignoreDuplicates=false] Ignore duplicate values for primary keys? (not supported by postgres < 9.5)
* @param {Array} [options.updateOnDuplicate] Fields to update if row key already exists (on duplicate key update)? (only supported by mysql). By default, all fields are updated.
* @param {Transaction} [options.transaction] Transaction to run query under
* @param {Function} [options.logging=false] A function that gets executed while running the query to log the sql.
......@@ -2338,7 +2338,8 @@ class Model {
options.fields = options.fields || Object.keys(this.tableAttributes);
const dialect = this.sequelize.options.dialect;
if (options.ignoreDuplicates && ['postgres', 'mssql'].indexOf(dialect) !== -1) {
if (options.ignoreDuplicates && dialect === 'mssql') {
return Promise.reject(new Error(dialect + ' does not support the \'ignoreDuplicates\' option.'));
}
if (options.updateOnDuplicate && dialect !== 'mysql') {
......
......@@ -394,7 +394,8 @@ describe(Support.getTestDialectTeaser('Model'), () => {
});
});
if (current.dialect.supports.ignoreDuplicates) {
if (current.dialect.supports.ignoreDuplicates ||
current.dialect.supports.onConflictDoNothing) {
it('should support the ignoreDuplicates option', function() {
const self = this;
const data = [
......@@ -580,7 +581,7 @@ describe(Support.getTestDialectTeaser('Model'), () => {
return Maya.bulkCreate([M2]);
}).spread(m => {
// only attributes are returned, no fields are mixed
// only attributes are returned, no fields are mixed
expect(m.createdAt).to.be.ok;
expect(m.created_at).to.not.exist;
expect(m.secret_given).to.not.exist;
......
......@@ -558,9 +558,15 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', {name: 'foo'}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo');"
}, {
arguments: ['myTable', {name: 'foo'}, {}, { ignoreDuplicates: true }],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') ON CONFLICT DO NOTHING;"
}, {
arguments: ['myTable', {name: 'foo'}, {}, { returning: true }],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') RETURNING *;"
}, {
arguments: ['myTable', {name: 'foo'}, {}, { ignoreDuplicates: true, returning: true }],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo') ON CONFLICT DO NOTHING RETURNING *;"
}, {
arguments: ['myTable', {name: "foo';DROP TABLE myTable;"}],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;');"
}, {
......@@ -666,9 +672,15 @@ if (dialect.match(/^postgres/)) {
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}]],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar');"
}, {
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}], { ignoreDuplicates: true }],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar') ON CONFLICT DO NOTHING;"
}, {
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}], { returning: true }],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar') RETURNING *;"
}, {
arguments: ['myTable', [{name: 'foo'}, {name: 'bar'}], { ignoreDuplicates: true, returning: true }],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'),('bar') ON CONFLICT DO NOTHING RETURNING *;"
}, {
arguments: ['myTable', [{name: "foo';DROP TABLE myTable;"}, {name: 'bar'}]],
expectation: "INSERT INTO \"myTable\" (\"name\") VALUES ('foo'';DROP TABLE myTable;'),('bar');"
}, {
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!