However, I can't find any Repository.extend method in Repository class and there's nothing about it in the documentation. How to solve this?
typeorm version: "^0.3.0"
I'm using nest js and trying to create a custom repository.
However, I can't find any Repository.extend method in Repository class and there's nothing about it in the documentation. How to solve this?
typeorm version: "^0.3.0"
I'm using nest js and trying to create a custom repository.
First of all:
npm install @nestjs/typeorm@next
NOTE
In my project @nestjs/typeorm version is 9.0.0-next.2 and typeorm version is 0.3.6
Create a folder named database in the src of your project then create two files in (typeorm-ex.decorator.ts and typeorm-ex.module.ts)
// typeorm-ex.decorator.ts
import { SetMetadata } from "@nestjs/common";
export const TYPEORM_EX_CUSTOM_REPOSITORY = "TYPEORM_EX_CUSTOM_REPOSITORY";
export function CustomRepository(entity: Function): ClassDecorator {
return SetMetadata(TYPEORM_EX_CUSTOM_REPOSITORY, entity);
}
And next file
// typeorm-ex.module.ts
import { DynamicModule, Provider } from "@nestjs/common";
import { getDataSourceToken } from "@nestjs/typeorm";
import { DataSource } from "typeorm";
import { TYPEORM_EX_CUSTOM_REPOSITORY } from "./typeorm-ex.decorator";
export class TypeOrmExModule {
public static forCustomRepository<T extends new (...args: any[]) => any>(repositories: T[]): DynamicModule {
const providers: Provider[] = [];
for (const repository of repositories) {
const entity = Reflect.getMetadata(TYPEORM_EX_CUSTOM_REPOSITORY, repository);
if (!entity) {
continue;
}
providers.push({
inject: [getDataSourceToken()],
provide: repository,
useFactory: (dataSource: DataSource): typeof repository => {
const baseRepository = dataSource.getRepository<any>(entity);
return new repository(baseRepository.target, baseRepository.manager, baseRepository.queryRunner);
},
});
}
return {
exports: providers,
module: TypeOrmExModule,
providers,
};
}
}
Open your AppModule and modify it like the following:
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mssql',
...
entities: [Photo],
}),
TypeOrmExModule.forCustomRepository([PhotoRepository]),
...
],
controllers: [AppController],
providers: [
AppService
],
})
export class AppModule { }
You can create your customer repository like the following :
@CustomRepository(Photo)
export class PhotoRepository extends Repository<Photo> {
public async getAllPhoto() {
const query = this.createQueryBuilder('photo')
.where('photo.isPublished = :isPublished', { isPublished: true })
const photos = await query.getMany()
return photos
}
}
Everything works perfectly.
Thanks to @anchan828
The way I could solve this error is the following:
First, I created the file datasource.ts, I also declared the datasource, it follows the same structure as the ormconfig.js file:
import { DataSource } from 'typeorm';
require('dotenv').config();
export const AppDataSource = new DataSource({
type: 'mongodb',
url: process.env.MONGO_URI,
useNewUrlParser: true,
synchronize: true,
logging: true,
database: process.env.DB_DATABASE,
entities: ['dist/entities/*.js'],
useUnifiedTopology: true,
});
AppDataSource.initialize()
.then(() => {
console.log('Data Source has been initialized!');
})
.catch((err) => {
console.error('Error during Data Source initialization', err);
});
And, after that, I created a Custom Repository:
import { AppDataSource } from '@CustomDataSource';
import { Product } from '@Entities';
import { CreateProductDto, UpdateProductDto } from '@Products';
const dataSource = AppDataSource;
export const ProductRepository =
dataSource.getMongoRepository(Product).extend({
async findOneById(id: number): Promise<Product> {
const product = await ProductRepository.findOne({ where: { id }});
return product;
},
async findMany(): Promise<Product[]> {
const products = await ProductRepository.find();
return products;
},
});
In this way, you don't have to add the repositories in TypeORMModule.forFeature([]), for each module in which you are working.
Note that now, we don't call this, we call ProductRepository and the method directly.
As refer to the related PR, the migration is work in progress. You can checkout the latest progress by using:
yarn add @nestjs/typeorm@next
You can use custom dynamic module as a workaround, like this gist for now.
But if you want to continue using the Repository class you can roll back to the next version and continue using this feature.
"@nestjs/typeorm": "^8.0.3",
"typeorm": "^0.2.45",
Use NPM
npm i @nestjs/typeorm@^8.0.3 typeorm@^0.2.45
In the new version of TypeORM (0.3.*), I am changing custom repositories to services. Based on connection to multiple official documentation databases. https://docs.nestjs.com/techniques/database#multiple-databases
Custom repository
@EntityRepository(Person)
export class PersonRepository extends Repository<Person> {...}
Custom repository as Service
@Injectable()
export class PersonRepository {
constructor(private dataSource: DataSource) { }
exampleQueryBuilder() {
return this.dataSource
.getRepository(Person)
.createQueryBuilder() ...
}
Repository injection
@Injectable()
export class PersonService {
constructor(
@Inject(PersonRepository)
private readonly personRepository: PersonRepository,
) {}
I created a utility method provideCustomRepository to simplify overriding a repository with nestjs / typeorm 0.3.x
https://gist.github.com/rhutchison/a530d89c37f1978a48dcee4bf2418cb7
import { Provider, Type } from '@nestjs/common';
import { getDataSourceToken, getRepositoryToken } from '@nestjs/typeorm';
import { DataSource, DataSourceOptions, Repository } from 'typeorm';
export function provideCustomRepository<T>(
entity: Type<T>,
repository: Type<Repository<T>>,
dataSource?: DataSource | DataSourceOptions | string
): Provider {
return {
provide: getRepositoryToken(entity),
inject: [getDataSourceToken(dataSource)],
useFactory(dataSource: DataSource) {
const baseRepository = dataSource.getRepository(entity);
return new repository(
baseRepository.target,
baseRepository.manager,
baseRepository.queryRunner
);
},
};
}
<script src="https://gist.github.com/rhutchison/a530d89c37f1978a48dcee4bf2418cb7.js"></script>
In order to extend UserRepository functionality you can use .extend method of Repository class
Example
// user.repository.ts
export const UserRepository = dataSource.getRepository(User).extend({...})