Skip to content

Commit

Permalink
feat(core): keep collection state of dirty collections after initiali…
Browse files Browse the repository at this point in the history
…zing

Previously when collection was dirty and we load its contents, the dirty state
would be lost. Now we restore the dirty state after we load the items.

Closes #2408
  • Loading branch information
B4nan committed Nov 13, 2021
1 parent eddd4a1 commit 49ed651
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 1 deletion.
12 changes: 12 additions & 0 deletions packages/core/src/entity/Collection.ts
Expand Up @@ -217,6 +217,18 @@ export class Collection<T, O = unknown> extends ArrayCollection<T, O> {
}

async init<P extends string = never>(options: InitOptions<T, P> = {}): Promise<this> {
if (this.dirty) {
const items = [...this.items];
this.dirty = false;
await this.init(options);

if (items.length) {
items.forEach(i => this.add(i));
}

return this;
}

const em = this.getEntityManager();

if (!this.initialized && this.property.reference === ReferenceType.MANY_TO_MANY && em.getPlatform().usesPivotTable()) {
Expand Down
29 changes: 28 additions & 1 deletion tests/EntityManager.postgre.test.ts
Expand Up @@ -7,7 +7,7 @@ import {
} from '@mikro-orm/core';
import { PostgreSqlDriver, PostgreSqlConnection } from '@mikro-orm/postgresql';
import { Address2, Author2, Book2, BookTag2, FooBar2, FooBaz2, Publisher2, PublisherType, PublisherType2, Test2, Label2 } from './entities-sql';
import { initORMPostgreSql, wipeDatabasePostgreSql } from './bootstrap';
import { initORMPostgreSql, mockLogger, wipeDatabasePostgreSql } from './bootstrap';
import { performance } from 'perf_hooks';

describe('EntityManagerPostgre', () => {
Expand Down Expand Up @@ -1096,6 +1096,33 @@ describe('EntityManagerPostgre', () => {
expect(wrap(tags[0].books.getItems()[0]).isInitialized()).toBe(true);
});

test('populating dirty collections will merge the items and keep it dirty', async () => {
await createBooksWithTags();

const a = await orm.em.findOneOrFail(Author2, { email: 'snow@wall.st' });
expect(a.books.isDirty()).toBe(false);
a.books.add(new Book2('new book', a, 123));
expect(a.books.isDirty()).toBe(true);

const mock = mockLogger(orm, ['query']);
const books = await a.books.loadItems();
expect(a.books.isDirty()).toBe(true);
await orm.em.flush();
expect(a.books.isDirty()).toBe(false);
expect(books).toHaveLength(4);
expect(books.map(b => b.title)).toEqual([
'My Life on The Wall, part 1',
'My Life on The Wall, part 2',
'My Life on The Wall, part 3',
'new book',
]);

expect(mock.mock.calls[0][0]).toMatch(`select "e0"."uuid_pk", "e0"."created_at", "e0"."title", "e0"."price", "e0"."double", "e0"."meta", "e0"."author_id", "e0"."publisher_id", "e0".price * 1.19 as "price_taxed" from "book2" as "e0" where "e0"."author_id" is not null and "e0"."author_id" = $1 order by "e0"."title" asc`);
expect(mock.mock.calls[1][0]).toMatch(`begin`);
expect(mock.mock.calls[2][0]).toMatch(`insert into "book2" ("author_id", "created_at", "price", "title", "uuid_pk") values ($1, $2, $3, $4, $5) returning "uuid_pk", "created_at", "title"`);
expect(mock.mock.calls[3][0]).toMatch(`commit`);
});

test('nested populating', async () => {
const author = new Author2('Jon Snow', 'snow@wall.st');
const book1 = new Book2('My Life on The Wall, part 1', author);
Expand Down

0 comments on commit 49ed651

Please sign in to comment.