From 3830984944b84af4bfe443d0952f7688d4d75516 Mon Sep 17 00:00:00 2001 From: tchak Date: Mon, 1 Jun 2015 11:24:04 +0300 Subject: [PATCH] Create snapshots on save not on flush alows us to have access to changed attributes in snapshot --- packages/ember-data/lib/system/model/model.js | 10 +++++-- packages/ember-data/lib/system/snapshot.js | 29 ++++++++++++++++++- packages/ember-data/lib/system/store.js | 18 +++++++----- .../tests/integration/snapshot-test.js | 14 +++++++++ 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/packages/ember-data/lib/system/model/model.js b/packages/ember-data/lib/system/model/model.js index 85f9caf5f7e..e435865e9af 100644 --- a/packages/ember-data/lib/system/model/model.js +++ b/packages/ember-data/lib/system/model/model.js @@ -889,7 +889,7 @@ var Model = Ember.Object.extend(Ember.Evented, { changedAttributes: function() { var oldData = get(this, '_data'); var newData = get(this, '_attributes'); - var diffData = {}; + var diffData = Ember.create(null); var prop; for (prop in newData) { @@ -899,11 +899,17 @@ var Model = Ember.Object.extend(Ember.Evented, { return diffData; }, + flushChangedAttributes: function() { + this._inFlightAttributes = this._attributes; + this._attributes = Ember.create(null); + }, + /** @method adapterWillCommit @private */ adapterWillCommit: function() { + this.flushChangedAttributes(); this.send('willCommit'); }, @@ -1052,8 +1058,6 @@ var Model = Ember.Object.extend(Ember.Evented, { var resolver = Ember.RSVP.defer(promiseLabel); this.store.scheduleSave(this, resolver); - this._inFlightAttributes = this._attributes; - this._attributes = Ember.create(null); return PromiseObject.create({ promise: resolver.promise diff --git a/packages/ember-data/lib/system/snapshot.js b/packages/ember-data/lib/system/snapshot.js index d14fc0d4a0c..2129e47f1ab 100644 --- a/packages/ember-data/lib/system/snapshot.js +++ b/packages/ember-data/lib/system/snapshot.js @@ -27,6 +27,8 @@ function Snapshot(record) { this.type = record.constructor; this.modelName = record.constructor.modelName; + this._changedAttributes = record.changedAttributes(); + // The following code is here to keep backwards compatibility when accessing // `constructor` directly. // @@ -135,7 +137,7 @@ Snapshot.prototype = { Example ```javascript - // store.push('post', { id: 1, author: 'Tomster', title: 'Hello World' }); + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); postSnapshot.attributes(); // => { author: 'Tomster', title: 'Ember.js rocks' } ``` @@ -146,6 +148,31 @@ Snapshot.prototype = { return Ember.copy(this._attributes); }, + /** + Returns all changed attributes and their old and new values. + + Example + + ```javascript + // store.push('post', { id: 1, author: 'Tomster', title: 'Ember.js rocks' }); + postModel.set('title', 'Ember.js rocks!'); + postSnapshot.changedAttributes(); // => { title: ['Ember.js rocks', 'Ember.js rocks!'] } + ``` + + @method changedAttributes + @return {Object} All changed attributes of the current snapshot + */ + changedAttributes: function() { + var prop; + var changedAttributes = Ember.create(null); + + for (prop in this._changedAttributes) { + changedAttributes[prop] = Ember.copy(this._changedAttributes[prop]); + } + + return changedAttributes; + }, + /** Returns the current value of a belongsTo relationship. diff --git a/packages/ember-data/lib/system/store.js b/packages/ember-data/lib/system/store.js index 3a21b1d43f3..350d2fa36cb 100644 --- a/packages/ember-data/lib/system/store.js +++ b/packages/ember-data/lib/system/store.js @@ -1254,8 +1254,9 @@ Store = Service.extend({ @param {Resolver} resolver */ scheduleSave: function(record, resolver) { + var snapshot = record._createSnapshot(); record.adapterWillCommit(); - this._pendingSave.push([record, resolver]); + this._pendingSave.push([snapshot, resolver]); once(this, 'flushPendingSave'); }, @@ -1271,8 +1272,9 @@ Store = Service.extend({ this._pendingSave = []; forEach(pending, function(tuple) { - var record = tuple[0]; + var snapshot = tuple[0]; var resolver = tuple[1]; + var record = snapshot.record; var adapter = this.adapterFor(record.constructor); var operation; @@ -1286,7 +1288,7 @@ Store = Service.extend({ operation = 'updateRecord'; } - resolver.resolve(_commit(adapter, this, operation, record)); + resolver.resolve(_commit(adapter, this, operation, snapshot)); }, this); }, @@ -2022,9 +2024,9 @@ function defaultSerializer(container) { container.lookup('serializer:-default'); } -function _commit(adapter, store, operation, record) { - var type = record.constructor; - var snapshot = record._createSnapshot(); +function _commit(adapter, store, operation, snapshot) { + var record = snapshot.record; + var type = snapshot.type; var promise = adapter[operation](store, type, snapshot); var serializer = serializerForAdapter(store, adapter, type); var label = "DS: Extract and notify about " + operation + " completion of " + record; @@ -2040,7 +2042,7 @@ function _commit(adapter, store, operation, record) { store._adapterRun(function() { if (adapterPayload) { - payload = serializer.extract(store, type, adapterPayload, get(record, 'id'), operation); + payload = serializer.extract(store, type, adapterPayload, get(snapshot, 'id'), operation); } store.didSaveRecord(record, payload); }); @@ -2048,7 +2050,7 @@ function _commit(adapter, store, operation, record) { return record; }, function(reason) { if (reason instanceof InvalidError) { - var errors = serializer.extractErrors(store, type, reason.errors, get(record, 'id')); + var errors = serializer.extractErrors(store, type, reason.errors, get(snapshot, 'id')); store.recordWasInvalid(record, errors); reason = new InvalidError(errors); } else { diff --git a/packages/ember-data/tests/integration/snapshot-test.js b/packages/ember-data/tests/integration/snapshot-test.js index 0c71dffd273..8b85621cab2 100644 --- a/packages/ember-data/tests/integration/snapshot-test.js +++ b/packages/ember-data/tests/integration/snapshot-test.js @@ -112,6 +112,20 @@ test("snapshot.attributes() returns a copy of all attributes for the current sna }); }); +test("snapshot.changedAttributes() returns a copy of all changed attributes for the current snapshot", function() { + expect(1); + + run(function() { + var post = env.store.push('post', { id: 1, title: 'Hello World' }); + post.set('title', 'Hello World!'); + var snapshot = post._createSnapshot(); + + var changes = snapshot.changedAttributes(); + + deepEqual(changes, { title: ['Hello World', 'Hello World!'] }, 'changed attributes are returned correctly'); + }); +}); + test("snapshot.belongsTo() returns undefined if relationship is undefined", function() { expect(1);