feat(SPG-123) Abstraction Transaction Data

pull/2/head
ashar 2024-05-31 11:06:50 +07:00
parent bbff8352af
commit 9ce4c58dc1
34 changed files with 651 additions and 483 deletions

View File

@ -44,7 +44,7 @@
"@nestjs/testing": "^10.0.0",
"@types/express": "^4.17.13",
"@types/jest": "29.5.12",
"@types/node": "18.11.18",
"@types/node": "^20.12.13",
"@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",

View File

@ -1,5 +1,5 @@
import { Entity, PrimaryGeneratedColumn } from "typeorm";
import { BaseCoreEntity } from "../../domain/entities/base-core.entity";
import { Entity, PrimaryGeneratedColumn } from 'typeorm';
import { BaseCoreEntity } from '../../domain/entities/base-core.entity';
@Entity()
export abstract class BaseCoreModel<Entity> implements BaseCoreEntity {

View File

@ -1,10 +1,13 @@
import { Column, Entity } from "typeorm";
import { BaseModel } from "./base.model";
import { STATUS } from "src/core/strings/constants/base.constants";
import { BaseStatusEntity } from "../../domain/entities/base-status.entity";
import { Column, Entity } from 'typeorm';
import { BaseModel } from './base.model';
import { STATUS } from 'src/core/strings/constants/base.constants';
import { BaseStatusEntity } from '../../domain/entities/base-status.entity';
@Entity()
export abstract class BaseStatusModel<Entity> extends BaseModel<Entity> implements BaseStatusEntity {
export abstract class BaseStatusModel<Entity>
extends BaseModel<Entity>
implements BaseStatusEntity
{
@Column('enum', { name: 'status', enum: STATUS, default: STATUS.DRAFT })
status: STATUS;
}
}

View File

@ -3,7 +3,10 @@ import { BaseCoreModel } from './base-core.model';
import { BaseEntity } from '../../domain/entities/base.entity';
@Entity()
export abstract class BaseModel<Entity> extends BaseCoreModel<Entity> implements BaseEntity {
export abstract class BaseModel<Entity>
extends BaseCoreModel<Entity>
implements BaseEntity
{
@Column('varchar', { name: 'creator_id', length: 36, nullable: true })
creator_id: string;
@ -19,6 +22,6 @@ export abstract class BaseModel<Entity> extends BaseCoreModel<Entity> implements
@Column({ type: 'bigint', nullable: false })
created_at: number;
@Column({ type: 'bigint', nullable: false })
@Column({ type: 'bigint', nullable: false })
updated_at: number;
}

View File

@ -1,54 +1,58 @@
import { EntityTarget, FindManyOptions, QueryRunner, Repository } from "typeorm";
import {
EntityTarget,
FindManyOptions,
QueryRunner,
Repository,
} from 'typeorm';
export abstract class BaseDataService<Entity> {
constructor(private repository: Repository<Entity>) {}
constructor(private repository: Repository<Entity>) {}
getRepository(): Repository<Entity> {
return this.repository;
}
getRepository(): Repository<Entity> {
return this.repository;
}
async create(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
entity: Entity,
): Promise<Entity> {
const newEntity = queryRunner.manager.create(entityTarget, entity);
return await queryRunner.manager.save(newEntity);
}
async update(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
filterUpdate: any,
entity: Entity,
): Promise<Entity> {
const newEntity = await queryRunner.manager.findOne(entityTarget, {
where: filterUpdate,
});
async create(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
entity: Entity,
): Promise<Entity> {
const newEntity = queryRunner.manager.create(entityTarget, entity);
return await queryRunner.manager.save(newEntity);
}
if (!newEntity) throw new Error('Data not found!');
Object.assign(newEntity, entity);
return await queryRunner.manager.save(newEntity);
}
async update(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
filterUpdate: any,
entity: Entity,
): Promise<Entity> {
const newEntity = await queryRunner.manager.findOne(entityTarget, {
where: filterUpdate,
});
async deleteById(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
id: string,
): Promise<void> {
await queryRunner.manager.delete(entityTarget, { id });
}
if (!newEntity) throw new Error('Data not found!');
Object.assign(newEntity, entity);
return await queryRunner.manager.save(newEntity);
}
async deleteByOptions(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
findManyOptions: FindManyOptions<Entity>,
): Promise<void> {
await queryRunner.manager.delete(entityTarget, findManyOptions);
}
async deleteById(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
id: string,
): Promise<void> {
await queryRunner.manager.delete(entityTarget, { id });
}
async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
}
async deleteByOptions(
queryRunner: QueryRunner,
entityTarget: EntityTarget<Entity>,
findManyOptions: FindManyOptions<Entity>,
): Promise<void> {
await queryRunner.manager.delete(entityTarget, findManyOptions);
}
async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
}

View File

@ -1,42 +1,40 @@
import { FindOneOptions, Repository, SelectQueryBuilder } from "typeorm";
import { BaseFilterEntity } from "../../domain/entities/base-filter.entity";
import { PaginationResponse } from "src/core/response/domain/ok-response.interface";
import { FindOneOptions, Repository, SelectQueryBuilder } from 'typeorm';
import { BaseFilterEntity } from '../../domain/entities/base-filter.entity';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
export abstract class BaseReadService<Entity> {
constructor(private repository: Repository<Entity>) {}
constructor(private repository: Repository<Entity>) {}
getRepository(): Repository<Entity> {
return this.repository;
}
getRepository(): Repository<Entity> {
return this.repository;
}
async getIndex(
queryBuilder: SelectQueryBuilder<Entity>,
params: BaseFilterEntity,
): Promise<PaginationResponse<Entity>> {
const [data, total] = await queryBuilder
.take(+params.limit)
.skip(+params.limit * +params.page - +params.limit)
.getManyAndCount();
async getIndex(
queryBuilder: SelectQueryBuilder<Entity>,
params: BaseFilterEntity,
): Promise<PaginationResponse<Entity>> {
const [data, total] = await queryBuilder
.take(+params.limit)
.skip(+params.limit * +params.page - +params.limit)
.getManyAndCount();
return {
data,
total,
};
}
async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
async getOneOrFailByOptions(
findOneOptions: FindOneOptions<Entity>,
): Promise<Entity> {
return await this.repository.findOneOrFail(findOneOptions);
}
async getManyByOptions(findManyOptions): Promise<Entity[]> {
return await this.repository.find(findManyOptions);
}
return {
data,
total,
};
}
}
async getOneByOptions(findOneOptions): Promise<Entity> {
return await this.repository.findOne(findOneOptions);
}
async getOneOrFailByOptions(
findOneOptions: FindOneOptions<Entity>,
): Promise<Entity> {
return await this.repository.findOneOrFail(findOneOptions);
}
async getManyByOptions(findManyOptions): Promise<Entity[]> {
return await this.repository.find(findManyOptions);
}
}

View File

@ -1,52 +1,41 @@
import { Repository, TreeRepository } from "typeorm";
import { BaseReadService } from "./base-read.service";
import { Repository, TreeRepository } from 'typeorm';
import { BaseReadService } from './base-read.service';
export abstract class BaseTreeReadService<Entity> extends BaseReadService<Entity> {
constructor(
private dataRepository: Repository<Entity>,
private treeRepository: TreeRepository<Entity>
) {
super(dataRepository);
}
export abstract class BaseTreeReadService<
Entity,
> extends BaseReadService<Entity> {
constructor(
private dataRepository: Repository<Entity>,
private treeRepository: TreeRepository<Entity>,
) {
super(dataRepository);
}
async findRoots() {
return this.treeRepository.findRoots()
}
async findRoots() {
return this.treeRepository.findRoots();
}
async findDescendants(
parent,
relations = [],
): Promise<Entity[]> {
return this.treeRepository.findDescendants(parent, {
relations: relations,
});
}
async findDescendantsTree(
parent,
relations = [],
): Promise<Entity> {
return this.treeRepository.findDescendantsTree(parent, {
relations: relations,
});
}
async findAncestors(
parent,
relations = [],
): Promise<Entity[]> {
return await this.treeRepository.findAncestors(parent, {
relations: relations,
async findDescendants(parent, relations = []): Promise<Entity[]> {
return this.treeRepository.findDescendants(parent, {
relations: relations,
});
}
}
async findAncestorsTree(
parent,
relations = [],
): Promise<Entity> {
return await this.treeRepository.findAncestorsTree(parent, {
relations: relations,
async findDescendantsTree(parent, relations = []): Promise<Entity> {
return this.treeRepository.findDescendantsTree(parent, {
relations: relations,
});
}
}
}
async findAncestors(parent, relations = []): Promise<Entity[]> {
return await this.treeRepository.findAncestors(parent, {
relations: relations,
});
}
async findAncestorsTree(parent, relations = []): Promise<Entity> {
return await this.treeRepository.findAncestorsTree(parent, {
relations: relations,
});
}
}

View File

@ -1,3 +1,3 @@
export interface BaseCoreEntity {
id: string;
}
id: string;
}

View File

@ -1,18 +1,18 @@
import { ORDER_TYPE, STATUS } from "src/core/strings/constants/base.constants";
import { ORDER_TYPE, STATUS } from 'src/core/strings/constants/base.constants';
export interface BaseFilterEntity {
page: number;
limit: number;
q?: string;
names: string[];
entity_ids: string[];
order_by: string;
order_type: ORDER_TYPE;
statuses: STATUS[];
created_ids: string[];
created_from: number;
created_to: number;
updated_ids: string[];
updated_from: number;
updated_to: number;
}
page: number;
limit: number;
q?: string;
names: string[];
entity_ids: string[];
order_by: string;
order_type: ORDER_TYPE;
statuses: STATUS[];
created_ids: string[];
created_from: number;
created_to: number;
updated_ids: string[];
updated_from: number;
updated_to: number;
}

View File

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

View File

@ -1,10 +1,10 @@
import { BaseCoreEntity } from "./base-core.entity";
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;
}
creator_id: string;
creator_name: string;
editor_id: string;
editor_name: string;
created_at: number;
updated_at: number;
}

View File

@ -1,52 +1,53 @@
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";
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;
public user: UsersSession;
public dataService: any;
public queryBuilder: any;
protected tableName: TABLE_NAME;
@Inject()
protected userProvider: UserProvider;
private readonly baseLog = new Logger(BaseReadManager.name);
private readonly baseLog = new Logger(BaseReadManager.name);
setUser() {
try {
this.user = this.userProvider?.user;
} catch (error) {
this.user = BLANK_USER;
}
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);
}
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();
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(`beforeProcess`, BaseReadManager.name);
await this.beforeProcess();
this.baseLog.log('afterProcess', BaseReadManager.name);
await this.afterProcess();
}
this.baseLog.log('process', BaseReadManager.name);
await this.process();
abstract prepareData(): Promise<void>;
this.baseLog.log('afterProcess', BaseReadManager.name);
await this.afterProcess();
}
abstract beforeProcess(): Promise<void>;
abstract prepareData(): Promise<void>;
abstract process(): Promise<void>;
abstract beforeProcess(): Promise<void>;
abstract afterProcess(): Promise<void>;
}
abstract process(): Promise<void>;
abstract afterProcess(): Promise<void>;
}

View File

@ -1,85 +1,91 @@
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";
import {
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;
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);
private readonly baseLog = new Logger(BaseManager.name);
setUser() {
try {
this.user = this.userProvider?.user;
} catch (error) {
this.user = BLANK_USER;
}
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();
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.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 get eventTopics(): EventTopics[];
abstract prepareData(): Promise<void>;
async execute(): Promise<void> {
try {
this.setUser();
abstract validateProcess(): Promise<void>;
this.queryRunner.startTransaction();
this.baseLog.verbose('prepareData');
await this.prepareData();
abstract beforeProcess(): Promise<void>;
if (!this.data || !this.dataService) {
throw new Error("data or service not implemented.");
}
abstract process(): Promise<void>;
this.baseLog.verbose('validateProcess');
await this.validateProcess();
abstract afterProcess(): Promise<void>;
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
};
}
async publishEvents() {
if (!this.eventTopics.length) return;
}
}

View File

@ -0,0 +1,67 @@
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BaseManager } from '../base.manager';
import { HttpStatus, NotFoundException } from '@nestjs/common';
export abstract class BaseBatchDeleteManager<Entity> extends BaseManager {
protected dataIds: string[];
protected result: BatchResult;
abstract get entityTarget(): any;
setData(ids: string[]): void {
this.dataIds = ids;
}
validateProcess(): Promise<void> {
return;
}
prepareData(): Promise<void> {
return;
}
async process(): Promise<void> {
let totalFailed = 0;
let totalSuccess = 0;
let messages = [];
for (const id of this.dataIds) {
try {
const entity = await this.dataService.getOneByOptions({
where: {
id: id,
},
});
if (!entity) {
throw new NotFoundException({
statusCode: HttpStatus.NOT_FOUND,
message: `Failed! Entity with id ${id} not found`,
error: 'Entity Not Found',
});
}
await this.validateData(entity);
await this.dataService.deleteById(
this.queryRunner,
this.entityTarget,
id,
);
totalSuccess = totalSuccess + 1;
} catch (error) {
totalFailed = totalFailed + 1;
messages.push(error.response?.message ?? error.message);
}
}
this.result = {
total_items: this.dataIds.length,
total_failed: totalFailed,
total_success: totalSuccess,
messages: messages,
};
}
abstract validateData(data: Entity): Promise<void>;
abstract getResult(): BatchResult;
}

View File

@ -0,0 +1,75 @@
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { BaseManager } from '../base.manager';
import { HttpStatus, NotFoundException } from '@nestjs/common';
import { STATUS } from 'src/core/strings/constants/base.constants';
export abstract class BaseBatchUpdateStatusManager<Entity> extends BaseManager {
protected dataIds: string[];
protected result: BatchResult;
protected dataStatus: STATUS;
abstract get entityTarget(): any;
setData(ids: string[], status: STATUS): void {
this.dataIds = ids;
this.dataStatus = status;
}
validateProcess(): Promise<void> {
return;
}
prepareData(): Promise<void> {
return;
}
async process(): Promise<void> {
let totalFailed = 0;
let totalSuccess = 0;
let messages = [];
for (const id of this.dataIds) {
try {
const entity = await this.dataService.getOneByOptions({
where: {
id: id,
},
});
if (!entity) {
throw new NotFoundException({
statusCode: HttpStatus.NOT_FOUND,
message: `Failed! Entity with id ${id} not found`,
error: 'Entity Not Found',
});
}
await this.validateData(entity);
await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: id },
{
status: this.dataStatus,
editor_id: this.user.id,
editor_name: this.user.name,
updated_at: new Date().getTime(),
},
);
totalSuccess = totalSuccess + 1;
} catch (error) {
totalFailed = totalFailed + 1;
messages.push(error.response?.message ?? error.message);
}
}
this.result = {
total_items: this.dataIds.length,
total_failed: totalFailed,
total_success: totalSuccess,
messages: messages,
};
}
abstract validateData(data: Entity): Promise<void>;
abstract getResult(): BatchResult;
}

View File

@ -1,40 +1,37 @@
import { BaseManager } from "../base.manager";
import { Injectable } from "@nestjs/common";
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;
protected result: Entity;
protected duplicateColumn: string[];
abstract get entityTarget(): any;
setData(entity: Entity): void {
this.data = entity;
}
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 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 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']
}
})
}
}
async getResult(): Promise<Entity> {
return await this.dataService.getOneByOptions({
where: {
id: this.result['id'],
},
});
}
}

View File

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

View File

@ -1,42 +1,39 @@
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";
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;
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;
}
setData(id: string, status: STATUS): void {
this.dataId = id;
this.dataStatus = status;
}
async prepareData(): Promise<void> {
this.data = new UserPrivilegeModel();
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,
});
}
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,
);
}
async process(): Promise<void> {
this.result = await this.dataService.update(
this.queryRunner,
this.entityTarget,
{ id: this.dataId },
this.data,
);
}
abstract getResult(): string;
}
abstract getResult(): string;
}

View File

@ -1,41 +1,39 @@
import { Injectable } from "@nestjs/common";
import { BaseManager } from "../base.manager";
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;
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;
}
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 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 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
}
})
}
}
async getResult(): Promise<Entity> {
return await this.dataService.getOneByOptions({
where: {
id: this.dataId,
},
});
}
}

View File

@ -1,7 +1,13 @@
import { BaseDataOrchestrator } from "./base-data.orchestrator";
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
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>;
}
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>;
abstract batchConfirm(dataIds: string[]): Promise<BatchResult>;
abstract batchActive(dataIds: string[]): Promise<BatchResult>;
abstract batchInactive(dataIds: string[]): Promise<BatchResult>;
}

View File

@ -1,7 +1,8 @@
import { BatchResult } from 'src/core/response/domain/ok-response.interface';
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>;
}
abstract create(data: Entity): Promise<Entity>;
abstract update(dataId: string, data: Entity): Promise<Entity>;
abstract delete(dataId: string): Promise<String>;
abstract batchDelete(dataIds: string[]): Promise<BatchResult>;
}

View File

@ -1,6 +1,6 @@
import { PaginationResponse } from "src/core/response/domain/ok-response.interface";
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>;
}
abstract index(params): Promise<PaginationResponse<Entity>>;
abstract detail(dataId: string): Promise<Entity>;
}

View File

@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';
export class BatchIdsDto {
@ApiProperty({ type: [String] })
ids: string[];
}

View File

@ -1,5 +1,5 @@
import { BaseCoreEntity } from "../../domain/entities/base-core.entity";
import { BaseCoreEntity } from '../../domain/entities/base-core.entity';
export class BaseCoreDto implements BaseCoreEntity {
id: string;
}
id: string;
}

View File

@ -1,8 +1,14 @@
import { ApiProperty } from "@nestjs/swagger";
import { BaseFilterEntity } from "../../domain/entities/base-filter.entity";
import { Transform } from "class-transformer";
import { IsArray, IsEnum, IsNumber, IsString, ValidateIf } from "class-validator";
import { ORDER_TYPE, STATUS } from "src/core/strings/constants/base.constants";
import { ApiProperty } from '@nestjs/swagger';
import { BaseFilterEntity } from '../../domain/entities/base-filter.entity';
import { Transform } from 'class-transformer';
import {
IsArray,
IsEnum,
IsNumber,
IsString,
ValidateIf,
} from 'class-validator';
import { ORDER_TYPE, STATUS } from 'src/core/strings/constants/base.constants';
export class BaseFilterDto implements BaseFilterEntity {
@ApiProperty({ type: Number, required: false, default: 1 })
@ -16,7 +22,7 @@ export class BaseFilterDto implements BaseFilterEntity {
@ValidateIf((body) => body.limit)
@IsNumber()
limit = 10;
@ApiProperty({ type: String, required: false })
q: string;

View File

@ -1,7 +1,7 @@
import { STATUS } from "src/core/strings/constants/base.constants";
import { BaseStatusEntity } from "../../domain/entities/base-status.entity";
import { BaseDto } from "./base.dto";
import { STATUS } from 'src/core/strings/constants/base.constants';
import { BaseStatusEntity } from '../../domain/entities/base-status.entity';
import { BaseDto } from './base.dto';
export class BaseStatusDto extends BaseDto implements BaseStatusEntity {
status: STATUS;
}
status: STATUS;
}

View File

@ -1,11 +1,11 @@
import { BaseEntity } from "../../domain/entities/base.entity";
import { BaseCoreDto } from "./base-core.dto";
import { BaseEntity } from '../../domain/entities/base.entity';
import { BaseCoreDto } from './base-core.dto';
export class BaseDto extends BaseCoreDto implements BaseEntity {
creator_id: string;
creator_name: string;
editor_id: string;
editor_name: string;
created_at: number;
updated_at: number;
}
creator_id: string;
creator_name: string;
editor_id: string;
editor_name: string;
created_at: number;
updated_at: number;
}

View File

@ -16,7 +16,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
let body: any;
let exceptionResponse;
try {
try {
exceptionResponse = JSON.parse(exception.message);
} catch (error) {}

View File

@ -15,3 +15,10 @@ export interface PaginationResponse<T> {
data: T[];
total: number;
}
export interface BatchResult {
messages: string[];
total_items: number;
total_success: number;
total_failed: number;
}

View File

@ -1,22 +1,22 @@
export enum STATUS {
ACTIVE = 'active',
CANCEL = 'cancel',
CONFIRMED = 'confirmed',
DRAFT = 'draft',
EXPIRED = 'expired',
INACTIVE = 'inactive',
PENDING = 'pending',
REFUNDED = 'refunded',
SETTLED = 'settled',
ACTIVE = 'active',
CANCEL = 'cancel',
CONFIRMED = 'confirmed',
DRAFT = 'draft',
EXPIRED = 'expired',
INACTIVE = 'inactive',
PENDING = 'pending',
REFUNDED = 'refunded',
SETTLED = 'settled',
}
export enum ORDER_TYPE {
ASC = 'ASC',
DESC = 'DESC',
ASC = 'ASC',
DESC = 'DESC',
}
export enum CONNECTION_NAME {
DEFAULT = 'default',
DEFAULT = 'default',
}
export enum METHOD {
@ -38,6 +38,6 @@ export enum OPERATION {
}
export const BLANK_USER = {
id: null,
name: null,
}
id: null,
name: null,
};

View File

@ -1,9 +1,9 @@
import { UsersSession } from "src/core/sessions";
import { OPERATION } from "./base.constants";
import { UsersSession } from 'src/core/sessions';
import { OPERATION } from './base.constants';
export interface EventTopics {
topic: any,
data: IEvent,
topic: any;
data?: IEvent;
}
export interface IEvent<Entity = any> {
@ -14,4 +14,4 @@ export interface IEvent<Entity = any> {
description: null | string;
module: string;
op: OPERATION;
}
}

View File

@ -1,3 +1,3 @@
export enum MODULE_NAME {
USER_PRIVILEGE = 'user-privileges'
}
USER_PRIVILEGE = 'user-privileges',
}

View File

@ -1,3 +1,3 @@
export enum TABLE_NAME {
USER_PRIVILEGE = 'user_privileges'
}
USER_PRIVILEGE = 'user_privileges',
}

View File

@ -1120,10 +1120,12 @@
dependencies:
undici-types "~5.26.4"
"@types/node@18.11.18":
version "18.11.18"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f"
integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==
"@types/node@^20.12.13":
version "20.12.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.13.tgz#90ed3b8a4e52dd3c5dc5a42dde5b85b74ad8ed88"
integrity sha512-gBGeanV41c1L171rR7wjbMiEpEI/l5XFQdLLfhr/REwpgDy/4U8y89+i8kRiLzDyZdOkXh+cRaTetUnCYutoXA==
dependencies:
undici-types "~5.26.4"
"@types/qs@*":
version "6.9.15"