diff --git a/src/core/helpers/validation/validate-relation.helper.ts b/src/core/helpers/validation/validate-relation.helper.ts index bcb19e1..78715e5 100644 --- a/src/core/helpers/validation/validate-relation.helper.ts +++ b/src/core/helpers/validation/validate-relation.helper.ts @@ -9,7 +9,7 @@ export class ValidateRelationHelper { private dataService: BaseDataService, private relations: validateRelations[], private tableName: string, - ) {} + ) { } async execute() { const repository = this.dataService.getRepository(); @@ -17,15 +17,32 @@ export class ValidateRelationHelper { // load relation for (const relation of this.relations) { - queryBuilder.loadRelationCountAndMap( - `${this.tableName}.total_${relation.relation}`, - `${this.tableName}.${relation.relation}`, - `total_${relation.relation}`, - ); + if (relation.singleQuery) { + queryBuilder.leftJoinAndMapOne( + `${ this.tableName }.${ relation.relation }`, + `${ this.tableName }.${ relation.relation }`, + relation.relation, + ) + } + else if (relation.query) { + queryBuilder.loadRelationCountAndMap( + `${ this.tableName }.total_${ relation.relation }`, + `${ this.tableName }.${ relation.relation }`, + `total_${ relation.relation }`, + relation.query, + ); + } + else { + queryBuilder.loadRelationCountAndMap( + `${ this.tableName }.total_${ relation.relation }`, + `${ this.tableName }.${ relation.relation }`, + `total_${ relation.relation }`, + ); + } } // filtering data only with specific data - queryBuilder.where(`${this.tableName}.id in ('${this.dataId}')`); + queryBuilder.where(`${ this.tableName }.id in ('${ this.dataId }')`); // get data const data = await queryBuilder.getOne(); @@ -34,10 +51,27 @@ export class ValidateRelationHelper { for (const relation of this.relations) { const message = relation.message ?? - `Failed! this data already connected to ${relation.relation}`; + `Failed! this data already connected to ${ relation.relation }`; - if (data[`total_${relation.relation}`]) + if (relation.singleQuery) { + const relationColumn = data[relation.relation]?.[`${ relation.singleQuery[0] }`] + if (this.mappingValidator(relationColumn, relation.singleQuery[1], relation.singleQuery[2])) + throw new UnprocessableEntityException(message); + } else if (data[`total_${ relation.relation } `]) throw new UnprocessableEntityException(message); } } -} + + mappingValidator(column, operator, value) { + switch (operator) { + case '!=': + return column != value; + + case '==': + return column == value; + + default: + return column == value; + } + } +} \ No newline at end of file diff --git a/src/core/modules/domain/usecase/managers/base-batch-update-status.manager.ts b/src/core/modules/domain/usecase/managers/base-batch-update-status.manager.ts index c8ce36a..19b19cc 100644 --- a/src/core/modules/domain/usecase/managers/base-batch-update-status.manager.ts +++ b/src/core/modules/domain/usecase/managers/base-batch-update-status.manager.ts @@ -39,7 +39,7 @@ export abstract class BaseBatchUpdateStatusManager extends BaseManager { if (!entity) { throw new NotFoundException({ statusCode: HttpStatus.NOT_FOUND, - message: `Failed! Entity with id ${id} not found`, + message: `Failed! Entity with id ${ id } not found`, error: 'Entity Not Found', }); } diff --git a/src/core/strings/constants/interface.constants.ts b/src/core/strings/constants/interface.constants.ts index 9300d00..a3bc410 100644 --- a/src/core/strings/constants/interface.constants.ts +++ b/src/core/strings/constants/interface.constants.ts @@ -1,5 +1,6 @@ import { UsersSession } from 'src/core/sessions'; import { OPERATION } from './base.constants'; +import { SelectQueryBuilder } from 'typeorm'; export interface EventTopics { topic: any; @@ -7,7 +8,16 @@ export interface EventTopics { } export interface validateRelations { + // nama relasi relation: string; + + // query digunakan untuk query optional jika ingin specifik data + query?: (qb: SelectQueryBuilder) => SelectQueryBuilder; + + // query ini sama dengan yang diatas, akan tetapi ini khusus untuk ManyToOne relation + singleQuery?: [string, any, any]; + + // custom message message?: string; } diff --git a/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts index f3690b1..103f58e 100644 --- a/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts +++ b/src/modules/item-related/item/domain/usecases/managers/active-item.manager.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { HttpStatus, Injectable, UnprocessableEntityException } from '@nestjs/common'; import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; import { ItemEntity } from '../../entities/item.entity'; import { @@ -7,11 +7,12 @@ import { } from 'src/core/strings/constants/interface.constants'; import { ItemModel } from '../../../data/models/item.model'; import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class ActiveItemManager extends BaseUpdateStatusManager { getResult(): string { - return `Success active data ${this.result.name}`; + return `Success active data ${ this.result.name }`; } async validateProcess(): Promise { @@ -27,7 +28,11 @@ export class ActiveItemManager extends BaseUpdateStatusManager { } get validateRelations(): validateRelations[] { - return []; + return [{ + relation: 'tenant', + singleQuery: ['status', '!=', STATUS.ACTIVE], + message: `Failed! Tenant of item must be active first`, + }]; } get entityTarget(): any { diff --git a/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts index 0802058..57279c0 100644 --- a/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts +++ b/src/modules/item-related/item/domain/usecases/managers/batch-active-item.manager.ts @@ -7,7 +7,8 @@ import { import { ItemModel } from '../../../data/models/item.model'; import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; import { BatchResult } from 'src/core/response/domain/ok-response.interface'; -import { Injectable } from '@nestjs/common'; +import { HttpStatus, Injectable, UnprocessableEntityException } from '@nestjs/common'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class BatchActiveItemManager extends BaseBatchUpdateStatusManager { @@ -24,7 +25,11 @@ export class BatchActiveItemManager extends BaseBatchUpdateStatusManager { - validateData(data: ItemEntity): Promise { + async validateData(data: ItemEntity): Promise { return; } @@ -24,7 +25,11 @@ export class BatchConfirmItemManager extends BaseBatchUpdateStatusManager { getResult(): string { - return `Success active data ${this.result.name}`; + return `Success active data ${ this.result.name }`; } async validateProcess(): Promise { @@ -27,7 +28,11 @@ export class ConfirmItemManager extends BaseUpdateStatusManager { } get validateRelations(): validateRelations[] { - return []; + return [{ + relation: 'tenant', + singleQuery: ['status', '!=', STATUS.ACTIVE], + message: `Failed! Tenant of item must be active first`, + }]; } get entityTarget(): any { diff --git a/src/modules/user-related/tenant/domain/usecases/managers/batch-delete-tenant.manager.ts b/src/modules/user-related/tenant/domain/usecases/managers/batch-delete-tenant.manager.ts index 789cc65..18acc85 100644 --- a/src/modules/user-related/tenant/domain/usecases/managers/batch-delete-tenant.manager.ts +++ b/src/modules/user-related/tenant/domain/usecases/managers/batch-delete-tenant.manager.ts @@ -8,11 +8,19 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { Injectable } from '@nestjs/common'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; +import { SelectQueryBuilder } from 'typeorm'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class BatchDeleteTenantManager extends BaseBatchDeleteManager { get validateRelations(): validateRelations[] { - return [{ relation: 'items' }]; + return [{ + relation: 'items', + query: (qb: SelectQueryBuilder) => { + return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] }); + }, + message: 'Failed! There is active item' + }]; } async beforeProcess(): Promise { diff --git a/src/modules/user-related/tenant/domain/usecases/managers/batch-inactive-tenant.manager.ts b/src/modules/user-related/tenant/domain/usecases/managers/batch-inactive-tenant.manager.ts index aef2e1d..6e1f7b2 100644 --- a/src/modules/user-related/tenant/domain/usecases/managers/batch-inactive-tenant.manager.ts +++ b/src/modules/user-related/tenant/domain/usecases/managers/batch-inactive-tenant.manager.ts @@ -8,11 +8,19 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { Injectable } from '@nestjs/common'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; +import { SelectQueryBuilder } from 'typeorm'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class BatchInactiveTenantManager extends BaseBatchUpdateStatusManager { get validateRelations(): validateRelations[] { - return [{ relation: 'items' }]; + return [{ + relation: 'items', + query: (qb: SelectQueryBuilder) => { + return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] }); + }, + message: 'Failed! There is active item' + }]; } validateData(data: UserEntity): Promise { diff --git a/src/modules/user-related/tenant/domain/usecases/managers/delete-tenant.manager.ts b/src/modules/user-related/tenant/domain/usecases/managers/delete-tenant.manager.ts index 745ee24..9233862 100644 --- a/src/modules/user-related/tenant/domain/usecases/managers/delete-tenant.manager.ts +++ b/src/modules/user-related/tenant/domain/usecases/managers/delete-tenant.manager.ts @@ -7,11 +7,19 @@ import { import { TenantDeletedEvent } from '../../entities/event/tenant-deleted.event'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class DeleteTenantManager extends BaseDeleteManager { get validateRelations(): validateRelations[] { - return [{ relation: 'items' }]; + return [{ + relation: 'items', + query: (qb: SelectQueryBuilder) => { + return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] }); + }, + message: 'Failed! There is active item' + }]; } getResult(): string { diff --git a/src/modules/user-related/tenant/domain/usecases/managers/inactive-tenant.manager.ts b/src/modules/user-related/tenant/domain/usecases/managers/inactive-tenant.manager.ts index 0244bc7..660a27b 100644 --- a/src/modules/user-related/tenant/domain/usecases/managers/inactive-tenant.manager.ts +++ b/src/modules/user-related/tenant/domain/usecases/managers/inactive-tenant.manager.ts @@ -7,15 +7,23 @@ import { import { TenantChangeStatusEvent } from '../../entities/event/tenant-change-status.event'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { STATUS } from 'src/core/strings/constants/base.constants'; @Injectable() export class InactiveTenantManager extends BaseUpdateStatusManager { get validateRelations(): validateRelations[] { - return [{ relation: 'items' }]; + return [{ + relation: 'items', + query: (qb: SelectQueryBuilder) => { + return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] }); + }, + message: 'Failed! There is active item' + }]; } getResult(): string { - return `Success inactive data ${this.result.name}`; + return `Success inactive data ${ this.result.name }`; } async validateProcess(): Promise {