I am trying to implement database i18n for TypeORM. I have been able to do that theoratically. But I also want to override built-in repository methods to use i18n (basically intercepting them and adding a query). How can I override createQueryBuilder in TypeORM repository? I can override methods like findMany, findOne and add new methods. But it is not working for createQueryBuilder. I know I can override all select methods in the repository. But I want to do it in one place and tried to override createQueryBuilder. The code shows my custom repository definitions.
export function TranslatableRepository<T>() {
return {
createQueryBuilder<Entity>(
alias?: string,
queryRunner?: QueryRunner
): SelectQueryBuilder<Entity> {
throw new Error();
let qb = this.manager.createQueryBuilder<Entity>(
this.metadata.target as any,
alias || this.metadata.targetName,
queryRunner || this.queryRunner
);
qb = qb.leftJoinAndSelect(
`${alias || this.metadata.targetName}.translations`,
'translation',
'translation.locale = :locale',
{
locale: this.getLocale()
}
);
return qb;
},
getLocale() {
return getLocaleFromContext();
}
} as ThisType<Repository<T> & TTranslatableRepository<T>> &
TTranslatableRepository<T>;
}
And I use it like postRepository.extend(TranslatableRepository<Post>()). The createQueryBuilder method above should throw the error. But it is using built-in method. This is the copy of extend method in TypeORM souce code.
extend(custom) {
// return {
// ...this,
// ...custom
// };
const thisRepo = this.constructor;
const { target, manager, queryRunner } = this;
const cls = new (class extends thisRepo {})(target, manager, queryRunner);
Object.assign(cls, custom);
return cls;
}
How can I override createQueryBuilder or is there any other ways to intercept queries?
Finally got it! I need to override the createQueryBuilder method in entity manager instead of in the repository.
Edited:
Warning, the following code will override the entityManager so if we don't want to mutate the default entityManager from appDataSource.manager, we need to provide a new entityManager, presumably from appDataSource.createEntityManager().
export function TranslatableRepository(manager: EntityManager) {
manager.createQueryBuilder = function createQueryBuilder<Entity>(
entityClass?: EntityTarget<Entity> | QueryRunner,
alias?: string,
queryRunner?: QueryRunner
): SelectQueryBuilder<Entity> {
let qb: SelectQueryBuilder<Entity>;
if (alias) {
qb = this.connection.createQueryBuilder(
entityClass as EntityTarget<Entity>,
alias,
queryRunner || this.queryRunner
);
} else {
qb = this.connection.createQueryBuilder(
(entityClass as QueryRunner | undefined) ||
queryRunner ||
this.queryRunner
);
}
return qb.leftJoinAndSelect(
`${alias}.translations`,
'translation',
'translation.locale = :locale',
{
locale: getLocaleFromContext()
}
);
};
return {};
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With