Skip to content

Commit

Permalink
Merge 3793c43 into 5c18fda
Browse files Browse the repository at this point in the history
  • Loading branch information
B4nan committed Jun 11, 2019
2 parents 5c18fda + 3793c43 commit 2273803
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 12 deletions.
2 changes: 1 addition & 1 deletion lib/drivers/IDatabaseDriver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EntityData, EntityMetadata, EntityProperty, IEntity, IEntityType, IPrimaryKey } from '../decorators';
import { Connection, QueryResult } from '../connections';
import { QueryOrder } from '../query';
import { QueryOrderMap } from '../query';
import { Platform } from '../platforms';
import { LockMode } from '../unit-of-work';

Expand Down
6 changes: 3 additions & 3 deletions lib/entity/ArrayCollection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EntityProperty, IEntity, IEntityType, IPrimaryKey } from '../decorators';
import { EntityProperty, IEntityType, IPrimaryKey } from '../decorators';
import { MetadataStorage } from '../metadata';

export class ArrayCollection<T extends IEntityType<T>> {
Expand Down Expand Up @@ -76,9 +76,9 @@ export class ArrayCollection<T extends IEntityType<T>> {
contains(item: T): boolean {
return !!this.items.find(i => {
const objectIdentity = i === item;
const primaryKeyIdentity = i.__primaryKey && item.__primaryKey && i.__serializedPrimaryKey === item.__serializedPrimaryKey;
const primaryKeyIdentity = !!i.__primaryKey && !!item.__primaryKey && i.__serializedPrimaryKey === item.__serializedPrimaryKey;

return !!(objectIdentity || primaryKeyIdentity);
return objectIdentity || primaryKeyIdentity;
});
}

Expand Down
4 changes: 2 additions & 2 deletions lib/entity/Collection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FilterQuery, QueryOrder, QueryOrderMap } from '..';
import { FilterQuery, QueryOrder, QueryOrderMap, Utils } from '..';
import { IEntityType } from '../decorators';
import { ArrayCollection } from './ArrayCollection';
import { ReferenceType } from './enums';
Expand Down Expand Up @@ -32,7 +32,7 @@ export class Collection<T extends IEntityType<T>> extends ArrayCollection<T> {
this.initialized = true;
}

super.set(items);
super.set(items.map(item => Utils.isEntity(item) ? item : this.owner.__em.getReference(this.property.type, item)));
this.dirty = !initialize;

for (const item of items) {
Expand Down
30 changes: 24 additions & 6 deletions lib/unit-of-work/UnitOfWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export class UnitOfWork {
}

for (const prop of Object.values(meta.properties)) {
const reference = entity[prop.name as keyof T];
const reference = entity[prop.name];
this.processReference(entity, prop, reference, visited);
}

Expand Down Expand Up @@ -211,7 +211,7 @@ export class UnitOfWork {
private processToOneReference<T extends IEntityType<T>>(parent: T, prop: EntityProperty<T>, reference: any, visited: IEntity[]): void {
if (!this.hasIdentifier(reference) && visited.includes(reference)) {
this.extraUpdates.push([parent, prop.name as keyof IEntity, reference]);
delete parent[prop.name as keyof T];
delete parent[prop.name];
}

if (!this.originalEntityData[reference.__uuid]) {
Expand Down Expand Up @@ -308,16 +308,18 @@ export class UnitOfWork {
}
}

private cascadeReference<T extends IEntityType<T>>(entity: T, prop: EntityProperty, type: Cascade, visited: IEntity[]): void {
private cascadeReference<T extends IEntityType<T>>(entity: T, prop: EntityProperty<T>, type: Cascade, visited: IEntity[]): void {
this.fixMissingReference(entity, prop);

if (!this.shouldCascade(prop, type)) {
return;
}

if ((prop.reference === ReferenceType.MANY_TO_ONE || prop.reference === ReferenceType.ONE_TO_ONE) && entity[prop.name as keyof T]) {
return this.cascade(entity[prop.name as keyof T], type, visited);
if ((prop.reference === ReferenceType.MANY_TO_ONE || prop.reference === ReferenceType.ONE_TO_ONE) && entity[prop.name]) {
return this.cascade(entity[prop.name], type, visited);
}

const collection = entity[prop.name as keyof T] as Collection<IEntity>;
const collection = entity[prop.name] as Collection<IEntity>;
const requireFullyInitialized = type === Cascade.PERSIST; // only cascade persist needs fully initialized items

if ([ReferenceType.ONE_TO_MANY, ReferenceType.MANY_TO_MANY].includes(prop.reference) && collection.isInitialized(requireFullyInitialized)) {
Expand Down Expand Up @@ -365,5 +367,21 @@ export class UnitOfWork {
}
}

private fixMissingReference<T extends IEntityType<T>>(entity: T, prop: EntityProperty<T>): void {
const reference = entity[prop.name] as IEntity | Collection<IEntity> | IPrimaryKey | (IEntity | IPrimaryKey)[];

if ([ReferenceType.MANY_TO_ONE, ReferenceType.ONE_TO_ONE].includes(prop.reference) && reference && !Utils.isEntity(reference)) {
entity[prop.name] = this.em.getReference(prop.type, reference as IPrimaryKey);
}

const isCollection = [ReferenceType.ONE_TO_MANY, ReferenceType.MANY_TO_MANY].includes(prop.reference);

if (isCollection && Array.isArray(reference)) {
const items = reference.map(item => Utils.isEntity(item) ? item : this.em.getReference(prop.type, item));
entity[prop.name] = new Collection<IEntity>(entity, items) as T[keyof T];
(entity[prop.name] as Collection<IEntity>).setDirty();
}
}

}

49 changes: 49 additions & 0 deletions tests/EntityManager.mongo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,55 @@ describe('EntityManagerMongo', () => {
expect(a.born).toBeUndefined();
});

test('automatically fix PK instead of entity when flushing (m:1)', async () => {
const author = new Author('Jon Snow', 'snow@wall.st');
Object.assign(author, { favouriteBook: '0000007b5c9c61c332380f78' });
expect(author.favouriteBook).not.toBeInstanceOf(Book);
expect(author.favouriteBook).toBe('0000007b5c9c61c332380f78');
await orm.em.persist(author);
expect(author.favouriteBook).toBeInstanceOf(Book);
expect(author.favouriteBook.id).toBe('0000007b5c9c61c332380f78');
});

test('automatically fix array of PKs instead of collection when flushing (m:n)', async () => {
const mock = jest.fn();
const logger = new Logger(mock, true);
Object.assign(orm.em.getConnection(), { logger });

const author = new Author('Jon Snow', 'snow@wall.st');
const book = new Book('B123', author);
await orm.em.persistAndFlush(book);

const tag = orm.em.getReference(BookTag, '0000007b5c9c61c332380f79')
Object.assign(book, { tags: ['0000007b5c9c61c332380f78', tag] });
expect(book.tags).not.toBeInstanceOf(Collection);
expect(book.tags).toEqual(['0000007b5c9c61c332380f78', tag]);
await orm.em.persistLater(book);
expect(book.tags).toBeInstanceOf(Collection);
expect(book.tags[0]).toBeInstanceOf(BookTag);
expect(book.tags[1]).toBeInstanceOf(BookTag);
expect(book.tags[0].id).toBe('0000007b5c9c61c332380f78');
expect(book.tags[1].id).toBe('0000007b5c9c61c332380f79');
expect(book.tags.isInitialized()).toBe(true);
expect(book.tags.isDirty()).toBe(true);

await orm.em.flush();
expect(mock.mock.calls[0][0]).toMatch(/db\.getCollection\("author"\)\.insertOne\({"createdAt":".*","updatedAt":".*","termsAccepted":false,"name":"Jon Snow","email":"snow@wall\.st","foo":"bar","_id":".*"}\);/);
expect(mock.mock.calls[1][0]).toMatch(/db\.getCollection\("books-table"\)\.insertOne\({"title":"B123","author":".*","_id":".*"}\);/);
expect(mock.mock.calls[2][0]).toMatch(/db\.getCollection\("books-table"\)\.updateMany\({"_id":".*"}, {"\$set":{"tags":\["0000007b5c9c61c332380f78","0000007b5c9c61c332380f79"]}}\);/);
});

test('automatically fix PK in collection instead of entity when flushing (m:n)', async () => {
const author = new Author('Jon Snow', 'snow@wall.st');
const book = new Book('B123', author);
book.tags.set(['0000007b5c9c61c332380f78' as any]);
expect(book.tags).not.toBeInstanceOf(BookTag);
expect(book.tags[0]).toBeInstanceOf(BookTag);
expect(book.tags[0].id).toBe('0000007b5c9c61c332380f78');
expect(book.tags.isInitialized()).toBe(true);
expect(book.tags.isDirty()).toBe(true);
});

afterAll(async () => orm.close(true));

});

0 comments on commit 2273803

Please sign in to comment.