Skip to content

Commit

Permalink
feat(mikro-orm): rename all occurrences of connection
Browse files Browse the repository at this point in the history
closes #1741
  • Loading branch information
derevnjuk committed Jan 30, 2022
1 parent d15f95b commit 74365ac
Show file tree
Hide file tree
Showing 17 changed files with 182 additions and 94 deletions.
8 changes: 4 additions & 4 deletions docs/tutorials/mikroorm.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ meta:

Currently, `@tsed/mikro-orm` allows you:

- Configure one or more MikroORM connections via the `@Configuration` decorator. All databases will be initialized when
- Configure one or more MikroORM instances via the `@Configuration` decorator. All databases will be initialized when
the server starts during the server's `OnInit` phase.
- Use the Entity MikroORM as Model for Controllers, AJV Validation and Swagger.

Expand Down Expand Up @@ -110,7 +110,7 @@ export class UsersService {
}
```

It's also possible to inject an ORM by a connection name:
It's also possible to inject an ORM by its context name:

```ts
import {Injectable} from "@tsed/di";
Expand Down Expand Up @@ -145,7 +145,7 @@ export class UsersService {
}
```

It's also possible to inject Entity manager by his connection name:
It's also possible to inject Entity manager by his context name:

```typescript
import {Injectable, AfterRoutesInit} from "@tsed/common";
Expand All @@ -154,7 +154,7 @@ import {EntityManager} from '@mikro-orm/mysql'; // Import EntityManager from you

@Injectable()
export class UsersService {
@Em("connectionName")
@Em("contextName")
private readonly em!: EntityManager;

async create(user: User): Promise<User> {
Expand Down
8 changes: 4 additions & 4 deletions packages/orm/mikro-orm/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ module.exports = {
...require("@tsed/jest-config")(__dirname, "mikro-orm"),
coverageThreshold: {
global: {
branches: 90.91,
functions: 96.97,
lines: 99.06,
statements: 98.54
branches: 90.38,
functions: 91.43,
lines: 96.52,
statements: 97.1
}
}
};
8 changes: 4 additions & 4 deletions packages/orm/mikro-orm/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ A package of Ts.ED framework. See website: https://tsed.io/tutorials/mikro-orm

Currently, `@tsed/mikro-orm` allows you:

- Configure one or more MikroOrm connections via the `@Configuration` decorator. All databases will be initialized
- Configure one or more MikroOrm instances via the `@Configuration` decorator. All databases will be initialized
when the server starts during the server's `OnInit` phase.
- Use the Entity MikroOrm as Model for Controllers, AJV Validation and Swagger.

Expand Down Expand Up @@ -129,7 +129,7 @@ export class UsersService {
}
```

It's also possible to inject an ORM by a connection name:
It's also possible to inject an ORM by its context name:

```ts
import {Injectable} from "@tsed/di";
Expand Down Expand Up @@ -164,7 +164,7 @@ export class UsersService {
}
```

It's also possible to inject Entity manager by his connection name:
It's also possible to inject Entity manager by his context name:

```typescript
import {Injectable, AfterRoutesInit} from "@tsed/common";
Expand All @@ -173,7 +173,7 @@ import {EntityManager} from '@mikro-orm/mysql'; // Import EntityManager from you

@Injectable()
export class UsersService {
@Em("connectionName")
@Em("contextName")
private readonly em!: EntityManager;

async create(user: User): Promise<User> {
Expand Down
8 changes: 4 additions & 4 deletions packages/orm/mikro-orm/src/MikroOrmModule.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,26 +34,26 @@ describe("MikroOrmModule", () => {
it("should create the corresponding connections", async () => {
// arrange
const mikroOrmModule = PlatformTest.get<MikroOrmModule>(MikroOrmModule);
when(mockMikroOrmRegistry.createConnection(config)).thenResolve(({} as unknown) as MikroORM);
when(mockMikroOrmRegistry.create(config)).thenResolve(({} as unknown) as MikroORM);

// act
await mikroOrmModule.$onInit();

verify(mockMikroOrmRegistry.createConnection(deepEqual(config))).called();
verify(mockMikroOrmRegistry.create(deepEqual(config))).called();
});
});

describe("$onDestroy", () => {
it("should destroy the corresponding connections", async () => {
// arrange
const mikroOrmModule = PlatformTest.get<MikroOrmModule>(MikroOrmModule);
when(mockMikroOrmRegistry.closeConnections()).thenResolve();
when(mockMikroOrmRegistry.clear()).thenResolve();

// act
await mikroOrmModule.$onDestroy();

// assert
verify(mockMikroOrmRegistry.closeConnections()).called();
verify(mockMikroOrmRegistry.clear()).called();
});
});
});
4 changes: 2 additions & 2 deletions packages/orm/mikro-orm/src/MikroOrmModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ export class MikroOrmModule implements OnDestroy, OnInit {
private readonly mikroOrmRegistry!: MikroOrmRegistry;

public async $onInit(): Promise<void> {
const promises = this.settings.map((opts) => this.mikroOrmRegistry.createConnection(opts));
const promises = this.settings.map((opts) => this.mikroOrmRegistry.create(opts));

await Promise.all(promises);
}

public $onDestroy(): Promise<void> {
return this.mikroOrmRegistry.closeConnections();
return this.mikroOrmRegistry.clear();
}
}

Expand Down
22 changes: 22 additions & 0 deletions packages/orm/mikro-orm/src/decorators/entityManager.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {DecoratorTypes, Store} from "@tsed/core";
import {Controller, INJECTABLE_PROP} from "@tsed/di";
import {EntityManager} from "@tsed/mikro-orm";
import {MongoEntityManager} from "@mikro-orm/mongodb";

@Controller("/users")
export class UsersCtrl {
@EntityManager()
public readonly em!: MongoEntityManager;
}

describe("@Orm", () => {
it("should decorate property", () => {
expect(Store.from(UsersCtrl).get(INJECTABLE_PROP)).toEqual({
em: {
propertyKey: "em",
bindingType: DecoratorTypes.PROP,
resolver: expect.any(Function)
}
});
});
});
12 changes: 6 additions & 6 deletions packages/orm/mikro-orm/src/decorators/entityManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import {Inject} from "@tsed/di";
import {MikroOrmRegistry} from "../services";

/**
* Get the entity manager for the given connection name.
* @param connectionName
* Get the entity manager for the given context name.
* @param {String} contextName
* @decorator
* @mikroOrm
*/
export const EntityManager = (connectionName?: string): PropertyDecorator =>
Inject(MikroOrmRegistry, (registry: MikroOrmRegistry) => registry.get(connectionName)?.em) as PropertyDecorator;
export const EntityManager = (contextName?: string): PropertyDecorator =>
Inject(MikroOrmRegistry, (registry: MikroOrmRegistry) => registry.get(contextName)?.em) as PropertyDecorator;

/**
* Get the entity manager for the given connection name.
* @param connectionName
* Get the entity manager for the given context name.
* @param {String} connectionName
* @decorator
* @mikroOrm
*/
Expand Down
22 changes: 22 additions & 0 deletions packages/orm/mikro-orm/src/decorators/orm.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {DecoratorTypes, Store} from "@tsed/core";
import {Controller, INJECTABLE_PROP} from "@tsed/di";
import {Orm} from "@tsed/mikro-orm";
import {MikroORM} from "@mikro-orm/core";

@Controller("/users")
export class UsersCtrl {
@Orm()
public readonly orm!: MikroORM;
}

describe("@Orm", () => {
it("should decorate property", () => {
expect(Store.from(UsersCtrl).get(INJECTABLE_PROP)).toEqual({
orm: {
propertyKey: "orm",
bindingType: DecoratorTypes.PROP,
resolver: expect.any(Function)
}
});
});
});
12 changes: 9 additions & 3 deletions packages/orm/mikro-orm/src/decorators/orm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import {MikroOrmRegistry} from "../services";
import {Inject} from "@tsed/di";

/**
* @deprecated Since 2022-02-01. Use {@link Orm} instead
* Get the ORM for the given context name.
* @param {String} contextName
*/
export const Connection = (contextName?: string): PropertyDecorator => Orm(contextName);

export const Orm = (contextName?: string): PropertyDecorator =>
Inject(MikroOrmRegistry, (registry: MikroOrmRegistry) => registry.get(contextName)) as PropertyDecorator;

/**
* Get the ORM for the given context name.
* @param {String} contextName
* @deprecated Since 2022-02-01. Use {@link Orm} instead
*/
export const Connection = Orm;
8 changes: 6 additions & 2 deletions packages/orm/mikro-orm/src/decorators/transactional.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import {TransactionalInterceptor, TransactionOptions} from "../interceptors";
import {Intercept} from "@tsed/di";

export const Transactional = (connectionOrOptions?: string | TransactionOptions): MethodDecorator =>
Intercept(TransactionalInterceptor, connectionOrOptions);
/**
* Register a new request context for your method and execute it inside the context.
* @param {String | TransactionOptions} contextNameOrOptions
*/
export const Transactional = (contextNameOrOptions?: string | TransactionOptions): MethodDecorator =>
Intercept(TransactionalInterceptor, contextNameOrOptions);
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ describe("TransactionalInterceptor", () => {

const spiedDbContext = spy(dbContext);

when(spiedDbContext.getContext()).thenReturn(existingCtx);
when(spiedDbContext.entries()).thenReturn(existingCtx);

// act
await transactionalInterceptor.intercept(context, next);
Expand All @@ -124,7 +124,7 @@ describe("TransactionalInterceptor", () => {
verify(entityManagerMock.flush()).never();
});

it("should run under existing context using different connection", async () => {
it("should run under existing context using different context", async () => {
// arrange
const transactionalInterceptor = new TransactionalInterceptor(instance(mikroOrmRegistryMock), dbContext, instance(loggerMock));
const existingCtx = new Map([["default", instance(entityManagerMock)]]);
Expand All @@ -134,7 +134,7 @@ describe("TransactionalInterceptor", () => {

const spiedDbContext = spy(dbContext);

when(spiedDbContext.getContext()).thenReturn(existingCtx);
when(spiedDbContext.entries()).thenReturn(existingCtx);
when(mikroOrmRegistryMock.get("mydb")).thenReturn(instance(mikroOrm));
when(entityManagerMock.name).thenReturn("mydb");

Expand Down
30 changes: 17 additions & 13 deletions packages/orm/mikro-orm/src/interceptors/TransactionalInterceptor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import {EntityManager} from "@mikro-orm/core";
import {Logger} from "@tsed/logger";

export interface TransactionOptions {
connectionName?: string;
retry?: boolean;
contextName?: string;
/**
* @deprecated Since 2022-02-01. Use {@link contextName} instead
*/
connectionName?: string;
}

@Interceptor()
Expand All @@ -25,13 +29,13 @@ export class TransactionalInterceptor implements InterceptorMethods {
this.logger.warn(`To retry a transaction you have to implement a "${RetryStrategy.description}" interface`);
}

const ctx = this.context.getContext();
const ctx = this.context.entries();

if (!ctx) {
return this.runWithinNewCtx(next, options);
}

if (ctx.has(options.connectionName!)) {
if (ctx.has(options.contextName!)) {
return next();
}

Expand All @@ -45,42 +49,42 @@ export class TransactionalInterceptor implements InterceptorMethods {
}

private runUnderCtx(next: InterceptorNext, ctx: Map<string, EntityManager>, options: TransactionOptions): Promise<unknown> | unknown {
const orm = this.registry.get(options.connectionName);
const orm = this.registry.get(options.contextName);
const em = orm.em.fork(true, true);

ctx.set(em.name, em);

const runInTransaction = () => this.executeInTransaction(options.connectionName!, next);
const runInTransaction = () => this.executeInTransaction(options.contextName!, next);

return this.context.run(ctx, () => (options.retry ? this.retryStrategy?.acquire(runInTransaction) : runInTransaction()));
}

private extractContextName(context: InterceptorContext<unknown>): TransactionOptions {
const options = context.options || ({} as Partial<TransactionOptions> | string);

let connectionName: string | undefined;
let contextName: string | undefined;
let retry: boolean | undefined;

if (typeof options === "string") {
connectionName = options;
contextName = options;
} else if (options) {
connectionName = options.connectionName;
contextName = options.contextName ?? options.connectionName;
retry = options.retry;
}

if (!connectionName) {
connectionName = "default";
if (!contextName) {
contextName = "default";
}

if (!retry) {
retry = false;
}

return {connectionName, retry};
return {contextName, retry};
}

private async executeInTransaction(connectionName: string, next: InterceptorNext): Promise<unknown> {
const em = this.context.get(connectionName);
private async executeInTransaction(contextName: string, next: InterceptorNext): Promise<unknown> {
const em = this.context.get(contextName);

const result = await next();

Expand Down
4 changes: 2 additions & 2 deletions packages/orm/mikro-orm/src/services/DBContent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ describe("DBContext", () => {
const dbCtx = new DBContext();

// act
const result = dbCtx.getContext();
const result = dbCtx.entries();

// assert
expect(result).toBeUndefined();
Expand All @@ -100,7 +100,7 @@ describe("DBContext", () => {
const dbCtx = new DBContext();
const store = new Map<string, EntityManager>();
const callback = jest.fn().mockImplementation(() => {
const result = dbCtx.getContext();
const result = dbCtx.entries();

// assert
expect(result).toEqual(store);
Expand Down
13 changes: 10 additions & 3 deletions packages/orm/mikro-orm/src/services/DBContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,25 @@ export class DBContext {
return this.storage.run(ctx, callback);
}

public getContext(): Map<string, EntityManager> | undefined {
public entries(): Map<string, EntityManager> | undefined {
return this.storage.getStore();
}

/**
* @deprecated Since 2022-02-01. Use {@link entries} instead
*/
public getContext(): Map<string, EntityManager> | undefined {
return this.entries();
}

public get(contextName: string): EntityManager | undefined {
const context = this.getContext();
const context = this.entries();

return context?.get(contextName);
}

public has(contextName: string): boolean {
const context = this.getContext();
const context = this.entries();

return !!context?.has(contextName);
}
Expand Down
Loading

0 comments on commit 74365ac

Please sign in to comment.