Skip to content

Commit

Permalink
implicit mostly killed off :)
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed May 1, 2021
1 parent b828441 commit 72e8068
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 142 deletions.
20 changes: 0 additions & 20 deletions packages/record-data/addon/-private/graph/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,17 +70,13 @@ export class Graph {
declare _potentialPolymorphicTypes: Dict<Dict<boolean>>;
declare identifiers: Map<StableRecordIdentifier, Dict<RelationshipEdge>>;
declare store: RecordDataStoreWrapper;
declare _queued: { belongsTo: any[]; hasMany: any[] };
declare _nextFlush: boolean;
declare _isUpdating: boolean;

constructor(store: RecordDataStoreWrapper) {
this._definitionCache = Object.create(null);
this._potentialPolymorphicTypes = Object.create(null);
this.identifiers = new Map();
this.store = store;
this._queued = { belongsTo: [], hasMany: [] };
this._nextFlush = false;
this._isUpdating = false;
}

Expand Down Expand Up @@ -282,22 +278,6 @@ export class Graph {
}
}

flush() {
this._nextFlush = false;
const { belongsTo, hasMany } = this._queued;
this._queued = { belongsTo: [], hasMany: [] };
// TODO validate this assumption
// pushing hasMany before belongsTo is a performance win
// as the hasMany's will populate most of the belongsTo's
// and we won't have to do the expensive extra diff.
for (let i = 0; i < hasMany.length; i++) {
this.update(hasMany[i], true);
}
for (let i = 0; i < belongsTo.length; i++) {
this.update(belongsTo[i], true);
}
}

destroy() {
this.identifiers.clear();
Graphs.delete(this.store);
Expand Down
6 changes: 5 additions & 1 deletion packages/record-data/addon/-private/record-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,11 @@ export default class RecordDataDefault implements RelationshipRecordData {
if (relationships) {
Object.keys(relationships).forEach((key) => {
const rel = relationships[key]!;
rel.removeCompletelyFromInverse();
if (!rel.definition.isImplicit) {
rel.removeCompletelyFromInverse();
} else {
rel.removeCompletelyFromInverse();
}
if (isNew === true && !rel.definition.isImplicit) {
rel.clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,4 @@ export default class BelongsToRelationship {
this.state.hasReceivedData = false;
this.state.isEmpty = true;
}

destroy() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -291,8 +291,6 @@ export default class ManyRelationship {
this.state.hasFailedLoadAttempt = value;
}

destroy() {}

addCanonicalRecordData(recordData: StableRecordIdentifier, idx?: number) {
if (this.canonicalMembers.has(recordData)) {
return;
Expand Down
134 changes: 21 additions & 113 deletions packages/record-data/addon/-private/relationships/state/relationship.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { recordDataFor as peekRecordData } from '@ember-data/store/-private';

import OrderedSet from '../../ordered-set';

type ManyRelationship = import('../..').ManyRelationship;

type Graph = import('../../graph').Graph;
type UpgradedMeta = import('../../graph/-edge-definition').UpgradedMeta;
type BelongsToRelationship = import('../..').BelongsToRelationship;
type RecordDataStoreWrapper = import('@ember-data/store/-private').RecordDataStoreWrapper;
type RecordData = import('@ember-data/store/-private/ts-interfaces/record-data').RecordData;
type RelationshipRecordData = import('../../ts-interfaces/relationship-record-data').RelationshipRecordData;
Expand Down Expand Up @@ -35,104 +30,44 @@ export default class Relationship {
declare definition: UpgradedMeta;
declare identifier: StableRecordIdentifier;

declare members: OrderedSet<StableRecordIdentifier>;
declare canonicalMembers: OrderedSet<StableRecordIdentifier>;
declare willSync: boolean;
declare members: Set<StableRecordIdentifier>;
declare canonicalMembers: Set<StableRecordIdentifier>;

constructor(graph: Graph, definition: UpgradedMeta, identifier: StableRecordIdentifier) {
this.graph = graph;
this.store = graph.store;
this.definition = definition;
this.identifier = identifier;

this.members = new OrderedSet<StableRecordIdentifier>();
this.canonicalMembers = new OrderedSet<StableRecordIdentifier>();

this.willSync = false;
}

recordDataDidDematerialize() {
const inverseKey = this.definition.inverseKey;
const callback = (inverseIdentifier) => {
if (!inverseIdentifier || !this.graph.has(inverseIdentifier, inverseKey)) {
return;
}
let relationship = this.graph.get(inverseIdentifier, inverseKey);

// For canonical members, it is possible that inverseRecordData has already been associated to
// to another record. For such cases, do not dematerialize the inverseRecordData
if (
relationship.definition.kind !== 'belongsTo' ||
!(relationship as BelongsToRelationship).localState ||
this.identifier === (relationship as BelongsToRelationship).localState
) {
relationship.inverseDidDematerialize(this.identifier);
}
};

// ensure we don't walk anything twice if an entry is
// in both members and canonicalMembers
let seen = Object.create(null);

for (let i = 0; i < this.members.list.length; i++) {
const inverseIdentifier = this.members.list[i];
if (inverseIdentifier) {
const id = inverseIdentifier.lid;
if (!seen[id]) {
seen[id] = true;
callback(inverseIdentifier);
}
}
}

for (let i = 0; i < this.canonicalMembers.list.length; i++) {
const inverseIdentifier = this.canonicalMembers.list[i];
if (inverseIdentifier) {
const id = inverseIdentifier.lid;
if (!seen[id]) {
seen[id] = true;
callback(inverseIdentifier);
}
}
}

this.canonicalMembers.clear();
this.members.clear();
}

inverseDidDematerialize(inverseRecordData: StableRecordIdentifier) {
this.members.delete(inverseRecordData);
this.canonicalMembers.delete(inverseRecordData);
this.members = new Set<StableRecordIdentifier>();
this.canonicalMembers = new Set<StableRecordIdentifier>();
}

addCanonicalRecordData(recordData: StableRecordIdentifier, idx?: number) {
if (!this.canonicalMembers.has(recordData)) {
this.canonicalMembers.add(recordData);
this.members.add(recordData);
}
this.flushCanonicalLater();
}

removeCanonicalRecordData(recordData: StableRecordIdentifier | null, idx?: number) {
if (this.canonicalMembers.has(recordData)) {
if (recordData && this.canonicalMembers.has(recordData)) {
this.canonicalMembers.delete(recordData);
this.flushCanonicalLater();
if (!isNew(recordData)) {
this.members.delete(recordData);
}
}
}

addRecordData(recordData: StableRecordIdentifier, idx?: number) {
if (!this.members.has(recordData)) {
this.members.addWithIndex(recordData, idx);
this.members.add(recordData);
}
}

removeRecordData(recordData: StableRecordIdentifier | null) {
if (recordData && this.members.has(recordData)) {
this.members.delete(recordData);
if (this.graph.has(recordData, this.definition.inverseKey)) {
(this.graph.get(recordData, this.definition.inverseKey) as
| BelongsToRelationship
| ManyRelationship).removeRecordDataFromOwn(this.identifier);
}
}
}

Expand Down Expand Up @@ -162,51 +97,24 @@ export default class Relationship {
}
};

this.members.toArray().forEach(unload);
this.canonicalMembers.toArray().forEach(unload);
this.members.forEach(unload);
this.canonicalMembers.forEach(unload);
this.members.clear();
this.canonicalMembers.clear();
}

recordDataDidDematerialize() {
this.removeCompletelyFromInverse();
}

/*
Removes the given RecordData from BOTH canonical AND current state.
This method is useful when either a deletion or a rollback on a new record
needs to entirely purge itself from an inverse relationship.
*/
Removes the given RecordData from BOTH canonical AND current state.
This method is useful when either a deletion or a rollback on a new record
needs to entirely purge itself from an inverse relationship.
*/
removeCompletelyFromOwn(recordData: StableRecordIdentifier) {
this.canonicalMembers.delete(recordData);
this.members.delete(recordData);
}

flushCanonical() {
let list = this.members.list as StableRecordIdentifier[];
this.willSync = false;
//a hack for not removing new RecordDatas
//TODO remove once we have proper diffing
let newRecordDatas: StableRecordIdentifier[] = [];
for (let i = 0; i < list.length; i++) {
// TODO Igor deal with this
if (isNew(list[i])) {
newRecordDatas.push(list[i]);
}
}

//TODO(Igor) make this less abysmally slow
this.members = this.canonicalMembers.copy();
for (let i = 0; i < newRecordDatas.length; i++) {
this.members.add(newRecordDatas[i]);
}
}

flushCanonicalLater() {
if (this.willSync) {
return;
}
this.willSync = true;
// Reaching back into the store to use ED's runloop
this.store._store._updateRelationshipState(this);
}

destroy() {}
}
6 changes: 2 additions & 4 deletions packages/store/addon/-private/system/core-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,6 @@ interface CoreStore {
adapter: string;
}

type RelationshipEdge = Relationship | ManyRelationship;

abstract class CoreStore extends Service {
/**
* EmberData specific backburner instance
Expand All @@ -250,7 +248,7 @@ abstract class CoreStore extends Service {
// used for coalescing record save requests
private _pendingSave: PendingSaveItem[] = [];
// used for coalescing relationship updates
private _updatedRelationships: RelationshipEdge[] = [];
private _updatedRelationships: ManyRelationship[] = [];
// used for coalescing internal model updates
private _updatedInternalModels: InternalModel[] = [];

Expand Down Expand Up @@ -3613,7 +3611,7 @@ abstract class CoreStore extends Service {
}
}

_updateRelationshipState(relationship: Relationship | ManyRelationship) {
_updateRelationshipState(relationship: ManyRelationship) {
if (this._updatedRelationships.push(relationship) !== 1) {
return;
}
Expand Down

0 comments on commit 72e8068

Please sign in to comment.