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

Commit 4305a37e by Mick Hansen

feature(instance): set now supports nested keys for JSON/JSONB attributes

1 parent b7725c7a
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
- [BUG] Error messages thrown by the db in languages other than english do not crash the app anymore (mysql, mariadb and postgres only) [#3567](https://github.com/sequelize/sequelize/pull/3567) - [BUG] Error messages thrown by the db in languages other than english do not crash the app anymore (mysql, mariadb and postgres only) [#3567](https://github.com/sequelize/sequelize/pull/3567)
- [FEATURE] All querys can be logged individually by inserting `logging: fn` in the query option. - [FEATURE] All querys can be logged individually by inserting `logging: fn` in the query option.
- [FEATURE] Partial index support for Postgres with `index.where` - [FEATURE] Partial index support for Postgres with `index.where`
- [REFACTOR] `.changed()` now works proactively by setting a flag on `set` instead of matching reactively. Not that objects and arrays will not be checked for equality on set and will always result in a change if they are `set`.
- [DEPRECATED] The query-chainer is deprecated and will be removed in version 2.2. Please use promises instead. - [DEPRECATED] The query-chainer is deprecated and will be removed in version 2.2. Please use promises instead.
- [REMOVED] Events are no longer supported. - [REMOVED] Events are no longer supported.
......
...@@ -5,6 +5,7 @@ var Utils = require('./utils') ...@@ -5,6 +5,7 @@ var Utils = require('./utils')
, BelongsToMany = require('./associations/belongs-to-many') , BelongsToMany = require('./associations/belongs-to-many')
, InstanceValidator = require('./instance-validator') , InstanceValidator = require('./instance-validator')
, QueryTypes = require('./query-types') , QueryTypes = require('./query-types')
, Dottie = require('dottie')
, Promise = require('./promise') , Promise = require('./promise')
, _ = require('lodash') , _ = require('lodash')
, primitives = ["string", "number", "boolean"] , primitives = ["string", "number", "boolean"]
...@@ -246,10 +247,13 @@ module.exports = (function() { ...@@ -246,10 +247,13 @@ module.exports = (function() {
* If set is called with an object, it will loop over the object, and call set recursively for each key, value pair. If you set raw to true, the underlying dataValues will either be * If set is called with an object, it will loop over the object, and call set recursively for each key, value pair. If you set raw to true, the underlying dataValues will either be
* set directly to the object passed, or used to extend dataValues, if dataValues already contain values. * set directly to the object passed, or used to extend dataValues, if dataValues already contain values.
* *
* When set is called, the previous value of the field is stored, so that you can later see which fields changed (see `changed`). * When set is called, the previous value of the field is stored and sets a changed flag(see `changed`).
* *
* Set can also be used to build instances for associations, if you have values for those. * Set can also be used to build instances for associations, if you have values for those.
* TODO(mick): should probably write something here about how includes in set works - perhaps also even some tests? * When using set with associations you need to make sure the property key matches the alias of the association
* while also making sure that the proper include options have been set (from .build() or .find())
*
* If called with a dot.seperated key on a JSON/JSONB attribute it will set the value nested and flag the entire object as changed.
* *
* @see {Model#find} for more information about includes * @see {Model#find} for more information about includes
* @param {String|Object} key * @param {String|Object} key
...@@ -257,7 +261,6 @@ module.exports = (function() { ...@@ -257,7 +261,6 @@ module.exports = (function() {
* @param {Object} [options] * @param {Object} [options]
* @param {Boolean} [options.raw=false] If set to true, field and virtual setters will be ignored * @param {Boolean} [options.raw=false] If set to true, field and virtual setters will be ignored
* @param {Boolean} [options.reset=false] Clear all previously set data values * @param {Boolean} [options.reset=false] Clear all previously set data values
* @param {Object} [options.include]
* @alias setAttributes * @alias setAttributes
*/ */
Instance.prototype.set = function(key, value, options) { Instance.prototype.set = function(key, value, options) {
...@@ -335,6 +338,10 @@ module.exports = (function() { ...@@ -335,6 +338,10 @@ module.exports = (function() {
if (!options.raw) { if (!options.raw) {
// If attribute is not in model definition, return // If attribute is not in model definition, return
if (!this._isAttribute(key)) { if (!this._isAttribute(key)) {
if (key.indexOf('.') > -1 && this.Model._isJsonAttribute(key.split('.')[0])) {
Dottie.set(this.dataValues, key, value);
this.changed(key, true);
}
return; return;
} }
......
...@@ -8,7 +8,7 @@ var chai = require('chai') ...@@ -8,7 +8,7 @@ var chai = require('chai')
, current = Support.sequelize; , current = Support.sequelize;
describe(Support.getTestDialectTeaser('Instance'), function() { describe(Support.getTestDialectTeaser('Instance'), function() {
describe.only('changed', function () { describe('changed', function () {
beforeEach(function () { beforeEach(function () {
this.User = this.sequelize.define('User', { this.User = this.sequelize.define('User', {
name: DataTypes.STRING, name: DataTypes.STRING,
......
'use strict';
/* jshint -W030 */
var chai = require('chai')
, expect = chai.expect
, Support = require(__dirname + '/../support')
, DataTypes = require(__dirname + '/../../../lib/data-types')
, current = Support.sequelize;
describe(Support.getTestDialectTeaser('Instance'), function() {
describe('set', function () {
it.only('sets nested keys in JSON objects', function () {
var User = this.sequelize.define('User', {
meta: DataTypes.JSONB
});
var user = User.build({
meta: {
location: 'Stockhollm'
}
}, {
isNewRecord: false,
raw: true
});
var meta = user.get('meta');
user.set('meta.location', 'Copenhagen');
expect(user.dataValues['meta.location']).not.to.be.ok;
expect(user.get('meta').location).to.equal('Copenhagen');
expect(user.get('meta') === meta).to.equal(true);
});
});
});
\ No newline at end of file
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!