Skip to content

Commit

Permalink
perf(core): use Set instead of array for cycle lookups
Browse files Browse the repository at this point in the history
Related: #732
  • Loading branch information
B4nan committed Aug 11, 2020
1 parent 12ba811 commit dff0c9d
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 18 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/EntityManager.ts
Expand Up @@ -400,7 +400,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
entity = Utils.isEntity<T>(data) ? data : this.getEntityFactory().create<T>(entityName, data as EntityData<T>);

// add to IM immediately - needed for self-references that can be part of `data` (do not trigger cascade merge)
this.getUnitOfWork().merge(entity, [entity]);
this.getUnitOfWork().merge(entity, new Set([entity]));
EntityAssigner.assign(entity, data as EntityData<T>, { onlyProperties: true, merge: true });
this.getUnitOfWork().merge(entity); // add to IM again so we have correct payload saved for change set computation

Expand Down Expand Up @@ -456,7 +456,7 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
}

const entity = this.getEntityFactory().createReference<T>(entityName, id);
this.getUnitOfWork().merge(entity, [entity], false);
this.getUnitOfWork().merge(entity, new Set([entity]), false);

if (wrapped) {
return Reference.create(entity);
Expand Down
32 changes: 16 additions & 16 deletions packages/core/src/unit-of-work/UnitOfWork.ts
Expand Up @@ -32,7 +32,7 @@ export class UnitOfWork {

constructor(private readonly em: EntityManager) { }

merge<T extends AnyEntity<T>>(entity: T, visited: AnyEntity[] = [], mergeData = true): void {
merge<T extends AnyEntity<T>>(entity: T, visited = new Set<AnyEntity>(), mergeData = true): void {
const wrapped = wrap(entity, true);
wrapped.__em = this.em;

Expand Down Expand Up @@ -121,7 +121,7 @@ export class UnitOfWork {
}
}

persist<T extends AnyEntity<T>>(entity: T, visited: AnyEntity[] = [], checkRemoveStack = false): void {
persist<T extends AnyEntity<T>>(entity: T, visited = new Set<AnyEntity>(), checkRemoveStack = false): void {
if (this.persistStack.has(entity)) {
return;
}
Expand All @@ -139,7 +139,7 @@ export class UnitOfWork {
this.cascade(entity, Cascade.PERSIST, visited, { checkRemoveStack });
}

remove(entity: AnyEntity, visited: AnyEntity[] = []): void {
remove(entity: AnyEntity, visited = new Set<AnyEntity>()): void {
if (this.removeStack.has(entity)) {
return;
}
Expand Down Expand Up @@ -218,7 +218,7 @@ export class UnitOfWork {

Object.values(this.identityMap)
.filter(entity => !this.removeStack.has(entity) && !this.orphanRemoveStack.has(entity))
.forEach(entity => this.persist(entity, [], true));
.forEach(entity => this.persist(entity, undefined, true));

for (const entity of this.persistStack) {
this.findNewEntities(entity);
Expand All @@ -242,12 +242,12 @@ export class UnitOfWork {
this.orphanRemoveStack.delete(entity);
}

private findNewEntities<T extends AnyEntity<T>>(entity: T, visited: AnyEntity[] = []): void {
if (visited.includes(entity)) {
private findNewEntities<T extends AnyEntity<T>>(entity: T, visited = new Set<AnyEntity>()): void {
if (visited.has(entity)) {
return;
}

visited.push(entity);
visited.add(entity);
const wrapped = wrap(entity, true);

if (!wrapped.isInitialized() || this.removeStack.has(entity) || this.orphanRemoveStack.has(entity)) {
Expand Down Expand Up @@ -280,7 +280,7 @@ export class UnitOfWork {
this.identifierMap[wrapped.__uuid] = new EntityIdentifier();
}

private processReference<T extends AnyEntity<T>>(parent: T, prop: EntityProperty<T>, reference: any, visited: AnyEntity[]): void {
private processReference<T extends AnyEntity<T>>(parent: T, prop: EntityProperty<T>, reference: any, visited: Set<AnyEntity>): void {
const isToOne = prop.reference === ReferenceType.MANY_TO_ONE || prop.reference === ReferenceType.ONE_TO_ONE;

if (isToOne && reference) {
Expand All @@ -292,13 +292,13 @@ export class UnitOfWork {
}
}

private processToOneReference<T extends AnyEntity<T>>(reference: any, visited: AnyEntity[]): void {
private processToOneReference<T extends AnyEntity<T>>(reference: any, visited: Set<AnyEntity>): void {
if (!this.originalEntityData[wrap(reference, true).__uuid]) {
this.findNewEntities(reference, visited);
}
}

private processToManyReference<T extends AnyEntity<T>>(reference: Collection<AnyEntity>, visited: AnyEntity[], parent: T, prop: EntityProperty<T>): void {
private processToManyReference<T extends AnyEntity<T>>(reference: Collection<AnyEntity>, visited: Set<AnyEntity>, parent: T, prop: EntityProperty<T>): void {
if (this.isCollectionSelfReferenced(reference, visited)) {
this.extraUpdates.add([parent, prop.name, reference]);
parent[prop.name as keyof T] = new Collection<AnyEntity>(parent) as unknown as T[keyof T];
Expand Down Expand Up @@ -358,12 +358,12 @@ export class UnitOfWork {
this.working = false;
}

private cascade<T extends AnyEntity<T>>(entity: T, type: Cascade, visited: AnyEntity[], options: { checkRemoveStack?: boolean; mergeData?: boolean } = {}): void {
if (visited.includes(entity)) {
private cascade<T extends AnyEntity<T>>(entity: T, type: Cascade, visited: Set<AnyEntity>, options: { checkRemoveStack?: boolean; mergeData?: boolean } = {}): void {
if (visited.has(entity)) {
return;
}

visited.push(entity);
visited.add(entity);

switch (type) {
case Cascade.PERSIST: this.persist(entity, visited, options.checkRemoveStack); break;
Expand All @@ -378,7 +378,7 @@ export class UnitOfWork {
}
}

private cascadeReference<T extends AnyEntity<T>>(entity: T, prop: EntityProperty<T>, type: Cascade, visited: AnyEntity[], options: { checkRemoveStack?: boolean; mergeData?: boolean }): void {
private cascadeReference<T extends AnyEntity<T>>(entity: T, prop: EntityProperty<T>, type: Cascade, visited: Set<AnyEntity>, options: { checkRemoveStack?: boolean; mergeData?: boolean }): void {
this.fixMissingReference(entity, prop);

if (!this.shouldCascade(prop, type)) {
Expand All @@ -402,9 +402,9 @@ export class UnitOfWork {
}
}

private isCollectionSelfReferenced(collection: Collection<AnyEntity>, visited: AnyEntity[]): boolean {
private isCollectionSelfReferenced(collection: Collection<AnyEntity>, visited: Set<AnyEntity>): boolean {
const filtered = collection.getItems(false).filter(item => !this.originalEntityData[wrap(item, true).__uuid]);
return filtered.some(items => visited.includes(items));
return filtered.some(items => visited.has(items));
}

private shouldCascade(prop: EntityProperty, type: Cascade): boolean {
Expand Down

0 comments on commit dff0c9d

Please sign in to comment.