From 5b2dfaabb4573d10fd8e2c8a71858ae6a2d0276c Mon Sep 17 00:00:00 2001 From: pieter-v Date: Thu, 2 Jul 2020 18:43:26 +0200 Subject: [PATCH] Optimize the update of a has-many relationship. (#7090) --- .../record-data/addon/-private/ordered-set.ts | 22 ++++++++++++ .../relationships/state/belongs-to.ts | 4 +-- .../-private/relationships/state/has-many.ts | 35 +++---------------- .../relationships/state/relationship.ts | 4 +-- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/packages/record-data/addon/-private/ordered-set.ts b/packages/record-data/addon/-private/ordered-set.ts index 3f7a9ba6fe8..56072d305e1 100644 --- a/packages/record-data/addon/-private/ordered-set.ts +++ b/packages/record-data/addon/-private/ordered-set.ts @@ -1,3 +1,4 @@ +import { assert } from '@ember/debug'; import { guidFor } from '@ember/object/internals'; import EmberOrderedSet from '@ember/ordered-set'; @@ -27,4 +28,25 @@ export default class EmberDataOrderedSet extends EmberOrderedSet { return this; } + + deleteWithIndex(obj: T | null, idx?: number): boolean { + let guid = guidFor(obj); + let presenceSet = this.presenceSet; + let list = this.list; + + if (presenceSet[guid] === true) { + delete presenceSet[guid]; + + assert('object is not present at specified index', idx === undefined || list[idx] === obj); + + let index = idx !== undefined ? idx : list.indexOf(obj); + if (index > -1) { + list.splice(index, 1); + } + this.size = list.length; + return true; + } else { + return false; + } + } } diff --git a/packages/record-data/addon/-private/relationships/state/belongs-to.ts b/packages/record-data/addon/-private/relationships/state/belongs-to.ts index 000d85ad145..aea9b66352f 100644 --- a/packages/record-data/addon/-private/relationships/state/belongs-to.ts +++ b/packages/record-data/addon/-private/relationships/state/belongs-to.ts @@ -154,14 +154,14 @@ export default class BelongsToRelationship extends Relationship { storeWrapper.notifyBelongsToChange(recordData.modelName, recordData.id, recordData.clientId, this.key); } - removeCanonicalRecordDataFromOwn(recordData: RelationshipRecordData) { + removeCanonicalRecordDataFromOwn(recordData: RelationshipRecordData, idx?: number) { if (!this.canonicalMembers.has(recordData)) { return; } this.canonicalState = null; this.setHasAnyRelationshipData(true); this.setRelationshipIsEmpty(true); - super.removeCanonicalRecordDataFromOwn(recordData); + super.removeCanonicalRecordDataFromOwn(recordData, idx); } removeAllCanonicalRecordDatasFromOwn() { diff --git a/packages/record-data/addon/-private/relationships/state/has-many.ts b/packages/record-data/addon/-private/relationships/state/has-many.ts index adec113c1a0..62d4c0c5422 100755 --- a/packages/record-data/addon/-private/relationships/state/has-many.ts +++ b/packages/record-data/addon/-private/relationships/state/has-many.ts @@ -3,7 +3,6 @@ import { isNone } from '@ember/utils'; import { CUSTOM_MODEL_CLASS } from '@ember-data/canary-features'; import { assertPolymorphicType } from '@ember-data/store/-debug'; -import OrderedSet from '../../ordered-set'; import Relationship from './relationship'; type RelationshipSchema = import('@ember-data/store/-private/ts-interfaces/record-data-schemas').RelationshipSchema; @@ -156,24 +155,12 @@ export default class ManyRelationship extends Relationship { } computeChanges(recordDatas: RelationshipRecordData[] = []) { - let members = this.canonicalMembers; - let recordDatasToRemove: RelationshipRecordData[] = []; - let recordDatasSet = setForArray(recordDatas); - - members.forEach(member => { - if (recordDatasSet.has(member)) { - return; - } - - recordDatasToRemove.push(member); - }); - - this.removeCanonicalRecordDatas(recordDatasToRemove); - + const members = this.canonicalMembers.toArray(); + for (let i = members.length - 1; i >= 0; i--) { + this.removeCanonicalRecordData(members[i], i); + } for (let i = 0, l = recordDatas.length; i < l; i++) { - let recordData = recordDatas[i]; - this.removeCanonicalRecordData(recordData); - this.addCanonicalRecordData(recordData, i); + this.addCanonicalRecordData(recordDatas[i], i); } } @@ -255,15 +242,3 @@ export default class ManyRelationship extends Relationship { } } } - -function setForArray(array) { - var set = new OrderedSet(); - - if (array) { - for (var i = 0, l = array.length; i < l; i++) { - set.add(array[i]); - } - } - - return set; -} diff --git a/packages/record-data/addon/-private/relationships/state/relationship.ts b/packages/record-data/addon/-private/relationships/state/relationship.ts index 809d8ae687d..fcd7bad2887 100644 --- a/packages/record-data/addon/-private/relationships/state/relationship.ts +++ b/packages/record-data/addon/-private/relationships/state/relationship.ts @@ -392,7 +392,7 @@ export default class Relationship { removeCanonicalRecordData(recordData: RelationshipRecordData, idx?: number) { if (this.canonicalMembers.has(recordData)) { - this.removeCanonicalRecordDataFromOwn(recordData); + this.removeCanonicalRecordDataFromOwn(recordData, idx); if (this.inverseKey) { this.removeCanonicalRecordDataFromInverse(recordData); } else { @@ -478,7 +478,7 @@ export default class Relationship { } removeCanonicalRecordDataFromOwn(recordData: RelationshipRecordData | null, idx?: number) { - this.canonicalMembers.delete(recordData); + this.canonicalMembers.deleteWithIndex(recordData, idx); this.flushCanonicalLater(); }