Skip to content

Commit da1f0d5

Browse files
committed
Make @OrmRepository generic and infer the repository type
1 parent 511c7a6 commit da1f0d5

File tree

5 files changed

+94
-79
lines changed

5 files changed

+94
-79
lines changed

src/decorators/OrmCustomRepository.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/decorators/OrmRepository.ts

Lines changed: 94 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,100 @@
1-
import {ConnectionManager} from "typeorm";
2-
import {Container} from "typedi";
1+
import { ConnectionManager, Repository, TreeRepository, MongoRepository } from "typeorm";
2+
import { Container } from "typedi";
33

44
/**
5-
* Allows to inject a Repository using typedi's Container.
6-
* If you want to inject custom Repository class decorated with @EntityRepository decorator, use OrmCustomRepository instead.
5+
* Helper to avoid V8 compilation of anonymous function on each call of decorator.
76
*/
8-
export function OrmRepository(cls: Function, connectionName: string = "default"): Function {
9-
return function(object: Object|Function, propertyName: string, index?: number) {
10-
Container.registerHandler({ object, index, propertyName, value: () => {
11-
const connectionManager = Container.get(ConnectionManager);
12-
if (!connectionManager.has(connectionName))
13-
throw new Error(`Cannot get connection "${connectionName}" from the connection manager. ` +
14-
`Make sure you have created such connection. Also make sure you have called useContainer(Container) ` +
15-
`in your application before you established a connection and importing any entity.`);
7+
function getRepository(connectionName: string, repositoryType: Function, entityType: Function) {
8+
const connectionManager = Container.get(ConnectionManager);
9+
if (!connectionManager.has(connectionName)) {
10+
throw new Error(
11+
`Cannot get connection "${connectionName}" from the connection manager. ` +
12+
`Make sure you have created such connection. Also make sure you have called useContainer(Container) ` +
13+
`in your application before you established a connection and importing any entity.`
14+
);
15+
}
16+
const connection = connectionManager.get(connectionName);
1617

17-
const connection = connectionManager.get(connectionName);
18-
return connection.getRepository(cls as any);
19-
}});
18+
switch (repositoryType) {
19+
case Repository:
20+
return connection.getRepository(entityType);
21+
case MongoRepository:
22+
return connection.getMongoRepository(entityType);
23+
case TreeRepository:
24+
return connection.getTreeRepository(entityType);
25+
// if not the TypeORM's ones, there must be custom repository classes
26+
default:
27+
return connection.getCustomRepository(repositoryType);
28+
}
29+
}
30+
31+
/**
32+
* Allows to inject a Repository, MongoRepository, TreeRepository
33+
* or custom repository using TypeDI's Container.
34+
* Be aware that you have to annotate the property with correct type!
35+
* ```ts
36+
* class Sample {
37+
* // constructor injection
38+
* constructor(
39+
* \@OrmRepository(User)
40+
* private userRepository: Repository<User>,
41+
* ) {}
42+
*
43+
* // property injection
44+
* \@OrmRepository(User)
45+
* userRepository: Repository<User>;
46+
* }
47+
* ```
48+
*/
49+
export function OrmRepository(entityType: Function, connectionName = "default") {
50+
return (object: object, propertyName: string, index?: number) => {
51+
let repositoryType: Function;
52+
53+
// if the decorator has been aplied to parameter (constructor injection)
54+
if (index) {
55+
const paramTypes: Function[] | undefined = Reflect.getOwnMetadata("design:paramtypes", object, propertyName);
56+
if (!paramTypes || !paramTypes[index]) {
57+
throw new Error(
58+
`Cannot get reflected type for a "${propertyName}" method's parameter of ${object.constructor.name} class. ` +
59+
`Make sure you have turned on an "emitDecoratorMetadata": true, option in tsconfig.json. ` +
60+
`and that you have imported "reflect-metadata" on top of the main entry file in your application.` +
61+
`And make sure that you have annotated the property type correctly with: ` +
62+
`Repository, MongoRepository, TreeRepository or custom repository class type.`
63+
);
64+
}
65+
repositoryType = paramTypes[index];
66+
}
67+
// if the parameter has been aplied to class property
68+
else {
69+
const propertyType: Function | undefined = Reflect.getOwnMetadata("design:type", object, propertyName);
70+
if (!propertyType) {
71+
throw new Error(
72+
`Cannot get reflected type for a property "${propertyName}" of ${object.constructor.name} class. ` +
73+
`Make sure you have turned on an "emitDecoratorMetadata": true, option in tsconfig.json ` +
74+
`and that you have imported "reflect-metadata" on top of the main entry file in your application.` +
75+
`And make sure that you have annotated the property type correctly with: ` +
76+
`Repository, MongoRepository, TreeRepository or custom repository class type.`
77+
);
78+
}
79+
repositoryType = propertyType;
80+
}
81+
82+
Container.registerHandler({
83+
index,
84+
object,
85+
propertyName,
86+
value: () => getRepository(connectionName, repositoryType, entityType),
87+
});
2088
};
89+
}
90+
91+
class Test {
92+
93+
constructor(
94+
@OrmRepository(Test)
95+
private repo: MongoRepository<any>,
96+
) {}
97+
98+
@OrmRepository(Test)
99+
property: Repository<any>;
21100
}

src/decorators/OrmSpecificRepository.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/decorators/OrmTreeRepository.ts

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
export * from "./decorators/OrmConnection";
22
export * from "./decorators/OrmEntityManager";
33
export * from "./decorators/OrmRepository";
4-
export * from "./decorators/OrmCustomRepository";
5-
export * from "./decorators/OrmSpecificRepository";
6-
export * from "./decorators/OrmTreeRepository";

0 commit comments

Comments
 (0)