Skip to content

Commit dbc56e5

Browse files
committed
Make OrmRepository decorator works with no param (custom repository case)
1 parent da1f0d5 commit dbc56e5

File tree

1 file changed

+96
-17
lines changed

1 file changed

+96
-17
lines changed

src/decorators/OrmRepository.ts

Lines changed: 96 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,31 @@ function getRepository(connectionName: string, repositoryType: Function, entityT
2929
}
3030

3131
/**
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!
32+
* Satisfy typescript compiler about universal decorators.
33+
*/
34+
export type ParamOrPropDecorator = (object: object, propertyName: string, index?: number) => void;
35+
36+
/**
37+
* Allows to inject a custom repository using TypeDI's Container.
38+
* Be aware that you have to annotate the param/property with correct type!
39+
* ```ts
40+
* class Sample {
41+
* // constructor injection
42+
* constructor(
43+
* \@OrmRepository()
44+
* private userRepository: UserRepository,
45+
* ) {}
46+
*
47+
* // property injection
48+
* \@OrmRepository()
49+
* userRepository: UserRepository;
50+
* }
51+
* ```
52+
*/
53+
export function OrmRepository(): ParamOrPropDecorator;
54+
/**
55+
* Allows to inject a Repository, MongoRepository, TreeRepository using TypeDI's Container.
56+
* Be aware that you have to annotate the param/property with correct type!
3557
* ```ts
3658
* class Sample {
3759
* // constructor injection
@@ -46,16 +68,66 @@ function getRepository(connectionName: string, repositoryType: Function, entityT
4668
* }
4769
* ```
4870
*/
49-
export function OrmRepository(entityType: Function, connectionName = "default") {
71+
export function OrmRepository(entityType: Function): ParamOrPropDecorator;
72+
/**
73+
* Allows to inject a custom repository using TypeDI's Container
74+
* and specify the connection name in a parameter.
75+
* Be aware that you have to annotate the param/property with correct type!
76+
* ```ts
77+
* class Sample {
78+
* // constructor injection
79+
* constructor(
80+
* \@OrmRepository("test-conn")
81+
* private userRepository: UserRepository,
82+
* ) {}
83+
*
84+
* // property injection
85+
* \@OrmRepository("test-conn")
86+
* userRepository: UserRepository;
87+
* }
88+
* ```
89+
*/
90+
export function OrmRepository(connectionName: string): ParamOrPropDecorator;
91+
/**
92+
* Allows to inject a Repository, MongoRepository, TreeRepository using TypeDI's Container
93+
* and specify the connection name in a parameter.
94+
* Be aware that you have to annotate the param/property with correct type!
95+
* ```ts
96+
* class Sample {
97+
* // constructor injection
98+
* constructor(
99+
* \@OrmRepository(User, "test-conn")
100+
* private userRepository: Repository<User>,
101+
* ) {}
102+
*
103+
* // property injection
104+
* \@OrmRepository(User, "test-conn")
105+
* userRepository: Repository<User>;
106+
* }
107+
* ```
108+
*/
109+
export function OrmRepository(entityType: Function, connectionName: string): ParamOrPropDecorator;
110+
111+
export function OrmRepository(entityTypeOrConnectionName?: Function|string, paramConnectionName = "default"): ParamOrPropDecorator {
50112
return (object: object, propertyName: string, index?: number) => {
113+
let entityType: Function|undefined;
114+
let connectionName: string;
51115
let repositoryType: Function;
52116

117+
// handle first parameter overload
118+
connectionName = paramConnectionName;
119+
if (typeof entityTypeOrConnectionName === "string") {
120+
connectionName = entityTypeOrConnectionName;
121+
} else if (typeof entityTypeOrConnectionName === "function") {
122+
entityType = entityTypeOrConnectionName;
123+
}
124+
53125
// if the decorator has been aplied to parameter (constructor injection)
54126
if (index) {
55127
const paramTypes: Function[] | undefined = Reflect.getOwnMetadata("design:paramtypes", object, propertyName);
56128
if (!paramTypes || !paramTypes[index]) {
57129
throw new Error(
58-
`Cannot get reflected type for a "${propertyName}" method's parameter of ${object.constructor.name} class. ` +
130+
`Cannot get reflected type for a "${propertyName}" method's ${index + 1}. parameter of ${object.constructor.name} class. ` +
59131
`Make sure you have turned on an "emitDecoratorMetadata": true, option in tsconfig.json. ` +
60132
`and that you have imported "reflect-metadata" on top of the main entry file in your application.` +
61133
`And make sure that you have annotated the property type correctly with: ` +
@@ -78,23 +150,30 @@ export function OrmRepository(entityType: Function, connectionName = "default")
78150
}
79151
repositoryType = propertyType;
80152
}
153+
154+
switch (repositoryType) {
155+
case Repository:
156+
case MongoRepository:
157+
case TreeRepository:
158+
if (!entityType) {
159+
throw new Error(
160+
`Missing "entityType" parameter of "@OrmRepository" decorator ` +
161+
index
162+
? `for a "${propertyName}" method's ${index! + 1}. parameter of ${object.constructor.name} class. `
163+
: `for a property "${propertyName}" of ${object.constructor.name} class. `
164+
+
165+
`For injecting Repository, MongoRepository or TreeRepository, ` +
166+
`you have to specify the entity type due to TS reflection limitation` +
167+
`"entityType" parameter can be ommited only for custom repositories.`
168+
);
169+
}
170+
}
81171

82172
Container.registerHandler({
83173
index,
84174
object,
85175
propertyName,
86-
value: () => getRepository(connectionName, repositoryType, entityType),
176+
value: () => getRepository(connectionName, repositoryType, entityType!),
87177
});
88178
};
89179
}
90-
91-
class Test {
92-
93-
constructor(
94-
@OrmRepository(Test)
95-
private repo: MongoRepository<any>,
96-
) {}
97-
98-
@OrmRepository(Test)
99-
property: Repository<any>;
100-
}

0 commit comments

Comments
 (0)