I have Typeorm Generic repository like this
import { Injectable } from '@nestjs/common'
import { IGenericRepository } from '../abstracts/generic-repository'
import { Repository } from 'typeorm'
@Injectable()
export class GenericRepository<T> implements IGenericRepository<T> {
private _repository: Repository<T>;
constructor(repository: Repository<T>) {
this._repository = repository;
}
getAll(): Promise<T[]> {
return this._repository.find()
}
findById(id: any): Promise<T> {
return this._repository.findOneBy(id)
}
create(item: T): Promise<T> {
return this._repository.save(item)
}
update(id: string, item: T) {
return this._repository
}
}
and I wanna to use this repository as provider in other services . for example I want to use this in user Module
import { Module } from '@nestjs/common';
import { User } from '../entity/user.entity';
import { GenericRepositoryModule, GenericRepository } from '@app/common';
import { Repository } from 'typeorm'
@Module({
imports: [
GenericRepositoryModule
],
providers: [ // I think something is wrong here
{
provide: 'userGenericRepository',
useFactory: (genericRepository: GenericRepository<User>, user: User) => new genericRepository(Repository(user)),
inject: [GenericRepository,User]
}
],
})
export class UserModule { }
But this doesn't work , there is an error
I think something is wrong with this provider
so, How can I fix this ?
The issue is that you are providing GenericRepository
to their own provider.
A way to solve this is:
export function createRepositoryToken(entity: any): string {
return `${entity}__generic_repository_token`;
}
export function createGenericRepositoryProvider(entity: any): Provider {
return {
provide: createRepositoryToken(entity),
useFactory: (manager: EntityManager) => {
return new GenericRepository(new Repository(entity, manager));
},
inject: [EntityManager],
};
}
export const InjectRepo = (entity: any) =>
Inject(createRepositoryToken(entity));
@Module({
imports: [],
providers: [
createGenericRepositoryProvider(User);
]
})
export class UserModule {}
A cleaner option is to write the module like this:
// user.providers.ts
export UserRepositoryProvider = createGenericRepositoryProvider(User);
and use it in your module
@Module({
imports: [],
providers: [
UserRepositoryProvider;
]
})
export class UserModule {}
@Injectable()
export class UserService {
constructor(@InjectRepo(User) private readonly repository: GenericRepository<User>)
}
and is done.
Update (bonus):
You can also create a module to provide generic repositories easily.
export type GenericRepositoryModuleOptions = {
entities: any[];
};
@Module({})
export class GenericRepositoryModule {
static forFeature(options: GenericRepositoryModuleOptions): DynamicModule {
const repositoryTokens = this.createRepositoryTokens(options);
const repositoryProviders = this.createRepositoryProviders(options);
return {
module: GenericRepositoryModule,
providers: repositoryProviders,
exports: repositoryTokens,
};
}
private static createRepositoryTokens(options: GenericRepositoryModuleOptions) {
return options.entities.map(entity => createRepositoryToken(entity));
}
private static createRepositoryProviders(
options: GenericRepositoryModuleOptions
): Provider[] {
return options.entities.map((entity) =>
createGenericRepositoryProvider(entity)
);
}
}