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

Commit 82b6c505 by Louis-Rémi Babé Committed by Jan Aagaard Meier

Fix upsert behavior to update all _changed_ fields by default (#7523)

* Fix upsert behavior to update all _changed_ fields by default

* Update changelog
1 parent aa7360aa
...@@ -68,6 +68,7 @@ ...@@ -68,6 +68,7 @@
- [REMOVED] Removes support for `{raw: 'injection goes here'}` for order and group. [#7188](https://github.com/sequelize/sequelize/issues/7188) - [REMOVED] Removes support for `{raw: 'injection goes here'}` for order and group. [#7188](https://github.com/sequelize/sequelize/issues/7188)
- [FIXED] `showIndex` breaks with newline characters [#7492](https://github.com/sequelize/sequelize/pull/7492) - [FIXED] `showIndex` breaks with newline characters [#7492](https://github.com/sequelize/sequelize/pull/7492)
- [FIXED] Update or soft delete breaks when querying on `JSON/JSONB` [#7376](https://github.com/sequelize/sequelize/issues/7376) [#7400](https://github.com/sequelize/sequelize/issues/7400) [#7444](https://github.com/sequelize/sequelize/issues/7444) - [FIXED] Update or soft delete breaks when querying on `JSON/JSONB` [#7376](https://github.com/sequelize/sequelize/issues/7376) [#7400](https://github.com/sequelize/sequelize/issues/7400) [#7444](https://github.com/sequelize/sequelize/issues/7444)
- [FIXED] Upsert now updates all changed fields by default
## BC breaks: ## BC breaks:
- Model.validate instance method now runs validation hooks by default. Previously you needed to pass { hooks: true }. You can override this behavior by passing { hooks: false } - Model.validate instance method now runs validation hooks by default. Previously you needed to pass { hooks: true }. You can override this behavior by passing { hooks: false }
......
...@@ -2170,7 +2170,7 @@ class Model { ...@@ -2170,7 +2170,7 @@ class Model {
* @param {Object} values * @param {Object} values
* @param {Object} [options] * @param {Object} [options]
* @param {Boolean} [options.validate=true] Run validations before the row is inserted * @param {Boolean} [options.validate=true] Run validations before the row is inserted
* @param {Array} [options.fields=Object.keys(this.attributes)] The fields to insert / update. Defaults to all fields * @param {Array} [options.fields=Object.keys(this.attributes)] The fields to insert / update. Defaults to all changed fields
* @param {Boolean} [options.hooks=true] Run before / after upsert hooks? * @param {Boolean} [options.hooks=true] Run before / after upsert hooks?
* @param {Transaction} [options.transaction] Transaction to run query under * @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. * @param {Function} [options.logging=false] A function that gets executed while running the query to log the sql.
...@@ -2184,15 +2184,15 @@ class Model { ...@@ -2184,15 +2184,15 @@ class Model {
hooks: true hooks: true
}, Utils.cloneDeep(options || {})); }, Utils.cloneDeep(options || {}));
if (!options.fields) {
options.fields = Object.keys(values);
}
const createdAtAttr = this._timestampAttributes.createdAt; const createdAtAttr = this._timestampAttributes.createdAt;
const updatedAtAttr = this._timestampAttributes.updatedAt; const updatedAtAttr = this._timestampAttributes.updatedAt;
const hadPrimary = this.primaryKeyField in values || this.primaryKeyAttribute in values; const hadPrimary = this.primaryKeyField in values || this.primaryKeyAttribute in values;
const instance = this.build(values); const instance = this.build(values);
if (!options.fields) {
options.fields = Object.keys(instance._changed);
}
return instance.validate(options).then(() => { return instance.validate(options).then(() => {
// Map field names // Map field names
const updatedDataValues = _.pick(instance.dataValues, Object.keys(instance._changed)); const updatedDataValues = _.pick(instance.dataValues, Object.keys(instance._changed));
......
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
"mysql2": "^1.2.0", "mysql2": "^1.2.0",
"pg": "^6.1.0", "pg": "^6.1.0",
"pg-hstore": "^2.3.2", "pg-hstore": "^2.3.2",
"pg-native": "^1.8.0", "pg-native": "^1.10.0",
"pg-types": "^1.11.0", "pg-types": "^1.11.0",
"rimraf": "^2.5.4", "rimraf": "^2.5.4",
"sinon": "^1.17.6", "sinon": "^1.17.6",
......
...@@ -12,8 +12,19 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -12,8 +12,19 @@ describe(Support.getTestDialectTeaser('Model'), () => {
if (current.dialect.supports.upserts) { if (current.dialect.supports.upserts) {
describe('method upsert', () => { describe('method upsert', () => {
const self = this;
const User = current.define('User', { const User = current.define('User', {
name: DataTypes.STRING, name: DataTypes.STRING,
virtualValue: {
type: DataTypes.VIRTUAL,
set(val) {
return this.value = val;
},
get() {
return this.value;
}
},
value: DataTypes.STRING,
secretValue: { secretValue: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false allowNull: false
...@@ -23,17 +34,40 @@ describe(Support.getTestDialectTeaser('Model'), () => { ...@@ -23,17 +34,40 @@ describe(Support.getTestDialectTeaser('Model'), () => {
before(function() { before(function() {
this.query = current.query; this.query = current.query;
current.query = sinon.stub().returns(Promise.resolve()); current.query = sinon.stub().returns(Promise.resolve());
self.stub = sinon.stub(current.getQueryInterface(), 'upsert', () => {
return User.build({});
});
});
beforeEach(() => {
self.stub.reset();
}); });
after(function() { after(function() {
current.query = this.query; current.query = this.query;
self.stub.restore();
}); });
it('skip validations for missing fields', () => { it('skip validations for missing fields', () => {
return expect(User.upsert({ return expect(User.upsert({
name: 'Grumpy Cat' name: 'Grumpy Cat'
})).not.to.be.rejectedWith(current.ValidationError); })).not.to.be.rejectedWith(current.ValidationError);
}); });
it('updates all changed fields by default', () => {
return User
.upsert({
name: 'Old Cat',
virtualValue: 111
})
.then(() => {
expect(Object.keys(self.stub.getCall(0).args[2])).to.deep.equal([
'name', 'value', 'updatedAt'
]);
});
});
}); });
} }
}); });
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!