feat(SPG-123) Abstraction Transaction Data

master
ashar 2024-05-30 09:32:39 +07:00
parent 38e420856e
commit 11cd564433
13 changed files with 415 additions and 0 deletions

View File

@ -0,0 +1,6 @@
import { STATUS } from "src/core/strings/constants/base.constants";
import { BaseEntity } from "./base.entity";
export interface BaseStatusEntity extends BaseEntity {
status: STATUS;
}

View File

@ -0,0 +1,10 @@
import { BaseCoreEntity } from "./base-core.entity";
export interface BaseEntity extends BaseCoreEntity {
creator_id: string;
creator_name: string;
editor_id: string;
editor_name: string;
created_at: number;
updated_at: number;
}

View File

@ -0,0 +1,52 @@
import { Inject, Injectable, Logger } from "@nestjs/common";
import { UserProvider, UsersSession } from "src/core/sessions";
import { BLANK_USER } from "src/core/strings/constants/base.constants";
import { TABLE_NAME } from "src/core/strings/constants/table.constants";
@Injectable()
export abstract class BaseReadManager {
public user: UsersSession;
public dataService: any;
public queryBuilder: any;
protected tableName: TABLE_NAME;
@Inject()
protected userProvider: UserProvider;
private readonly baseLog = new Logger(BaseReadManager.name);
setUser() {
try {
this.user = this.userProvider?.user;
} catch (error) {
this.user = BLANK_USER;
}
}
setService(dataService) {
this.dataService = dataService;
this.queryBuilder = this.dataService.getRepository().createQueryBuilder(this.tableName);
}
async execute(): Promise<void> {
this.baseLog.log(`prepareData`, BaseReadManager.name);
await this.prepareData();
this.baseLog.log(`beforeProcess`, BaseReadManager.name);
await this.beforeProcess();
this.baseLog.log('process', BaseReadManager.name);
await this.process();
this.baseLog.log('afterProcess', BaseReadManager.name);
await this.afterProcess();
}
abstract prepareData(): Promise<void>;
abstract beforeProcess(): Promise<void>;
abstract process(): Promise<void>;
abstract afterProcess(): Promise<void>;
}

View File

@ -0,0 +1,85 @@
import { BadRequestException, Inject, Injectable, Logger } from "@nestjs/common";
import { EventBus } from "@nestjs/cqrs";
import { UserProvider, UsersSession } from "src/core/sessions";
import { BLANK_USER } from "src/core/strings/constants/base.constants";
import { EventTopics } from "src/core/strings/constants/interface.constants";
import { QueryRunner } from "typeorm";
@Injectable()
export abstract class BaseManager {
public user: UsersSession;
public queryRunner: QueryRunner;
public dataService: any;
protected data: any;
@Inject()
protected userProvider: UserProvider;
@Inject()
protected eventBus: EventBus;
private readonly baseLog = new Logger(BaseManager.name);
setUser() {
try {
this.user = this.userProvider?.user;
} catch (error) {
this.user = BLANK_USER;
}
}
setService(dataService) {
this.dataService = dataService;
this.queryRunner = this.dataService.getRepository().manager.connection.createQueryRunner();
}
abstract get eventTopics(): EventTopics[];
async execute(): Promise<void> {
try {
this.setUser();
this.queryRunner.startTransaction();
this.baseLog.verbose('prepareData');
await this.prepareData();
if (!this.data || !this.dataService) {
throw new Error("data or service not implemented.");
}
this.baseLog.verbose('validateProcess');
await this.validateProcess();
this.baseLog.verbose('beforeProcess');
await this.beforeProcess();
this.baseLog.verbose('process');
await this.process();
this.baseLog.verbose('afterProcess');
await this.afterProcess();
this.baseLog.verbose('commitTransaction');
await this.queryRunner.commitTransaction();
this.publishEvents();
await this.queryRunner.release();
} catch (e) {
if (e.response) throw new Error(JSON.stringify(e.response));
else throw new Error(e.message);
}
}
abstract prepareData(): Promise<void>;
abstract validateProcess(): Promise<void>;
abstract beforeProcess(): Promise<void>;
abstract process(): Promise<void>;
abstract afterProcess(): Promise<void>;
async publishEvents() {
if (!this.eventTopics.length) return
};
}

View File

@ -0,0 +1,40 @@
import { BaseManager } from "../base.manager";
import { Injectable } from "@nestjs/common";
@Injectable()
export abstract class BaseCreateManager<Entity> extends BaseManager {
protected result: Entity;
protected duplicateColumn: string[];
abstract get entityTarget(): any;
setData(entity: Entity): void {
this.data = entity;
}
async prepareData(): Promise<void> {
Object.assign(this.data, {
creator_id: this.user.id,
creator_name: this.user.name,
created_at: new Date().getTime(),
updated_at: new Date().getTime(),
});
}
async process(): Promise<void> {
this.result = await this.dataService.create(
this.queryRunner,
this.entityTarget,
this.data,
);
}
async getResult(): Promise<Entity> {
return await this.dataService.getOneByOptions({
where: {
id: this.result['id']
}
})
}
}

View File

@ -0,0 +1,41 @@
import { HttpStatus, Injectable, UnauthorizedException, UnprocessableEntityException } from "@nestjs/common";
import { BaseManager } from "../base.manager";
@Injectable()
export abstract class BaseDeleteManager<Entity> extends BaseManager {
protected dataId: string;
protected result: Entity;
abstract get entityTarget(): any;
setData(id: string): void {
this.dataId = id;
}
async prepareData(): Promise<void> {
this.data = await this.dataService.getOneByOptions({
where: {
id: this.dataId
}
})
if (!this.data)
throw new UnprocessableEntityException({
statusCode: HttpStatus.UNPROCESSABLE_ENTITY,
message: `Data with id ${this.dataId} not found`,
error: 'Unprocessable Entity',
});
return;
}
async process(): Promise<void> {
await this.dataService.deleteById(
this.queryRunner,
this.entityTarget,
this.dataId,
);
}
abstract getResult(): string;
}

View File

@ -0,0 +1,24 @@
import { BaseReadManager } from "../base-read.manager";
export abstract class BaseDetailManager<Entity> extends BaseReadManager {
protected dataId: string;
protected result: Entity;
abstract get selectData(): string[];
abstract get relationData(): string[];
abstract get setFindProperties(): any;
setData(dataId: string): void {
this.dataId = dataId;
}
async process(): Promise<void> {
this.queryBuilder.select(this.selectData).where(this.setFindProperties);
this.result = await this.queryBuilder.getOne();
}
getResult(): Entity {
return this.result;
}
}

View File

@ -0,0 +1,54 @@
import { PaginationResponse } from "src/core/response/domain/ok-response.interface";
import { BaseReadManager } from "../base-read.manager";
import { SelectQueryBuilder } from "typeorm";
import { BaseFilterEntity } from "../../entities/base-filter.entity";
import { Param, SpecificSearchFilter } from "src/core/helpers/query/specific-search.helper";
export abstract class BaseIndexManager<Entity> extends BaseReadManager {
protected result: PaginationResponse<Entity>;
public filterParam: BaseFilterEntity;
abstract get specificFilter(): Param[];
setFilterParam(param: BaseFilterEntity): void {
this.filterParam = param;
}
async process(): Promise<void> {
// const filterSearch: string[] = this.setFilterSearch();
// this.queryBuilder.andWhere(
// new Brackets((qb) => {
// filterSearch.map((fSearch) => {
// qb.orWhere(`${fSearch} ILIKE :query`, {
// query: `%${
// this.filterParam.q.trim().replace(/\s+/g, ' ') ?? ''
// }%`,
// });
// });
// }),
// );
new SpecificSearchFilter<Entity>(this.queryBuilder, this.tableName, this.specificFilter).getFilter();
this.setQueryFilter(this.queryBuilder);
this.result = await this.dataService.getIndex(
this.queryBuilder,
this.filterParam,
);
}
setFilterSearch(): string[] {
return [];
}
abstract setQueryFilter(
queryBuilder: SelectQueryBuilder<Entity>,
): SelectQueryBuilder<Entity>;
getResult(): PaginationResponse<Entity> {
return this.result;
}
}

View File

@ -0,0 +1,42 @@
import { Injectable } from "@nestjs/common";
import { BaseManager } from "../base.manager";
import { STATUS } from "src/core/strings/constants/base.constants";
import { UserPrivilegeModel } from "src/modules/user-related/user-privilege/data/model/user-privilege.model";
@Injectable()
export abstract class BaseUpdateStatusManager<Entity> extends BaseManager {
protected dataId: string;
protected result: Entity;
protected dataStatus: STATUS;
protected duplicateColumn: string[];
abstract get entityTarget(): any;
setData(id: string, status: STATUS): void {
this.dataId = id;
this.dataStatus = status;
}
async prepareData(): Promise<void> {
this.data = new UserPrivilegeModel();
Object.assign(this.data, {
editor_id: this.user.id,
editor_name: this.user.name,
updated_at: new Date().getTime(),
id: this.dataId,
status: this.dataStatus,
});
}
async process(): Promise<void> {
this.result = await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.dataId },
this.data,
);
}
abstract getResult(): string;
}

View File

@ -0,0 +1,41 @@
import { Injectable } from "@nestjs/common";
import { BaseManager } from "../base.manager";
@Injectable()
export abstract class BaseUpdateManager<Entity> extends BaseManager {
protected dataId: string;
protected result: Entity;
protected duplicateColumn: string[];
abstract get entityTarget(): any;
setData(id: string, entity: Entity): void {
this.dataId = id;
this.data = entity;
}
async prepareData(): Promise<void> {
Object.assign(this.data, {
editor_id: this.user.id,
editor_name: this.user.name,
updated_at: new Date().getTime(),
});
}
async process(): Promise<void> {
this.result = await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.dataId },
this.data,
);
}
async getResult(): Promise<Entity> {
return await this.dataService.getOneByOptions({
where: {
id: this.dataId
}
})
}
}

View File

@ -0,0 +1,7 @@
import { BaseDataOrchestrator } from "./base-data.orchestrator";
export abstract class BaseDataTransactionOrchestrator<Entity> extends BaseDataOrchestrator<Entity> {
abstract active(dataId: string): Promise<String>;
abstract confirm(dataId: string): Promise<String>;
abstract inactive(dataId: string): Promise<String>;
}

View File

@ -0,0 +1,7 @@
export abstract class BaseDataOrchestrator<Entity> {
abstract create(data: Entity): Promise<Entity>;
abstract update(dataId: string, data: Entity): Promise<Entity>;
abstract delete(dataId: string): Promise<String>;
}

View File

@ -0,0 +1,6 @@
import { PaginationResponse } from "src/core/response/domain/ok-response.interface";
export abstract class BaseReadOrchestrator<Entity> {
abstract index(params): Promise<PaginationResponse<Entity>>;
abstract detail(dataId: string): Promise<Entity>;
}