From aaf9f2ca99495e5b419684e9c046ec3446a58fd0 Mon Sep 17 00:00:00 2001 From: pik Date: Tue, 2 Aug 2016 14:35:15 -0300 Subject: [PATCH 1/3] belongsTo errors without inverse relation --- test/unit/decorators/belongsTo.test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/unit/decorators/belongsTo.test.js b/test/unit/decorators/belongsTo.test.js index 64413b7e..32636e76 100644 --- a/test/unit/decorators/belongsTo.test.js +++ b/test/unit/decorators/belongsTo.test.js @@ -77,6 +77,25 @@ describe('JSData.belongsTo', function () { assert.strictEqual(bar2.foo, foo) assert.strictEqual(bar3.foo, foo) }) + + it ('should not create an inverseLink if no inverseRelationship is defined', function() { + const store = new JSData.DataStore() + store.defineMapper('foo', { + }) + store.defineMapper('bar', { + relations: { + belongsTo: { + foo: { + localField: '_foo', + foreignKey: 'foo_id' + } + } + } + }) + const foo = store.add('foo', { id: 1 }) + const bar = store.add('bar', { id: 1, foo_id: 1 }) + }) + it('should add property accessors to prototype of target and allow relation re-assignment using customizations', function () { const store = new JSData.DataStore() store.defineMapper('foo', { From 50fc3302ede6b86cef6766ea675c8c5e1d9c347b Mon Sep 17 00:00:00 2001 From: pik Date: Tue, 2 Aug 2016 15:26:20 -0300 Subject: [PATCH 2/3] Fix belongsTo error without inverse relationship --- src/DataStore.js | 29 +++------------------ src/Record.js | 35 ++++++++++++++++++++++++++ test/unit/decorators/belongsTo.test.js | 1 + 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/DataStore.js b/src/DataStore.js index 3266e690..855db08d 100644 --- a/src/DataStore.js +++ b/src/DataStore.js @@ -1046,19 +1046,8 @@ const props = { // e.g. profile.user !== someUser // or comment.post !== somePost - if (currentParent) { - // e.g. otherUser.profile = undefined - if (inverseDef.type === hasOneType) { - safeSetLink(currentParent, inverseDef.localField, undefined) - } else if (inverseDef.type === hasManyType) { - // e.g. remove comment from otherPost.comments - const children = utils.get(currentParent, inverseDef.localField) - if (id === undefined) { - utils.remove(children, (child) => child === this) - } else { - utils.remove(children, (child) => child === this || id === utils.get(child, idAttribute)) - } - } + if (currentParent && inverseDef) { + this.removeInverseRelation(currentParent, id, inverseDef, idAttribute) } if (record) { // e.g. profile.user = someUser @@ -1077,18 +1066,8 @@ const props = { safeSetProp(this, foreignKey, relatedId) collection.updateIndex(this, updateOpts) - // Update (set) inverse relation - if (inverseDef.type === hasOneType) { - // e.g. someUser.profile = profile - safeSetLink(record, inverseDef.localField, this) - } else if (inverseDef.type === hasManyType) { - // e.g. add comment to somePost.comments - const children = utils.get(record, inverseDef.localField) - if (id === undefined) { - utils.noDupeAdd(children, this, (child) => child === this) - } else { - utils.noDupeAdd(children, this, (child) => child === this || id === utils.get(child, idAttribute)) - } + if (inverseDef) { + this.setupInverseRelation(record, id, inverseDef, idAttribute) } } else { // Unset in-memory link only diff --git a/src/Record.js b/src/Record.js index 37d9b811..d2a31b0b 100644 --- a/src/Record.js +++ b/src/Record.js @@ -1,6 +1,11 @@ import utils from './utils' import Component from './Component' import Settable from './Settable' +import { + belongsToType, + hasManyType, + hasOneType +} from './decorators' const DOMAIN = 'Record' @@ -386,6 +391,36 @@ export default Component.extend({ return !this._mapper().validate(this, opts) }, + removeInverseRelation(currentParent, id, inverseDef, idAttribute) { + if (inverseDef.type === hasOneType) { + safeSetLink(currentParent, inverseDef.localField, undefined) + } else if (inverseDef.type === hasManyType) { + // e.g. remove comment from otherPost.comments + const children = utils.get(currentParent, inverseDef.localField) + if (id === undefined) { + utils.remove(children, (child) => child === this) + } else { + utils.remove(children, (child) => child === this || id === utils.get(child, idAttribute)) + } + } + }, + + setupInverseRelation(record, id, inverseDef, idAttribute) { + // Update (set) inverse relation + if (inverseDef.type === hasOneType) { + // e.g. someUser.profile = profile + safeSetLink(record, inverseDef.localField, this) + } else if (inverseDef.type === hasManyType) { + // e.g. add comment to somePost.comments + const children = utils.get(record, inverseDef.localField) + if (id === undefined) { + utils.noDupeAdd(children, this, (child) => child === this) + } else { + utils.noDupeAdd(children, this, (child) => child === this || id === utils.get(child, idAttribute)) + } + } + }, + /** * Lazy load relations of this record, to be attached to the record once their * loaded. diff --git a/test/unit/decorators/belongsTo.test.js b/test/unit/decorators/belongsTo.test.js index 32636e76..ee2f0b3d 100644 --- a/test/unit/decorators/belongsTo.test.js +++ b/test/unit/decorators/belongsTo.test.js @@ -94,6 +94,7 @@ describe('JSData.belongsTo', function () { }) const foo = store.add('foo', { id: 1 }) const bar = store.add('bar', { id: 1, foo_id: 1 }) + assert.strictEqual(bar._foo, foo) }) it('should add property accessors to prototype of target and allow relation re-assignment using customizations', function () { From 7d05e20a0e9c99eb860d6eb8fee9cc78b56d8255 Mon Sep 17 00:00:00 2001 From: pik Date: Tue, 2 Aug 2016 15:39:22 -0300 Subject: [PATCH 3/3] Move safeSetProp, safeSetLink to utils --- src/DataStore.js | 19 ++----------------- src/Record.js | 2 +- src/utils.js | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/DataStore.js b/src/DataStore.js index 855db08d..44042a13 100644 --- a/src/DataStore.js +++ b/src/DataStore.js @@ -1,4 +1,5 @@ -import utils from './utils' +import utils, { safeSetLink, safeSetProp } from './utils' + import { belongsToType, hasManyType, @@ -261,22 +262,6 @@ const ownMethodsForScoping = [ 'hashQuery' ] -const safeSetProp = function (record, field, value) { - if (record && record._set) { - record._set(`props.${field}`, value) - } else { - utils.set(record, field, value) - } -} - -const safeSetLink = function (record, field, value) { - if (record && record._set) { - record._set(`links.${field}`, value) - } else { - utils.set(record, field, value) - } -} - const cachedFn = function (name, hashOrId, opts) { const cached = this._completedQueries[name][hashOrId] if (utils.isFunction(cached)) { diff --git a/src/Record.js b/src/Record.js index d2a31b0b..90023262 100644 --- a/src/Record.js +++ b/src/Record.js @@ -1,4 +1,4 @@ -import utils from './utils' +import utils, { safeSetLink } from './utils' import Component from './Component' import Settable from './Settable' import { diff --git a/src/utils.js b/src/utils.js index eda53641..ef09b441 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1576,6 +1576,23 @@ http://www.js-data.io/v3.0/docs/errors#${code}` } object[last] = undefined + }, + +} + +export const safeSetProp = function (record, field, value) { + if (record && record._set) { + record._set(`props.${field}`, value) + } else { + utils.set(record, field, value) + } +} + +export const safeSetLink = function (record, field, value) { + if (record && record._set) { + record._set(`links.${field}`, value) + } else { + utils.set(record, field, value) } }