diff --git a/addon/-private/system/relationships/state/belongs-to.js b/addon/-private/system/relationships/state/belongs-to.js index 802708cc5b0..2b6089d828a 100644 --- a/addon/-private/system/relationships/state/belongs-to.js +++ b/addon/-private/system/relationships/state/belongs-to.js @@ -5,163 +5,156 @@ import { } from "ember-data/-private/system/promise-proxies"; import { assertPolymorphicType } from "ember-data/-private/debug"; - import Relationship from "ember-data/-private/system/relationships/state/relationship"; -export default function BelongsToRelationship(store, record, inverseKey, relationshipMeta) { - this._super$constructor(store, record, inverseKey, relationshipMeta); - this.record = record; - this.key = relationshipMeta.key; - this.inverseRecord = null; - this.canonicalState = null; -} +export default class BelongsToRelationship extends Relationship { + constructor(store, internalModel, inverseKey, relationshipMeta) { + super(store, internalModel, inverseKey, relationshipMeta); + this.internalModel = internalModel; + this.key = relationshipMeta.key; + this.inverseRecord = null; + this.canonicalState = null; + } -BelongsToRelationship.prototype = Object.create(Relationship.prototype); -BelongsToRelationship.prototype.constructor = BelongsToRelationship; -BelongsToRelationship.prototype._super$constructor = Relationship; + setRecord(newRecord) { + if (newRecord) { + this.addRecord(newRecord); + } else if (this.inverseRecord) { + this.removeRecord(this.inverseRecord); + } + this.setHasData(true); + this.setHasLoaded(true); + } -BelongsToRelationship.prototype.setRecord = function(newRecord) { - if (newRecord) { - this.addRecord(newRecord); - } else if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); + setCanonicalRecord(newRecord) { + if (newRecord) { + this.addCanonicalRecord(newRecord); + } else if (this.canonicalState) { + this.removeCanonicalRecord(this.canonicalState); + } + this.flushCanonicalLater(); } - this.setHasData(true); - this.setHasLoaded(true); -}; - -BelongsToRelationship.prototype.setCanonicalRecord = function(newRecord) { - if (newRecord) { - this.addCanonicalRecord(newRecord); - } else if (this.canonicalState) { - this.removeCanonicalRecord(this.canonicalState); + + addCanonicalRecord(newRecord) { + if (this.canonicalMembers.has(newRecord)) { return;} + + if (this.canonicalState) { + this.removeCanonicalRecord(this.canonicalState); + } + + this.canonicalState = newRecord; + super.addCanonicalRecord(newRecord); } - this.flushCanonicalLater(); -}; -BelongsToRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; -BelongsToRelationship.prototype.addCanonicalRecord = function(newRecord) { - if (this.canonicalMembers.has(newRecord)) { return;} + flushCanonical() { + //temporary fix to not remove newly created records if server returned null. + //TODO remove once we have proper diffing + if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { + return; + } + if (this.inverseRecord !== this.canonicalState) { + this.inverseRecord = this.canonicalState; + this.internalModel.notifyBelongsToChanged(this.key); + } - if (this.canonicalState) { - this.removeCanonicalRecord(this.canonicalState); + super.flushCanonical(); } - this.canonicalState = newRecord; - this._super$addCanonicalRecord(newRecord); -}; + addRecord(newRecord) { + if (this.members.has(newRecord)) { return; } + + assertPolymorphicType(this.internalModel, this.relationshipMeta, newRecord); + + if (this.inverseRecord) { + this.removeRecord(this.inverseRecord); + } -BelongsToRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; -BelongsToRelationship.prototype.flushCanonical = function() { - //temporary fix to not remove newly created records if server returned null. - //TODO remove once we have proper diffing - if (this.inverseRecord && this.inverseRecord.isNew() && !this.canonicalState) { - return; + this.inverseRecord = newRecord; + super.addRecord(newRecord); + this.internalModel.notifyBelongsToChanged(this.key); } - if (this.inverseRecord !== this.canonicalState) { - this.inverseRecord = this.canonicalState; - this.record.notifyBelongsToChanged(this.key); + + setRecordPromise(newPromise) { + var content = newPromise.get && newPromise.get('content'); + assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); + this.setRecord(content ? content._internalModel : content); } - this._super$flushCanonical(); -}; -BelongsToRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; -BelongsToRelationship.prototype.addRecord = function(newRecord) { - if (this.members.has(newRecord)) { return;} + removeRecordFromOwn(record) { + if (!this.members.has(record)) { return;} + this.inverseRecord = null; + super.removeRecordFromOwn(record); + this.internalModel.notifyBelongsToChanged(this.key); + } - assertPolymorphicType(this.record, this.relationshipMeta, newRecord); + removeCanonicalRecordFromOwn(record) { + if (!this.canonicalMembers.has(record)) { return;} + this.canonicalState = null; + super.removeCanonicalRecordFromOwn(record); + } - if (this.inverseRecord) { - this.removeRecord(this.inverseRecord); + findRecord() { + if (this.inverseRecord) { + return this.store._findByInternalModel(this.inverseRecord); + } else { + return Ember.RSVP.Promise.resolve(null); + } } - this.inverseRecord = newRecord; - this._super$addRecord(newRecord); - this.record.notifyBelongsToChanged(this.key); -}; - -BelongsToRelationship.prototype.setRecordPromise = function(newPromise) { - var content = newPromise.get && newPromise.get('content'); - assert("You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo or hasMany relationship to the get call.", content !== undefined); - this.setRecord(content ? content._internalModel : content); -}; - -BelongsToRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; -BelongsToRelationship.prototype.removeRecordFromOwn = function(record) { - if (!this.members.has(record)) { return;} - this.inverseRecord = null; - this._super$removeRecordFromOwn(record); - this.record.notifyBelongsToChanged(this.key); -}; - -BelongsToRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; -BelongsToRelationship.prototype.removeCanonicalRecordFromOwn = function(record) { - if (!this.canonicalMembers.has(record)) { return;} - this.canonicalState = null; - this._super$removeCanonicalRecordFromOwn(record); -}; - -BelongsToRelationship.prototype.findRecord = function() { - if (this.inverseRecord) { - return this.store._findByInternalModel(this.inverseRecord); - } else { - return Ember.RSVP.Promise.resolve(null); + fetchLink() { + return this.store.findBelongsTo(this.internalModel, this.link, this.relationshipMeta).then((record) => { + if (record) { + this.addRecord(record); + } + return record; + }); } -}; -BelongsToRelationship.prototype.fetchLink = function() { - return this.store.findBelongsTo(this.record, this.link, this.relationshipMeta).then((record) => { - if (record) { - this.addRecord(record); - } - return record; - }); -}; - -BelongsToRelationship.prototype.getRecord = function() { - //TODO(Igor) flushCanonical here once our syncing is not stupid - if (this.isAsync) { - var promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecord(); + getRecord() { + //TODO(Igor) flushCanonical here once our syncing is not stupid + if (this.isAsync) { + var promise; + if (this.link) { + if (this.hasLoaded) { + promise = this.findRecord(); + } else { + promise = this.findLink().then(() => this.findRecord()); + } } else { - promise = this.findLink().then(() => this.findRecord()); + promise = this.findRecord(); } + + return PromiseObject.create({ + promise: promise, + content: this.inverseRecord ? this.inverseRecord.getRecord() : null + }); } else { - promise = this.findRecord(); + if (this.inverseRecord === null) { + return null; + } + var toReturn = this.inverseRecord.getRecord(); + assert("You looked up the '" + this.key + "' relationship on a '" + this.internalModel.modelName + "' with id " + this.internalModel.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); + return toReturn; } + } - return PromiseObject.create({ - promise: promise, - content: this.inverseRecord ? this.inverseRecord.getRecord() : null - }); - } else { - if (this.inverseRecord === null) { - return null; + reload() { + // TODO handle case when reload() is triggered multiple times + + if (this.link) { + return this.fetchLink(); } - var toReturn = this.inverseRecord.getRecord(); - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.belongsTo({ async: true })`)", toReturn === null || !toReturn.get('isEmpty')); - return toReturn; - } -}; -BelongsToRelationship.prototype.reload = function() { - // TODO handle case when reload() is triggered multiple times + // reload record, if it is already loaded + if (this.inverseRecord && this.inverseRecord.hasRecord) { + return this.inverseRecord.record.reload(); + } - if (this.link) { - return this.fetchLink(); + return this.findRecord(); } - // reload record, if it is already loaded - if (this.inverseRecord && this.inverseRecord.hasRecord) { - return this.inverseRecord.record.reload(); + updateData(data) { + let internalModel = this.store._pushResourceIdentifier(this, data); + this.setCanonicalRecord(internalModel); } - - return this.findRecord(); -}; - -BelongsToRelationship.prototype.updateData = function(data) { - let internalModel = this.store._pushResourceIdentifier(this, data); - this.setCanonicalRecord(internalModel); -}; +} diff --git a/addon/-private/system/relationships/state/create.js b/addon/-private/system/relationships/state/create.js index b5da724a921..6b6c1c67c31 100644 --- a/addon/-private/system/relationships/state/create.js +++ b/addon/-private/system/relationships/state/create.js @@ -3,18 +3,18 @@ import ManyRelationship from "ember-data/-private/system/relationships/state/has import BelongsToRelationship from "ember-data/-private/system/relationships/state/belongs-to"; import EmptyObject from "ember-data/-private/system/empty-object"; -var get = Ember.get; +const { get } = Ember; function shouldFindInverse(relationshipMeta) { let options = relationshipMeta.options; return !(options && options.inverse === null); } -function createRelationshipFor(record, relationshipMeta, store) { +function createRelationshipFor(internalModel, relationshipMeta, store) { let inverseKey; let inverse = null; if (shouldFindInverse(relationshipMeta)) { - inverse = record.type.inverseFor(relationshipMeta.key, store); + inverse = internalModel.type.inverseFor(relationshipMeta.key, store); } if (inverse) { @@ -22,26 +22,36 @@ function createRelationshipFor(record, relationshipMeta, store) { } if (relationshipMeta.kind === 'hasMany') { - return new ManyRelationship(store, record, inverseKey, relationshipMeta); + return new ManyRelationship(store, internalModel, inverseKey, relationshipMeta); } else { - return new BelongsToRelationship(store, record, inverseKey, relationshipMeta); + return new BelongsToRelationship(store, internalModel, inverseKey, relationshipMeta); } } -export default function Relationships(record) { - this.record = record; - this.initializedRelationships = new EmptyObject(); -} +export default class Relationships { + constructor(internalModel) { + this.internalModel = internalModel; + this.initializedRelationships = new EmptyObject(); + } + + // TODO @runspired deprecate this as it was never truly a record instance + get record() { + return this.internalModel; + } -Relationships.prototype.has = function(key) { - return !!this.initializedRelationships[key]; -}; + has(key) { + return !!this.initializedRelationships[key]; + } + + get(key) { + let relationships = this.initializedRelationships; + let internalModel = this.internalModel; + let relationshipsByName = get(internalModel.type, 'relationshipsByName'); -Relationships.prototype.get = function(key) { - var relationships = this.initializedRelationships; - var relationshipsByName = get(this.record.type, 'relationshipsByName'); - if (!relationships[key] && relationshipsByName.get(key)) { - relationships[key] = createRelationshipFor(this.record, relationshipsByName.get(key), this.record.store); + if (!relationships[key] && relationshipsByName.get(key)) { + relationships[key] = createRelationshipFor(internalModel, relationshipsByName.get(key), internalModel.store); + } + + return relationships[key]; } - return relationships[key]; -}; +} diff --git a/addon/-private/system/relationships/state/has-many.js b/addon/-private/system/relationships/state/has-many.js index 76f790eb6e0..881552024dd 100644 --- a/addon/-private/system/relationships/state/has-many.js +++ b/addon/-private/system/relationships/state/has-many.js @@ -6,234 +6,228 @@ import ManyArray from "ember-data/-private/system/many-array"; import { assertPolymorphicType } from "ember-data/-private/debug"; -export default function ManyRelationship(store, record, inverseKey, relationshipMeta) { - this._super$constructor(store, record, inverseKey, relationshipMeta); - this.belongsToType = relationshipMeta.type; - this.canonicalState = []; - this.isPolymorphic = relationshipMeta.options.polymorphic; -} - -ManyRelationship.prototype = Object.create(Relationship.prototype); -ManyRelationship.prototype.getManyArray = function() { - if (!this._manyArray) { - this._manyArray = ManyArray.create({ - canonicalState: this.canonicalState, - store: this.store, - relationship: this, - type: this.store.modelFor(this.belongsToType), - record: this.record, - meta: this.meta, - isPolymorphic: this.isPolymorphic - }); +export default class ManyRelationship extends Relationship { + constructor(store, record, inverseKey, relationshipMeta) { + super(store, record, inverseKey, relationshipMeta); + this.belongsToType = relationshipMeta.type; + this.canonicalState = []; + this.isPolymorphic = relationshipMeta.options.polymorphic; + } + + getManyArray() { + if (!this._manyArray) { + this._manyArray = ManyArray.create({ + canonicalState: this.canonicalState, + store: this.store, + relationship: this, + type: this.store.modelFor(this.belongsToType), + record: this.record, + meta: this.meta, + isPolymorphic: this.isPolymorphic + }); + } + return this._manyArray; } - return this._manyArray; -}; -ManyRelationship.prototype.constructor = ManyRelationship; -ManyRelationship.prototype._super$constructor = Relationship; - -ManyRelationship.prototype.destroy = function() { - if (this._manyArray) { - this._manyArray.destroy(); + destroy() { + if (this._manyArray) { + this._manyArray.destroy(); + } } -}; -ManyRelationship.prototype._super$updateMeta = Relationship.prototype.updateMeta; -ManyRelationship.prototype.updateMeta = function(meta) { - this._super$updateMeta(meta); - if (this._manyArray) { - this._manyArray.set('meta', meta); + updateMeta(meta) { + super.updateMeta(meta); + if (this._manyArray) { + this._manyArray.set('meta', meta); + } } -}; -ManyRelationship.prototype._super$addCanonicalRecord = Relationship.prototype.addCanonicalRecord; -ManyRelationship.prototype.addCanonicalRecord = function(record, idx) { - if (this.canonicalMembers.has(record)) { - return; - } - if (idx !== undefined) { - this.canonicalState.splice(idx, 0, record); - } else { - this.canonicalState.push(record); + addCanonicalRecord(record, idx) { + if (this.canonicalMembers.has(record)) { + return; + } + if (idx !== undefined) { + this.canonicalState.splice(idx, 0, record); + } else { + this.canonicalState.push(record); + } + super.addCanonicalRecord(record, idx); } - this._super$addCanonicalRecord(record, idx); -}; -ManyRelationship.prototype._super$addRecord = Relationship.prototype.addRecord; -ManyRelationship.prototype.addRecord = function(record, idx) { - if (this.members.has(record)) { - return; + addRecord(record, idx) { + if (this.members.has(record)) { + return; + } + super.addRecord(record, idx); + // make lazy later + this.getManyArray().internalAddRecords([record], idx); } - this._super$addRecord(record, idx); - // make lazy later - this.getManyArray().internalAddRecords([record], idx); -}; -ManyRelationship.prototype._super$removeCanonicalRecordFromOwn = Relationship.prototype.removeCanonicalRecordFromOwn; -ManyRelationship.prototype.removeCanonicalRecordFromOwn = function(record, idx) { - var i = idx; - if (!this.canonicalMembers.has(record)) { - return; - } - if (i === undefined) { - i = this.canonicalState.indexOf(record); - } - if (i > -1) { - this.canonicalState.splice(i, 1); + removeCanonicalRecordFromOwn(record, idx) { + var i = idx; + if (!this.canonicalMembers.has(record)) { + return; + } + if (i === undefined) { + i = this.canonicalState.indexOf(record); + } + if (i > -1) { + this.canonicalState.splice(i, 1); + } + super.removeCanonicalRecordFromOwn(record, idx); } - this._super$removeCanonicalRecordFromOwn(record, idx); -}; -ManyRelationship.prototype._super$flushCanonical = Relationship.prototype.flushCanonical; -ManyRelationship.prototype.flushCanonical = function() { - if (this._manyArray) { - this._manyArray.flushCanonical(); + flushCanonical() { + if (this._manyArray) { + this._manyArray.flushCanonical(); + } + super.flushCanonical(); } - this._super$flushCanonical(); -}; -ManyRelationship.prototype._super$removeRecordFromOwn = Relationship.prototype.removeRecordFromOwn; -ManyRelationship.prototype.removeRecordFromOwn = function(record, idx) { - if (!this.members.has(record)) { - return; - } - this._super$removeRecordFromOwn(record, idx); - let manyArray = this.getManyArray(); - if (idx !== undefined) { - //TODO(Igor) not used currently, fix - manyArray.currentState.removeAt(idx); - } else { - manyArray.internalRemoveRecords([record]); + removeRecordFromOwn(record, idx) { + if (!this.members.has(record)) { + return; + } + super.removeRecordFromOwn(record, idx); + let manyArray = this.getManyArray(); + if (idx !== undefined) { + //TODO(Igor) not used currently, fix + manyArray.currentState.removeAt(idx); + } else { + manyArray.internalRemoveRecords([record]); + } } -}; -ManyRelationship.prototype.notifyRecordRelationshipAdded = function(record, idx) { - assertPolymorphicType(this.record, this.relationshipMeta, record); + notifyRecordRelationshipAdded(record, idx) { + assertPolymorphicType(this.record, this.relationshipMeta, record); - this.record.notifyHasManyAdded(this.key, record, idx); -}; + this.record.notifyHasManyAdded(this.key, record, idx); + } -ManyRelationship.prototype.reload = function() { - let manyArray = this.getManyArray(); - let manyArrayLoadedState = manyArray.get('isLoaded'); + reload() { + let manyArray = this.getManyArray(); + let manyArrayLoadedState = manyArray.get('isLoaded'); - if (this._loadingPromise) { - if (this._loadingPromise.get('isPending')) { - return this._loadingPromise; - } - if (this._loadingPromise.get('isRejected')) { - manyArray.set('isLoaded', manyArrayLoadedState); + if (this._loadingPromise) { + if (this._loadingPromise.get('isPending')) { + return this._loadingPromise; + } + if (this._loadingPromise.get('isRejected')) { + manyArray.set('isLoaded', manyArrayLoadedState); + } } - } - if (this.link) { - this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); - return this._loadingPromise; - } else { - this._loadingPromise = promiseManyArray(this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray), 'Reload with ids'); - return this._loadingPromise; + if (this.link) { + this._loadingPromise = promiseManyArray(this.fetchLink(), 'Reload with link'); + return this._loadingPromise; + } else { + this._loadingPromise = promiseManyArray(this.store._scheduleFetchMany(manyArray.currentState).then(() => manyArray), 'Reload with ids'); + return this._loadingPromise; + } } -}; -ManyRelationship.prototype.computeChanges = function(records) { - var members = this.canonicalMembers; - var recordsToRemove = []; - var length; - var record; - var i; + computeChanges(records) { + var members = this.canonicalMembers; + var recordsToRemove = []; + var length; + var record; + var i; - records = setForArray(records); + records = setForArray(records); - members.forEach(function(member) { - if (records.has(member)) { return; } + members.forEach(function(member) { + if (records.has(member)) { return; } - recordsToRemove.push(member); - }); + recordsToRemove.push(member); + }); - this.removeCanonicalRecords(recordsToRemove); + this.removeCanonicalRecords(recordsToRemove); + + // Using records.toArray() since currently using + // removeRecord can modify length, messing stuff up + // forEach since it directly looks at "length" each + // iteration + records = records.toArray(); + length = records.length; + for (i = 0; i < length; i++) { + record = records[i]; + this.removeCanonicalRecord(record); + this.addCanonicalRecord(record, i); + } + } - // Using records.toArray() since currently using - // removeRecord can modify length, messing stuff up - // forEach since it directly looks at "length" each - // iteration - records = records.toArray(); - length = records.length; - for (i = 0; i < length; i++) { - record = records[i]; - this.removeCanonicalRecord(record); - this.addCanonicalRecord(record, i); + fetchLink() { + return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => { + if (records.hasOwnProperty('meta')) { + this.updateMeta(records.meta); + } + this.store._backburner.join(() => { + this.updateRecordsFromAdapter(records); + this.getManyArray().set('isLoaded', true); + }); + return this.getManyArray(); + }); } -}; -ManyRelationship.prototype.fetchLink = function() { - return this.store.findHasMany(this.record, this.link, this.relationshipMeta).then((records) => { - if (records.hasOwnProperty('meta')) { - this.updateMeta(records.meta); + findRecords() { + let manyArray = this.getManyArray(); + let array = manyArray.toArray(); + let internalModels = new Array(array.length); + + for (let i = 0; i < array.length; i++) { + internalModels[i] = array[i]._internalModel; } - this.store._backburner.join(() => { - this.updateRecordsFromAdapter(records); - this.getManyArray().set('isLoaded', true); + + //TODO CLEANUP + return this.store.findMany(internalModels).then(() => { + if (!manyArray.get('isDestroyed')) { + //Goes away after the manyArray refactor + manyArray.set('isLoaded', true); + } + return manyArray; }); - return this.getManyArray(); - }); -}; - -ManyRelationship.prototype.findRecords = function() { - let manyArray = this.getManyArray() - let array = manyArray.toArray(); - let internalModels = new Array(array.length); - - for (let i = 0; i < array.length; i++) { - internalModels[i] = array[i]._internalModel; - } - - //TODO CLEANUP - return this.store.findMany(internalModels).then(() => { - if (!manyArray.get('isDestroyed')) { - //Goes away after the manyArray refactor - manyArray.set('isLoaded', true); - } - return manyArray; - }); -}; -ManyRelationship.prototype.notifyHasManyChanged = function() { - this.record.notifyHasManyAdded(this.key); -}; - -ManyRelationship.prototype.getRecords = function() { - //TODO(Igor) sync server here, once our syncing is not stupid - let manyArray = this.getManyArray(); - if (this.isAsync) { - var promise; - if (this.link) { - if (this.hasLoaded) { - promise = this.findRecords(); + } + + notifyHasManyChanged() { + this.record.notifyHasManyAdded(this.key); + } + + getRecords() { + //TODO(Igor) sync server here, once our syncing is not stupid + let manyArray = this.getManyArray(); + if (this.isAsync) { + var promise; + if (this.link) { + if (this.hasLoaded) { + promise = this.findRecords(); + } else { + promise = this.findLink().then(() => this.findRecords()); + } } else { - promise = this.findLink().then(() => this.findRecords()); + promise = this.findRecords(); } + this._loadingPromise = PromiseManyArray.create({ + content: manyArray, + promise: promise + }); + return this._loadingPromise; } else { - promise = this.findRecords(); - } - this._loadingPromise = PromiseManyArray.create({ - content: manyArray, - promise: promise - }); - return this._loadingPromise; - } else { - assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); + assert("You looked up the '" + this.key + "' relationship on a '" + this.record.type.modelName + "' with id " + this.record.id + " but some of the associated records were not loaded. Either make sure they are all loaded together with the parent record, or specify that the relationship is async (`DS.hasMany({ async: true })`)", manyArray.isEvery('isEmpty', false)); - //TODO(Igor) WTF DO I DO HERE? - if (!manyArray.get('isDestroyed')) { - manyArray.set('isLoaded', true); + //TODO(Igor) WTF DO I DO HERE? + // TODO @runspired equal WTFs to Igor + if (!manyArray.get('isDestroyed')) { + manyArray.set('isLoaded', true); + } + return manyArray; } - return manyArray; } -}; -ManyRelationship.prototype.updateData = function(data) { - let internalModels = this.store._pushResourceIdentifiers(this, data); - this.updateRecordsFromAdapter(internalModels); -}; + updateData(data) { + let internalModels = this.store._pushResourceIdentifiers(this, data); + this.updateRecordsFromAdapter(internalModels); + } +} function setForArray(array) { var set = new OrderedSet(); diff --git a/addon/-private/system/relationships/state/relationship.js b/addon/-private/system/relationships/state/relationship.js index 7266ef6cb28..e361526bc9d 100644 --- a/addon/-private/system/relationships/state/relationship.js +++ b/addon/-private/system/relationships/state/relationship.js @@ -53,35 +53,42 @@ const { 'updateRecordsFromAdapter' ); -export default function Relationship(store, record, inverseKey, relationshipMeta) { - heimdall.increment(newRelationship); - var async = relationshipMeta.options.async; - this.members = new OrderedSet(); - this.canonicalMembers = new OrderedSet(); - this.store = store; - this.key = relationshipMeta.key; - this.inverseKey = inverseKey; - this.record = record; - this.isAsync = typeof async === 'undefined' ? true : async; - this.relationshipMeta = relationshipMeta; - //This probably breaks for polymorphic relationship in complex scenarios, due to - //multiple possible modelNames - this.inverseKeyForImplicit = this.record.constructor.modelName + this.key; - this.linkPromise = null; - this.meta = null; - this.hasData = false; - this.hasLoaded = false; -} +export default class Relationship { + constructor(store, internalModel, inverseKey, relationshipMeta) { + heimdall.increment(newRelationship); + var async = relationshipMeta.options.async; + this.members = new OrderedSet(); + this.canonicalMembers = new OrderedSet(); + this.store = store; + this.key = relationshipMeta.key; + this.inverseKey = inverseKey; + this.internalModel = internalModel; + this.isAsync = typeof async === 'undefined' ? true : async; + this.relationshipMeta = relationshipMeta; + //This probably breaks for polymorphic relationship in complex scenarios, due to + //multiple possible modelNames + this.inverseKeyForImplicit = this.internalModel.modelName + this.key; + this.linkPromise = null; + this.meta = null; + this.hasData = false; + this.hasLoaded = false; + } -Relationship.prototype = { - constructor: Relationship, + // TODO @runspired deprecate this as it was never truly a record instance + get record() { + return this.internalModel; + } - destroy() { }, + get parentType() { + return this.internalModel.modelName; + } + + destroy() { } updateMeta(meta) { heimdall.increment(updateMeta); this.meta = meta; - }, + } clear() { heimdall.increment(clear); @@ -92,12 +99,12 @@ Relationship.prototype = { member = members[0]; this.removeRecord(member); } - }, + } removeRecords(records) { heimdall.increment(removeRecords); records.forEach((record) => this.removeRecord(record)); - }, + } addRecords(records, idx) { heimdall.increment(addRecords); @@ -107,7 +114,7 @@ Relationship.prototype = { idx++; } }); - }, + } addCanonicalRecords(records, idx) { heimdall.increment(addCanonicalRecords); @@ -118,7 +125,7 @@ Relationship.prototype = { this.addCanonicalRecord(records[i]); } } - }, + } addCanonicalRecord(record, idx) { heimdall.increment(addCanonicalRecord); @@ -135,7 +142,7 @@ Relationship.prototype = { } this.flushCanonicalLater(); this.setHasData(true); - }, + } removeCanonicalRecords(records, idx) { heimdall.increment(removeCanonicalRecords); @@ -146,7 +153,7 @@ Relationship.prototype = { this.removeCanonicalRecord(records[i]); } } - }, + } removeCanonicalRecord(record, idx) { heimdall.increment(removeCanonicalRecord); @@ -161,7 +168,7 @@ Relationship.prototype = { } } this.flushCanonicalLater(); - }, + } addRecord(record, idx) { heimdall.increment(addRecord); @@ -179,7 +186,7 @@ Relationship.prototype = { this.record.updateRecordArraysLater(); } this.setHasData(true); - }, + } removeRecord(record) { heimdall.increment(removeRecord); @@ -193,7 +200,7 @@ Relationship.prototype = { } } } - }, + } removeRecordFromInverse(record) { heimdall.increment(removeRecordFromInverse); @@ -202,14 +209,14 @@ Relationship.prototype = { if (inverseRelationship) { inverseRelationship.removeRecordFromOwn(this.record); } - }, + } removeRecordFromOwn(record) { heimdall.increment(removeRecordFromOwn); this.members.delete(record); this.notifyRecordRelationshipRemoved(record); this.record.updateRecordArrays(); - }, + } removeCanonicalRecordFromInverse(record) { heimdall.increment(removeCanonicalRecordFromInverse); @@ -218,13 +225,13 @@ Relationship.prototype = { if (inverseRelationship) { inverseRelationship.removeCanonicalRecordFromOwn(this.record); } - }, + } removeCanonicalRecordFromOwn(record) { heimdall.increment(removeCanonicalRecordFromOwn); this.canonicalMembers.delete(record); this.flushCanonicalLater(); - }, + } flushCanonical() { heimdall.increment(flushCanonical); @@ -232,17 +239,17 @@ Relationship.prototype = { //a hack for not removing new records //TODO remove once we have proper diffing var newRecords = []; - for (var i=0; i this.store._backburner.schedule('syncRelationships', this, this.flushCanonical)); - }, + } updateLink(link) { heimdall.increment(updateLink); @@ -263,7 +270,7 @@ Relationship.prototype = { this.link = link; this.linkPromise = null; this.record.notifyPropertyChange(this.key); - }, + } findLink() { heimdall.increment(findLink); @@ -274,55 +281,55 @@ Relationship.prototype = { this.linkPromise = promise; return promise.then((result) => result); } - }, + } updateRecordsFromAdapter(records) { heimdall.increment(updateRecordsFromAdapter); //TODO(Igor) move this to a proper place //TODO Once we have adapter support, we need to handle updated and canonical changes this.computeChanges(records); - }, + } - notifyRecordRelationshipAdded() { }, - notifyRecordRelationshipRemoved() { }, + notifyRecordRelationshipAdded() { } + notifyRecordRelationshipRemoved() { } /* - `hasData` for a relationship is a flag to indicate if we consider the - content of this relationship "known". Snapshots uses this to tell the - difference between unknown (`undefined`) or empty (`null`). The reason for - this is that we wouldn't want to serialize unknown relationships as `null` - as that might overwrite remote state. - - All relationships for a newly created (`store.createRecord()`) are - considered known (`hasData === true`). + `hasData` for a relationship is a flag to indicate if we consider the + content of this relationship "known". Snapshots uses this to tell the + difference between unknown (`undefined`) or empty (`null`). The reason for + this is that we wouldn't want to serialize unknown relationships as `null` + as that might overwrite remote state. + + All relationships for a newly created (`store.createRecord()`) are + considered known (`hasData === true`). */ setHasData(value) { heimdall.increment(setHasData); this.hasData = value; - }, + } /* - `hasLoaded` is a flag to indicate if we have gotten data from the adapter or - not when the relationship has a link. + `hasLoaded` is a flag to indicate if we have gotten data from the adapter or + not when the relationship has a link. - This is used to be able to tell when to fetch the link and when to return - the local data in scenarios where the local state is considered known - (`hasData === true`). + This is used to be able to tell when to fetch the link and when to return + the local data in scenarios where the local state is considered known + (`hasData === true`). - Updating the link will automatically set `hasLoaded` to `false`. + Updating the link will automatically set `hasLoaded` to `false`. */ setHasLoaded(value) { heimdall.increment(setHasLoaded); this.hasLoaded = value; - }, + } /* - `push` for a relationship allows the store to push a JSON API Relationship - Object onto the relationship. The relationship will then extract and set the - meta, data and links of that relationship. + `push` for a relationship allows the store to push a JSON API Relationship + Object onto the relationship. The relationship will then extract and set the + meta, data and links of that relationship. - `push` use `updateMeta`, `updateData` and `updateLink` to update the state - of the relationship. + `push` use `updateMeta`, `updateData` and `updateLink` to update the state + of the relationship. */ push(payload) { heimdall.increment(push); @@ -348,16 +355,16 @@ Relationship.prototype = { } /* - Data being pushed into the relationship might contain only data or links, - or a combination of both. + Data being pushed into the relationship might contain only data or links, + or a combination of both. - If we got data we want to set both hasData and hasLoaded to true since - this would indicate that we should prefer the local state instead of - trying to fetch the link or call findRecord(). + If we got data we want to set both hasData and hasLoaded to true since + this would indicate that we should prefer the local state instead of + trying to fetch the link or call findRecord(). - If we have no data but a link is present we want to set hasLoaded to false - without modifying the hasData flag. This will ensure we fetch the updated - link next time the relationship is accessed. + If we have no data but a link is present we want to set hasLoaded to false + without modifying the hasData flag. This will ensure we fetch the updated + link next time the relationship is accessed. */ if (hasData) { this.setHasData(true); @@ -365,7 +372,7 @@ Relationship.prototype = { } else if (hasLink) { this.setHasLoaded(false); } - }, + } updateData() {} -}; +}