nestjs-typeorm-transactions
Version:
A NestJS module to make transaction management easier across different services
249 lines • 9.83 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TransactionalRepository = void 0;
const datasource_storage_1 = require("./common/datasource-storage");
const async_local_storage_1 = require("./common/async-local-storage");
class TransactionalRepository {
constructor(dataSource, EntityClass, connection = datasource_storage_1.DEFAULT_DATASOURCE_NAME) {
this.dataSource = dataSource;
this.EntityClass = EntityClass;
this.connection = connection;
}
/** Execute a raw query */
static async executeRawQuery(options) {
let manager;
const connection = options.connection ?? datasource_storage_1.DEFAULT_DATASOURCE_NAME;
if (async_local_storage_1.asyncLocalStorage.getStore() && async_local_storage_1.asyncLocalStorage.getStore()[connection]) {
manager = async_local_storage_1.asyncLocalStorage.getStore()[connection];
}
else {
manager = datasource_storage_1.DataSourceStorage.getDataSource(connection).manager;
}
return await manager.query(options.query, options.parameters);
}
/** Retrieve the transactional entity manager optionally specifying a connection name. If no connection name is specified, the default connection's entity manager is returned */
static getEntityManager(connection = datasource_storage_1.DEFAULT_DATASOURCE_NAME) {
let manager;
if (async_local_storage_1.asyncLocalStorage.getStore() && async_local_storage_1.asyncLocalStorage.getStore()[connection]) {
manager = async_local_storage_1.asyncLocalStorage.getStore()[connection];
}
else {
manager = datasource_storage_1.DataSourceStorage.getDataSource(connection).manager;
}
return manager;
}
/** Get native typeorm repository */
getTypeOrmRepository() {
let manager;
if (async_local_storage_1.asyncLocalStorage.getStore() && async_local_storage_1.asyncLocalStorage.getStore()[this.connection]) {
manager = async_local_storage_1.asyncLocalStorage.getStore()[this.connection];
}
else {
manager = this.dataSource.manager;
}
return manager.getRepository(this.EntityClass);
}
/** Create query builder */
createQueryBuilder(alias, queryRunner) {
return this.getTypeOrmRepository().createQueryBuilder(alias, queryRunner);
}
/** Return multiple records */
async find(options) {
return await this.getTypeOrmRepository()
.createQueryBuilder()
.setFindOptions(options ?? {})
.getMany();
}
/** Return multiple records */
async findBy(where) {
return await this.find({
where,
});
}
/** Return multiple records with pagination */
async findWithPagination(limit, page, options) {
const data = await this.getTypeOrmRepository()
.createQueryBuilder()
.setFindOptions(options ?? {})
.skip((page - 1) * limit)
.take(limit)
.getMany();
const count = await this.getTypeOrmRepository()
.createQueryBuilder()
.setFindOptions(options ?? {})
.getCount();
return {
count,
pageCount: Math.ceil(count / limit),
currentPage: page,
limit,
data,
};
}
/** Find one record */
async findOne(options) {
return await this.getTypeOrmRepository()
.createQueryBuilder()
.setFindOptions(options)
.getOne();
}
/** Find one record */
async findOneBy(where) {
return await this.findOne({
where,
});
}
/** Preload an entity using typeorm preload method */
async preload(entity) {
return await this.getTypeOrmRepository().preload(entity);
}
async insert(entity) {
if (entity instanceof Array) {
await this.getTypeOrmRepository().insert(entity);
return entity;
}
else {
await this.getTypeOrmRepository().insert(entity);
return entity;
}
}
create(entity) {
if (entity instanceof Array) {
return this.getTypeOrmRepository().create(entity);
}
else {
return this.getTypeOrmRepository().create(entity);
}
}
async save(entity, saveOptions) {
if (!saveOptions) {
saveOptions = { transaction: false };
}
else {
saveOptions.transaction = false;
}
if (entity instanceof Array) {
return await this.getTypeOrmRepository().save(entity, saveOptions);
}
else {
return await this.getTypeOrmRepository().save(entity, saveOptions);
}
}
/** Updates given entity/entities */
async update(id, entity) {
await this.getTypeOrmRepository().update(id, entity);
}
/** Upserts record(s) */
async upsert(entity, conflictPaths) {
await this.getTypeOrmRepository().upsert(entity, conflictPaths);
}
/** Deletes record(s) */
async delete(id) {
await this.getTypeOrmRepository().delete(id);
}
/** Disassociate all child entities in many to many relationships */
async disassociateAll(entityId, relation) {
const relations = this.getTypeOrmRepository().metadata.relations;
let found = false;
let columnName = '';
for (let r of relations) {
if (r.propertyName === relation.toString()) {
if (!r.isManyToMany || !r.junctionEntityMetadata) {
throw new Error('Not a many to many relationship or no junction metadata found');
}
r.junctionEntityMetadata.columns.forEach((column) => {
if (column.referencedColumn.target === this.EntityClass) {
columnName = column.databaseName;
}
});
if (!columnName) {
throw new Error('No column found in junction table for the given entity');
}
await this.getTypeOrmRepository()
.createQueryBuilder()
.delete()
.from(r.joinTableName)
.where(`${columnName} = :id`, {
id: entityId,
})
.execute();
found = true;
}
}
if (!found) {
throw new Error(`Relation ${relation.toString()} not found in ${this.EntityClass instanceof Function
? this.EntityClass.name
: this.EntityClass.options.name}`);
}
}
/** Disassociate child entities by ids in many to many relationships */
async disassociate(entityId, relatedEntityId, relation) {
const relations = this.getTypeOrmRepository().metadata.relations;
let found = false;
for (let r of relations)
if (r.propertyName === relation.toString()) {
if (!r.isManyToMany) {
throw new Error('Not a many to many relationship');
}
await this.getTypeOrmRepository()
.createQueryBuilder()
.relation(this.EntityClass, relation.toString())
.of(entityId)
.remove(relatedEntityId);
found = true;
}
if (!found) {
throw new Error(`Relation ${relation.toString()} not found in ${this.EntityClass instanceof Function
? this.EntityClass.name
: this.EntityClass.options.name}`);
}
}
/** Associate child entities by ids in many to many relationships */
async associate(entityId, relatedEntityId, relation) {
const relations = this.getTypeOrmRepository().metadata.relations;
let found = false;
for (let r of relations)
if (r.propertyName === relation.toString()) {
if (!r.isManyToMany) {
throw new Error('Not a many to many relationship');
}
await this.getTypeOrmRepository()
.createQueryBuilder()
.relation(this.EntityClass, relation.toString())
.of(entityId)
.add(relatedEntityId);
found = true;
}
if (!found) {
throw new Error(`Relation ${relation.toString()} not found in ${this.EntityClass instanceof Function
? this.EntityClass.name
: this.EntityClass.options.name}`);
}
}
/** Count entities */
async count(options) {
return await this.getTypeOrmRepository().count(options);
}
/** Get the average of a culumn */
async average(columnName, where) {
return await this.getTypeOrmRepository().average(columnName, where);
}
/** Get the sum of a column */
async sum(columnName, where) {
return await this.getTypeOrmRepository().sum(columnName, where);
}
/** Get the max value of a column */
async max(columnName, where) {
return await this.getTypeOrmRepository().maximum(columnName, where);
}
/** Get the min value of a column */
async min(columnName, where) {
return await this.getTypeOrmRepository().minimum(columnName, where);
}
/** Merge multiple entity like objects into a single entity */
merge(mergeIntoEntity, ...entityLikes) {
return this.getTypeOrmRepository().merge(mergeIntoEntity, ...entityLikes);
}
}
exports.TransactionalRepository = TransactionalRepository;
//# sourceMappingURL=transactional.repository.js.map