UNPKG

@ember-data/record-data

Version:

Provides the default RecordData implementation for ember-data

219 lines (186 loc) 6.78 kB
import { assert, inspect } from '@ember/debug'; import { isNone } from '@ember/utils'; import { assertPolymorphicType } from '@ember-data/store/-debug'; import Relationship from './relationship'; type ExistingResourceIdentifierObject = import('@ember-data/store/-private/ts-interfaces/ember-data-json-api').ExistingResourceIdentifierObject; type RelationshipSchema = import('@ember-data/store/-private/ts-interfaces/record-data-schemas').RelationshipSchema; type RelationshipRecordData = import('../../ts-interfaces/relationship-record-data').RelationshipRecordData; type DefaultSingleResourceRelationship = import('../../ts-interfaces/relationship-record-data').DefaultSingleResourceRelationship; export default class BelongsToRelationship extends Relationship { inverseRecordData: RelationshipRecordData | null; canonicalState: RelationshipRecordData | null; key: string; constructor( store: any, inverseKey: string | null, relationshipMeta: RelationshipSchema, recordData: RelationshipRecordData, inverseIsAsync: boolean ) { super(store, inverseKey, relationshipMeta, recordData, inverseIsAsync); this.key = relationshipMeta.key; this.inverseRecordData = null; this.canonicalState = null; this.key = relationshipMeta.key; } setRecordData(recordData: RelationshipRecordData) { if (recordData) { this.addRecordData(recordData); } else if (this.inverseRecordData) { this.removeRecordData(this.inverseRecordData); } this.setHasAnyRelationshipData(true); this.setRelationshipIsStale(false); this.setRelationshipIsEmpty(false); } setCanonicalRecordData(recordData: RelationshipRecordData) { if (recordData) { this.addCanonicalRecordData(recordData); } else if (this.canonicalState) { this.removeCanonicalRecordData(this.canonicalState); } this.flushCanonicalLater(); } setInitialCanonicalRecordData(recordData: RelationshipRecordData) { if (!recordData) { return; } // When we initialize a belongsTo relationship, we want to avoid work like // notifying our internalModel that we've "changed" and excessive thrash on // setting up inverse relationships this.canonicalMembers.add(recordData); this.members.add(recordData); this.inverseRecordData = this.canonicalState = recordData; this.setupInverseRelationship(recordData); } addCanonicalRecordData(recordData: RelationshipRecordData) { if (this.canonicalMembers.has(recordData)) { return; } if (this.canonicalState) { this.removeCanonicalRecordData(this.canonicalState); } this.canonicalState = recordData; super.addCanonicalRecordData(recordData); this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(false); } inverseDidDematerialize() { super.inverseDidDematerialize(this.inverseRecordData); this.notifyBelongsToChange(); } removeCompletelyFromOwn(recordData: RelationshipRecordData) { super.removeCompletelyFromOwn(recordData); if (this.canonicalState === recordData) { this.canonicalState = null; } if (this.inverseRecordData === recordData) { this.inverseRecordData = null; this.notifyBelongsToChange(); } } removeCompletelyFromInverse() { super.removeCompletelyFromInverse(); this.inverseRecordData = null; } flushCanonical() { //temporary fix to not remove newly created records if server returned null. //TODO remove once we have proper diffing if (this.inverseRecordData && this.inverseRecordData.isNew() && !this.canonicalState) { this.willSync = false; return; } if (this.inverseRecordData !== this.canonicalState) { this.inverseRecordData = this.canonicalState; this.notifyBelongsToChange(); } super.flushCanonical(); } addRecordData(recordData: RelationshipRecordData) { if (this.members.has(recordData)) { return; } // TODO Igor cleanup assertPolymorphicType(this.recordData, this.relationshipMeta, recordData, this.store); if (this.inverseRecordData) { this.removeRecordData(this.inverseRecordData); } this.inverseRecordData = recordData; super.addRecordData(recordData); this.notifyBelongsToChange(); } removeRecordDataFromOwn(recordData: RelationshipRecordData) { if (!this.members.has(recordData)) { return; } this.inverseRecordData = null; super.removeRecordDataFromOwn(recordData); this.notifyBelongsToChange(); } removeAllRecordDatasFromOwn() { super.removeAllRecordDatasFromOwn(); this.inverseRecordData = null; this.notifyBelongsToChange(); } notifyBelongsToChange() { let recordData = this.recordData; let storeWrapper = this.recordData.storeWrapper; storeWrapper.notifyBelongsToChange(recordData.modelName, recordData.id, recordData.clientId, this.key); } removeCanonicalRecordDataFromOwn(recordData: RelationshipRecordData, idx?: number) { if (!this.canonicalMembers.has(recordData)) { return; } this.canonicalState = null; this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(true); super.removeCanonicalRecordDataFromOwn(recordData, idx); } removeAllCanonicalRecordDatasFromOwn() { super.removeAllCanonicalRecordDatasFromOwn(); this.canonicalState = null; } getData(): DefaultSingleResourceRelationship { let data; let payload: any = {}; if (this.inverseRecordData) { data = this.inverseRecordData.getResourceIdentifier(); } if (this.inverseRecordData === null && this.hasAnyRelationshipData) { data = null; } if (this.links) { payload.links = this.links; } if (data !== undefined) { payload.data = data; } if (this.meta) { payload.meta = this.meta; } payload._relationship = this; return payload; } updateData(data: ExistingResourceIdentifierObject, initial: boolean) { let recordData; if (isNone(data)) { recordData = null; } assert( `Ember Data expected the data for the ${ this.key } relationship on a ${this.recordData.toString()} to be in a JSON API format and include an \`id\` and \`type\` property but it found ${inspect( data )}. Please check your serializer and make sure it is serializing the relationship payload into a JSON API format.`, data === null || (data.id !== undefined && data.type !== undefined) ); if (recordData !== null) { recordData = this.recordData.storeWrapper.recordDataFor(data.type, data.id); } if (initial) { this.setInitialCanonicalRecordData(recordData); } else { this.setCanonicalRecordData(recordData); } } }