-
Notifications
You must be signed in to change notification settings - Fork 138
Switch to passing only the current-change in 'changes' emit #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
10000
|
@@ -743,6 +743,8 @@ const creatingPath = 'creating' | |
const eventIdPath = 'eventId' | ||
// boolean - Whether to skip validation for a Record's currently changing property | ||
const noValidatePath = 'noValidate' | ||
// boolean - Whether to preserve Change History for a Record | ||
const keepChangeHistoryPath = 'keepChangeHistory' | ||
// boolean - Whether to skip change notification for a Record's currently | ||
// changing property | ||
const silentPath = 'silent' | ||
|
@@ -787,7 +789,6 @@ const makeDescriptor = function (prop, schema, opts) { | |
const _get = this[getter] | ||
const _set = this[setter] | ||
const _unset = this[unsetter] | ||
|
||
// Optionally check that the new value passes validation | ||
if (!_get(noValidatePath)) { | ||
const errors = schema.validate(value, { path: [prop] }) | ||
|
@@ -802,6 +803,8 @@ const makeDescriptor = function (prop, schema, opts) { | |
// TODO: Make it so tracking can be turned on for all properties instead of | ||
// only per-property | ||
if (track && !_get(creatingPath)) { | ||
// previous is versioned on database commit | ||
// props are versioned on set() | ||
const previous = _get(previousPath) | ||
const current = _get(keyPath) | ||
let changing = _get(changingPath) | ||
|
@@ -853,12 +856,16 @@ const makeDescriptor = function (prop, schema, opts) { | |
for (i = 0; i < changed.length; i++) { | ||
this.emit('change:' + changed[i], this, utils.get(this, changed[i])) | ||
} | ||
const changes = this.changes() | ||
const changeRecord = utils.plainCopy(changes) | ||
changeRecord.timestamp = new Date().getTime() | ||
const changeHistory = _get(changeHistoryPath) || [] | ||
_set(changeHistoryPath, changeHistory) | ||
changeHistory.push(changeRecord) | ||
|
||
const changes = utils.diffObjects({ [prop] : value }, { [prop] : current }) | ||
|
||
if (_get(keepChangeHistoryPath)) { | ||
const changeRecord = utils.plainCopy(changes) | ||
changeRecord.timestamp = new Date().getTime() | ||
let changeHistory = _get(changeHistoryPath) | ||
!changeHistory && _set(changeHistoryPath, (changeHistory = [])) | ||
changeHistory.push(changeRecord) | ||
} | ||
this.emit('change', this, changes) | ||
} | ||
_unset(silentPath) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { assert, JSData, sinon } from '../../_setup' | ||
const { Record } = JSData | ||
|
||
describe("Record#on('change')", function() { | ||
it('Tracking changes to a single property', function(done) { | ||
const Store = new JSData.DataStore() | ||
const Foo = Store.defineMapper('foo', { | ||
schema: { | ||
properties: { | ||
id: { type: 'number' }, | ||
name: { type: 'string', track: true } | ||
} | ||
}, | ||
}) | ||
const foo = Foo.createRecord() | ||
const listener = sinon.stub() | ||
foo.on('change', listener) | ||
foo.name = 'new foo' | ||
const secondSpec = function() { | ||
foo.name = 'updated foo' | ||
setTimeout(function () { | ||
const [record, changes] = listener.args[1] | ||
assert.equal(foo, record, "on 'change' listener called with record which was modified") | ||
assert.isTrue(listener.calledTwice, "on 'change' listener was called when modifying a property") | ||
assert.equal(Object.keys(changes.added).length, 0) | ||
assert.equal(Object.keys(changes.removed).length, 0) | ||
assert.equal(changes.changed.name, 'updated foo', "Only the property changed was emitted in the changeSet") | ||
done() | ||
}, 5) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I saw the other tests using timeout - but something like an eventloop.after(function() {}) would be a preferable approach for testing, not sure how difficult that is to do ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this case, something like this might work: setImmediate(function () {...}); however, the tests need to work in a bunch of different browsers, and I'm not sure how cross-browser |
||
} | ||
setTimeout(function () { | ||
const [record, changes] = listener.args[0] | ||
assert.equal(foo, record, "on 'change' listener called with record which was modified") | ||
assert.isTrue(listener.calledOnce, "on 'change' listener was called when modifying a property") | ||
assert.equal(Object.keys(changes.changed).length, 0) | ||
assert.equal(Object.keys(changes.removed).length, 0) | ||
assert.equal(changes.added.name, 'new foo', "Only the property changed was emitted in the changeSet") | ||
secondSpec() | ||
}, 5) | ||
}) | ||
|
||
it('keepChangeHistory: false', function(done) { | ||
const Store = new JSData.DataStore() | ||
|
||
class FooRecord extends Record { | ||
constructor(props, opts) { | ||
super(props, opts) | ||
this._set('keepChangeHistory', false) | ||
this._set('noValidate', true) | ||
} | ||
} | ||
|
||
const Foo = Store.defineMapper('foo', { | ||
recordClass: FooRecord, | ||
schema: { | ||
properties: { | ||
id: { type: 'number' }, | ||
name: { type: 'string', track: true } | ||
} | ||
}, | ||
}) | ||
|
||
const Bar = Store.defineMapper('bar', { | ||
schema: { | ||
properties: { | ||
id: { type: 'number' }, | ||
name: { type: 'string', track: true } | ||
} | ||
}, | ||
}) | ||
|
||
const foo = Foo.createRecord() | ||
const bar = Bar.createRecord() | ||
const listener = sinon.stub() | ||
foo.on('change', listener) | ||
bar.on('change', listener) | ||
foo.name = 'new foo' | ||
bar.name = 'new bar' | ||
setTimeout(function () { | ||
assert.isTrue(listener.calledTwice, "on 'change' listener was called when modifying properties") | ||
assert.deepEqual(foo.changeHistory(), [], "no changeHistory was stored if keepChangeHistory: false is set") | ||
assert.equal(bar.changeHistory().length, 1, "if keepChangeHistory is true by default changeHistory is present") | ||
done() | ||
}, 5) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just added a code comment to clarify the reason for adding the second test.