Skip to content

Commit

Permalink
refactor(core): remove autoFlush configuration, deprecate persistLater
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
The `flush` parameter of `persist()` and `remove()` methods is still there, but you
should prefer to call `em.flush()` explicitly.

Also `persistLater()` and `removeLater()` methods are deprecated. Use `persist()` or
`remove` respectively.

Closes #439
  • Loading branch information
B4nan committed Apr 18, 2020
1 parent cad49fe commit 62cfbfe
Show file tree
Hide file tree
Showing 8 changed files with 62 additions and 36 deletions.
2 changes: 1 addition & 1 deletion ROADMAP.md
Expand Up @@ -39,7 +39,7 @@ discuss specifics.
- [x] Require TS 3.7 or newer
- [x] Split into multiple packages (core, driver packages, TS support, SQL support, CLI)
- [ ] Drop default value for db `type` (currently defaults to `mongodb`)
- [ ] Remove `autoFlush` option
- [x] Remove `autoFlush` option
- [ ] Remove `IdEntity/UuidEntity/MongoEntity` interfaces
- [ ] Rename `wrappedReference` to `reference` (keep `wrappedReference` supported)
- [ ] Use `bigint` type natively in `BigIntType`
Expand Down
8 changes: 8 additions & 0 deletions docs/docs/upgrading-v3-to-v4.md
Expand Up @@ -21,3 +21,11 @@ TODO multiple packages
## SqlEntityManager and MongoEntityManager

TODO QB getter, knex getter, aggregate...

## `autoFlush` option has been removed

The `flush` parameter of `persist()` and `remove()` methods is still there, but you
should prefer to call `em.flush()` explicitly.

Also `persistLater()` and `removeLater()` methods are deprecated. Use `persist()` or
`remove` respectively.
42 changes: 26 additions & 16 deletions packages/core/src/EntityManager.ts
Expand Up @@ -374,44 +374,50 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
* Tells the EntityManager to make an instance managed and persistent. You can force flushing via second parameter.
* The entity will be entered into the database at or before transaction commit or as a result of the flush operation.
*/
persist(entity: AnyEntity | AnyEntity[], flush = this.config.get('autoFlush')): void | Promise<void> {
if (flush) {
return this.persistAndFlush(entity);
persist(entity: AnyEntity | AnyEntity[], flush?: false): void;
persist(entity: AnyEntity | AnyEntity[], flush: true): Promise<void>;
persist(entity: AnyEntity | AnyEntity[], flush = false): void | Promise<void> {
const entities = Utils.asArray(entity);

for (const ent of entities) {
this.getUnitOfWork().persist(ent);
}

this.persistLater(entity);
if (flush) {
return this.flush();
}
}

/**
* Persists your entity immediately, flushing all not yet persisted changes to the database too.
* Equivalent to `em.persistLater(e) && em.flush()`.
*/
async persistAndFlush(entity: AnyEntity | AnyEntity[]): Promise<void> {
this.persistLater(entity);
this.persist(entity);
await this.flush();
}

/**
* Tells the EntityManager to make an instance managed and persistent.
* The entity will be entered into the database at or before transaction commit or as a result of the flush operation.
*
* @deprecated use `persist()`
*/
persistLater(entity: AnyEntity | AnyEntity[]): void {
const entities = Utils.asArray(entity);

for (const ent of entities) {
this.getUnitOfWork().persist(ent);
}
this.persist(entity);
}

/**
* Removes an entity instance or all entities matching your `where` query. When deleting entity by instance, you
* will need to flush your changes. You can force flushing via third parameter.
*/
remove<T extends AnyEntity<T>>(entityName: EntityName<T>, where: FilterQuery<T> | T, flush = this.config.get('autoFlush')): void | Promise<number> {
remove<T extends AnyEntity<T>>(entityName: EntityName<T>, where: FilterQuery<T> | T, flush?: false): void;
remove<T extends AnyEntity<T>>(entityName: EntityName<T>, where: FilterQuery<T> | T, flush: true): Promise<number>;
remove<T extends AnyEntity<T>>(entityName: EntityName<T>, where: FilterQuery<T> | T, flush = false): void | Promise<number> {
entityName = Utils.className(entityName);

if (Utils.isEntity(where)) {
const ret = this.removeEntity(where, flush);
const ret = this.removeEntity(where, flush as true);
return ret ? ret.then(() => 1) : ret;
}

Expand All @@ -422,12 +428,14 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
* Removes an entity instance. You can force flushing via second parameter.
* A removed entity will be removed from the database at or before transaction commit or as a result of the flush operation.
*/
removeEntity<T extends AnyEntity<T>>(entity: T, flush = this.config.get('autoFlush')): void | Promise<void> {
removeEntity<T extends AnyEntity<T>>(entity: T, flush?: false): void;
removeEntity<T extends AnyEntity<T>>(entity: T, flush: true): Promise<void>;
removeEntity<T extends AnyEntity<T>>(entity: T, flush = false): void | Promise<void> {
this.getUnitOfWork().remove(entity);

if (flush) {
return this.removeAndFlush(entity);
return this.flush();
}

this.removeLater(entity);
}

/**
Expand All @@ -442,6 +450,8 @@ export class EntityManager<D extends IDatabaseDriver = IDatabaseDriver> {
/**
* Removes an entity instance.
* A removed entity will be removed from the database at or before transaction commit or as a result of the flush operation.
*
* @deprecated use `removeEntity()`
*/
removeLater(entity: AnyEntity): void {
this.getUnitOfWork().remove(entity);
Expand Down
18 changes: 14 additions & 4 deletions packages/core/src/entity/EntityRepository.ts
Expand Up @@ -8,14 +8,19 @@ export class EntityRepository<T extends AnyEntity<T>> {
constructor(protected readonly em: EntityManager,
protected readonly entityName: EntityName<T>) { }

persist(entity: AnyEntity | AnyEntity[], flush = this.em.config.get('autoFlush')): void | Promise<void> {
return this.em.persist(entity, flush);
persist(entity: AnyEntity | AnyEntity[], flush?: false): void;
persist(entity: AnyEntity | AnyEntity[], flush: true): Promise<void>;
persist(entity: AnyEntity | AnyEntity[], flush = false): void | Promise<void> {
return this.em.persist(entity, flush as true);
}

async persistAndFlush(entity: AnyEntity | AnyEntity[]): Promise<void> {
await this.em.persistAndFlush(entity);
}

/**
* @deprecated use `persist()`
*/
persistLater(entity: AnyEntity | AnyEntity[]): void {
this.em.persistLater(entity);
}
Expand Down Expand Up @@ -50,14 +55,19 @@ export class EntityRepository<T extends AnyEntity<T>> {
return this.em.find<T>(this.entityName, {}, populate as string[], orderBy, limit, offset);
}

remove(where: T | FilterQuery<T>, flush = this.em.config.get('autoFlush')): void | Promise<number> {
return this.em.remove(this.entityName, where, flush);
remove(where: T | FilterQuery<T>, flush?: false): void;
remove(where: T | FilterQuery<T>, flush: true): Promise<number>;
remove(where: T | FilterQuery<T>, flush = false): void | Promise<number> {
return this.em.remove(this.entityName, where, flush as true);
}

async removeAndFlush(entity: AnyEntity): Promise<void> {
await this.em.removeAndFlush(entity);
}

/**
* @deprecated use `remove()`
*/
removeLater(entity: AnyEntity): void {
this.em.removeLater(entity);
}
Expand Down
2 changes: 0 additions & 2 deletions packages/core/src/utils/Configuration.ts
Expand Up @@ -26,7 +26,6 @@ export class Configuration<D extends IDatabaseDriver = IDatabaseDriver> {
disableDynamicFileAccess: false,
tsConfigPath: process.cwd() + '/tsconfig.json',
},
autoFlush: false,
strict: false,
// eslint-disable-next-line no-console
logger: console.log.bind(console),
Expand Down Expand Up @@ -306,7 +305,6 @@ export interface MikroORMOptions<D extends IDatabaseDriver = IDatabaseDriver> ex
disableDynamicFileAccess?: boolean;
tsConfigPath?: string;
};
autoFlush: boolean;
type: keyof typeof Configuration.PLATFORMS;
driver?: { new (config: Configuration): D };
driverOptions: Dictionary;
Expand Down
14 changes: 7 additions & 7 deletions tests/EntityManager.mongo.test.ts
Expand Up @@ -39,9 +39,9 @@ describe('EntityManagerMongo', () => {
book3.publisher = publisherRef;

const repo = orm.em.getRepository(Book);
repo.persistLater(book1);
repo.persistLater(book2);
repo.persistLater(book3);
repo.persist(book1);
repo.persist(book2);
repo.persist(book3);
await repo.flush();
orm.em.clear();

Expand Down Expand Up @@ -296,8 +296,8 @@ describe('EntityManagerMongo', () => {
const author2 = new Author('name2', 'email2');
const author3 = new Author('name3', 'email3');
const repo = orm.em.getRepository(Author) as AuthorRepository;
repo.persistLater(author);
repo.persistLater(author2);
repo.persist(author);
repo.persist(author2);
await repo.removeAndFlush(author);
expect(Object.keys(orm.em.getUnitOfWork().getIdentityMap())).toEqual([`Author-${author2.id}`]);
author2.name = 'lol';
Expand Down Expand Up @@ -1346,7 +1346,7 @@ describe('EntityManagerMongo', () => {
const b1 = new Book('b1', author);
const b2 = new Book('b2', author);
const b3 = new Book('b3', author);
orm.em.persistLater([b1, b2, b3]);
orm.em.persist([b1, b2, b3]);
await orm.em.flush();
orm.em.clear();

Expand Down Expand Up @@ -1618,7 +1618,7 @@ describe('EntityManagerMongo', () => {
Object.assign(book, { tags: ['0000007b5c9c61c332380f78', tag] });
expect(book.tags).not.toBeInstanceOf(Collection);
expect(book.tags).toEqual(['0000007b5c9c61c332380f78', tag]);
expect(() => orm.em.persistLater(book)).toThrowError(`Entity of type BookTag expected for property Book.tags, '0000007b5c9c61c332380f78' of type string given. If you are using Object.assign(entity, data), use wrap(entity).assign(data, { em }) instead.`);
expect(() => orm.em.persist(book)).toThrowError(`Entity of type BookTag expected for property Book.tags, '0000007b5c9c61c332380f78' of type string given. If you are using Object.assign(entity, data), use wrap(entity).assign(data, { em }) instead.`);

wrap(book).assign({ tags: ['0000007b5c9c61c332380f78', tag] }, { em: orm.em });
expect(book.tags).toBeInstanceOf(Collection);
Expand Down
6 changes: 3 additions & 3 deletions tests/EntityRepository.test.ts
Expand Up @@ -25,7 +25,7 @@ const methods = {
nativeUpdate: jest.fn(),
nativeDelete: jest.fn(),
aggregate: jest.fn(),
config: new Configuration({ autoFlush: true } as any, false),
config: new Configuration({} as any, false),
};
const Mock = jest.fn<EntityManager, any>(() => methods as any);
const em = new Mock();
Expand All @@ -41,7 +41,7 @@ describe('EntityRepository', () => {
repo.getReference('bar');
expect(methods.getReference.mock.calls[0]).toEqual([Publisher, 'bar', false]);
const e = Object.create(Publisher.prototype);
await repo.persist(e, false);
await repo.persist(e);
expect(methods.persist.mock.calls[0]).toEqual([e, false]);
await repo.persistAndFlush(e);
expect(methods.persistAndFlush.mock.calls[0]).toEqual([e]);
Expand All @@ -57,7 +57,7 @@ describe('EntityRepository', () => {
expect(methods.findOneOrFail.mock.calls[0]).toEqual([Publisher, 'bar', [], undefined]);
await repo.createQueryBuilder();
expect(methods.createQueryBuilder.mock.calls[0]).toEqual([Publisher, undefined]);
await repo.remove('bar');
await repo.remove('bar', true);
expect(methods.remove.mock.calls[0]).toEqual([Publisher, 'bar', true]);
const entity = {} as AnyEntity;
await repo.removeAndFlush(entity);
Expand Down
6 changes: 3 additions & 3 deletions tests/issues/GH486.test.ts
@@ -1,13 +1,13 @@
import { Entity, PrimaryKey, Property, OneToMany, MikroORM, ReflectMetadataProvider, Collection, ManyToOne } from '../../lib';
import { PostgreSqlDriver } from '../../lib/drivers/PostgreSqlDriver';
import { Entity, PrimaryKey, Property, OneToMany, MikroORM, ReflectMetadataProvider, Collection, ManyToOne } from '@mikro-orm/core';
import { PostgreSqlDriver } from '@mikro-orm/postgresql';

@Entity()
class A {

@PrimaryKey()
id!: number;

@OneToMany(() => B, b => b.a)
@OneToMany('B', 'a')
bs = new Collection<B>(this);

@Property()
Expand Down

0 comments on commit 62cfbfe

Please sign in to comment.