Skip to content

Commit

Permalink
fix(core): reset collections when assigning to those not initialized
Browse files Browse the repository at this point in the history
Previously when one assigned some collection values to not initialized collection, it would
not wipe it when flushing, keeping the old values there.
  • Loading branch information
B4nan committed Aug 9, 2020
1 parent fc1cd3d commit e19a6b4
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 5 deletions.
7 changes: 5 additions & 2 deletions packages/core/src/entity/Collection.ts
Expand Up @@ -8,7 +8,7 @@ import { wrap } from './wrap';

export class Collection<T extends AnyEntity<T>, O extends AnyEntity<O> = AnyEntity> extends ArrayCollection<T, O> {

private snapshot: T[] = []; // used to create a diff of the collection at commit time
private snapshot: T[] | undefined = []; // used to create a diff of the collection at commit time
private initialized = false;
private dirty = false;
private _populated = false;
Expand Down Expand Up @@ -66,10 +66,13 @@ export class Collection<T extends AnyEntity<T>, O extends AnyEntity<O> = AnyEnti
this.validateModification(items);
}

const wasInitialized = this.initialized;
this.initialized = true;
super.hydrate(items);

if (takeSnapshot) {
if (!wasInitialized) {
this.snapshot = undefined;
} else if (takeSnapshot) {
this.takeSnapshot();
}
}
Expand Down
7 changes: 4 additions & 3 deletions packages/knex/src/AbstractSqlDriver.ts
Expand Up @@ -231,15 +231,16 @@ export abstract class AbstractSqlDriver<C extends AbstractSqlConnection = Abstra
const wrapped = wrap(coll.owner, true);
const meta = wrapped.__meta;
const pks = wrapped.__primaryKeys;
const snapshot = coll.getSnapshot().map(item => wrap(item, true).__primaryKeys);
const snap = coll.getSnapshot();
const snapshot = snap ? snap.map(item => wrap(item, true).__primaryKeys) : [];
const current = coll.getItems(false).map(item => wrap(item, true).__primaryKeys);
const deleteDiff = snapshot.filter(item => !current.includes(item));
const deleteDiff = snap ? snapshot.filter(item => !current.includes(item)) : true;
const insertDiff = current.filter(item => !snapshot.includes(item));
const target = snapshot.filter(item => current.includes(item)).concat(...insertDiff);
const equals = Utils.equals(current, target);

// wrong order if we just delete and insert to the end
if (coll.property.fixedOrder && !equals) {
if (coll.property.fixedOrder && !equals && Array.isArray(deleteDiff)) {
deleteDiff.length = insertDiff.length = 0;
deleteDiff.push(...snapshot);
insertDiff.push(...current);
Expand Down
21 changes: 21 additions & 0 deletions tests/EntityHelper.mysql.test.ts
Expand Up @@ -79,6 +79,27 @@ describe('EntityHelperMySql', () => {
expect(book2.tags.getIdentifiers()).toMatchObject([tag2.id]);
});

test('assign() should update not initialized collection [mysql]', async () => {
const other = new BookTag2('other');
await orm.em.persistAndFlush(other);
const jon = new Author2('Jon Snow', 'snow@wall.st');
const book = new Book2('Book2', jon);
const tag1 = new BookTag2('tag 1');
const tag2 = new BookTag2('tag 2');
const tag3 = new BookTag2('tag 3');
book.tags.add(tag1, tag2, tag3);
await orm.em.persistAndFlush(book);
orm.em.clear();

const book1 = await orm.em.findOneOrFail(Book2, book.uuid);
wrap(book1).assign({ tags: [tag1.id, other.id] });
await orm.em.flush();
orm.em.clear();

const book2 = await orm.em.findOneOrFail(Book2, book.uuid, ['tags']);
expect(book2.tags.getIdentifiers()).toMatchObject([tag1.id, other.id]);
});

test('assign() allows deep merging of object properties [mysql]', async () => {
const jon = new Author2('Jon Snow', 'snow@wall.st');
const book = new Book2('Book2', jon);
Expand Down

0 comments on commit e19a6b4

Please sign in to comment.