feat(SPG-5) Filter

pull/2/head
ashar 2024-06-04 15:52:33 +07:00
parent 1ac5aca57d
commit 6596c776e8
17 changed files with 316 additions and 65 deletions

View File

@ -0,0 +1,22 @@
import { SelectQueryBuilder } from 'typeorm';
export class BetweenQueryHelper {
constructor(
protected baseQuery: SelectQueryBuilder<any>,
protected moduleName: string,
protected columnName: string,
protected from: any,
protected to: any,
protected valueAlias: string,
) {}
getQuery(): SelectQueryBuilder<any> {
return this.baseQuery.andWhere(
`${this.moduleName}.${this.columnName} BETWEEN :from${this.valueAlias} AND :to${this.valueAlias}`,
{
[`from${this.valueAlias}`]: this.from,
[`to${this.valueAlias}`]: this.to,
},
);
}
}

View File

@ -0,0 +1,84 @@
import { SelectQueryBuilder } from 'typeorm';
import { WhereInQueryHelper } from './or-where-in-query.helpe';
import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity';
import { BetweenQueryHelper } from './between-query.helper';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { ORDER_TYPE } from 'src/core/strings/constants/base.constants';
export function setQueryFilterDefault(
queryBuilder: SelectQueryBuilder<any>,
baseFilter: BaseFilterEntity,
tableName: TABLE_NAME,
): SelectQueryBuilder<any> {
// filter berdasarkan statuses
if (!!baseFilter.statuses)
new WhereInQueryHelper(
queryBuilder,
tableName,
'status',
baseFilter.statuses,
'statuses',
).getQuery();
// filter berdasarkan id pembuat
if (!!baseFilter.created_ids)
new WhereInQueryHelper(
queryBuilder,
tableName,
'created_id',
baseFilter.created_ids,
'created_ids',
).getQuery();
// filter berdasarkan tanggal terakhir dibuat
if (!!baseFilter.created_from && !!baseFilter.created_to)
new BetweenQueryHelper(
queryBuilder,
tableName,
'created_at',
baseFilter.created_from,
baseFilter.created_to,
'created',
).getQuery();
// filter berdasarkan id pengubah
if (!!baseFilter.updated_ids)
new WhereInQueryHelper(
queryBuilder,
tableName,
'editor_id',
baseFilter.updated_ids,
'editor_ids',
).getQuery();
// filter berdasarkan tanggal terakhir update
if (!!baseFilter.updated_from && !!baseFilter.updated_to)
new BetweenQueryHelper(
queryBuilder,
tableName,
'updated_at',
baseFilter.updated_from,
baseFilter.updated_to,
'updated',
).getQuery();
return queryBuilder;
}
export function getOrderBy(
baseFilter: BaseFilterEntity,
queryBuilder: SelectQueryBuilder<any>,
tableName: TABLE_NAME,
) {
let orderBy: string = `${tableName}.created_at`;
const orderType = baseFilter.order_type ?? ORDER_TYPE.DESC;
if (!!baseFilter.order_by) {
orderBy =
baseFilter.order_by.split('.').length > 1
? `${baseFilter.order_by}`
: `${tableName}.${baseFilter.order_by}`;
}
queryBuilder.orderBy(orderBy, orderType);
}

View File

@ -0,0 +1,31 @@
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { SelectQueryBuilder } from 'typeorm';
export function joinRelationHelper(
relations: string[],
tableName: TABLE_NAME,
queryBuilder: SelectQueryBuilder<any>,
type?: string,
) {
relations.forEach((relation) => {
let alias = relation;
let relationName = `${tableName}.${relation}`;
if (relation.split(' ').length > 1) {
alias = relation.split(' ').pop();
const relationpath = relation.split(' ')[0];
if (relationpath.split('.').length > 1) relationName = relationpath;
else relationName = `${tableName}.${relation.split(' ')[0]}`;
} else if (relation.split('.').length > 1) {
alias = relation.split('.').pop();
relationName = relation;
}
if (type == 'count')
queryBuilder.loadRelationCountAndMap(relationName, relationName, alias);
else if (type == 'select')
queryBuilder.leftJoinAndSelect(relationName, alias);
else queryBuilder.leftJoin(relationName, alias);
});
}

View File

@ -0,0 +1,20 @@
import { SelectQueryBuilder } from 'typeorm';
export class WhereInQueryHelper {
constructor(
protected baseQuery: SelectQueryBuilder<any>,
protected moduleName: string,
protected columnName: string,
protected values: string[],
protected valueAliases: string,
) {}
getQuery(): SelectQueryBuilder<any> {
return this.baseQuery.andWhere(
`${this.moduleName}.${this.columnName} IN (:...${this.valueAliases})`,
{
[this.valueAliases]: this.values,
},
);
}
}

View File

@ -0,0 +1,20 @@
import { SelectQueryBuilder } from 'typeorm';
export class SearchQueryHelper {
constructor(
protected baseQuery: SelectQueryBuilder<any>,
protected moduleName: string,
protected columnName: string,
protected value: string,
protected valueAliases: string,
) {}
getQuery(): SelectQueryBuilder<any> {
return this.baseQuery.andWhere(
`${this.moduleName}.${this.columnName} ILIKE :${this.valueAliases}`,
{
[this.valueAliases]: `%${this.value}%`,
},
);
}
}

View File

@ -1,12 +1,6 @@
import { Param } from 'src/core/modules/domain/entities/base-filter.entity';
import { Brackets, SelectQueryBuilder } from 'typeorm'; import { Brackets, SelectQueryBuilder } from 'typeorm';
export interface Param {
cols: string;
data: string[];
additional?: any[];
leftJoin?: any[];
}
export class SpecificSearchFilter<Entity = any> { export class SpecificSearchFilter<Entity = any> {
constructor( constructor(
private query: SelectQueryBuilder<Entity>, private query: SelectQueryBuilder<Entity>,

View File

@ -16,3 +16,16 @@ export interface BaseFilterEntity {
updated_from: number; updated_from: number;
updated_to: number; updated_to: number;
} }
export interface Param {
cols: string;
data: string[];
additional?: any[];
leftJoin?: any[];
}
export interface RelationParam {
joinRelations: string[];
selectRelations: string[];
countRelations: string[];
}

View File

@ -2,6 +2,7 @@ import { Inject, Injectable, Logger } from '@nestjs/common';
import { UserProvider, UsersSession } from 'src/core/sessions'; import { UserProvider, UsersSession } from 'src/core/sessions';
import { BLANK_USER } from 'src/core/strings/constants/base.constants'; import { BLANK_USER } from 'src/core/strings/constants/base.constants';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { RelationParam } from '../entities/base-filter.entity';
@Injectable() @Injectable()
export abstract class BaseReadManager { export abstract class BaseReadManager {
@ -9,6 +10,8 @@ export abstract class BaseReadManager {
public dataService: any; public dataService: any;
public queryBuilder: any; public queryBuilder: any;
protected tableName: TABLE_NAME; protected tableName: TABLE_NAME;
abstract get relations(): RelationParam;
abstract get selects(): string[];
@Inject() @Inject()
protected userProvider: UserProvider; protected userProvider: UserProvider;
@ -22,8 +25,9 @@ export abstract class BaseReadManager {
} }
} }
setService(dataService) { setService(dataService, tableName) {
this.dataService = dataService; this.dataService = dataService;
this.tableName = tableName;
this.queryBuilder = this.dataService this.queryBuilder = this.dataService
.getRepository() .getRepository()
.createQueryBuilder(this.tableName); .createQueryBuilder(this.tableName);

View File

@ -1,11 +1,9 @@
import { joinRelationHelper } from 'src/core/helpers/query/join-relations.helper';
import { BaseReadManager } from '../base-read.manager'; import { BaseReadManager } from '../base-read.manager';
export abstract class BaseDetailManager<Entity> extends BaseReadManager { export abstract class BaseDetailManager<Entity> extends BaseReadManager {
protected dataId: string; protected dataId: string;
protected result: Entity; protected result: Entity;
abstract get selectData(): string[];
abstract get relationData(): string[];
abstract get setFindProperties(): any; abstract get setFindProperties(): any;
setData(dataId: string): void { setData(dataId: string): void {
@ -13,7 +11,26 @@ export abstract class BaseDetailManager<Entity> extends BaseReadManager {
} }
async process(): Promise<void> { async process(): Promise<void> {
this.queryBuilder.select(this.selectData).where(this.setFindProperties); const { joinRelations, selectRelations, countRelations } = this.relations;
if (joinRelations?.length)
joinRelationHelper(joinRelations, this.tableName, this.queryBuilder);
if (selectRelations?.length)
joinRelationHelper(
selectRelations,
this.tableName,
this.queryBuilder,
'select',
);
if (countRelations?.length)
joinRelationHelper(
countRelations,
this.tableName,
this.queryBuilder,
'count',
);
if (this.selects?.length) this.queryBuilder.select(this.selects);
this.queryBuilder.where(this.setFindProperties);
this.result = await this.queryBuilder.getOne(); this.result = await this.queryBuilder.getOne();
} }

View File

@ -1,10 +1,13 @@
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { BaseReadManager } from '../base-read.manager'; import { BaseReadManager } from '../base-read.manager';
import { SelectQueryBuilder } from 'typeorm'; import { SelectQueryBuilder } from 'typeorm';
import { SpecificSearchFilter } from 'src/core/helpers/query/specific-search.helper';
import { import {
Param, getOrderBy,
SpecificSearchFilter, setQueryFilterDefault,
} from 'src/core/helpers/query/specific-search.helper'; } from 'src/core/helpers/query/default-filter.helper';
import { Param } from '../../entities/base-filter.entity';
import { joinRelationHelper } from 'src/core/helpers/query/join-relations.helper';
export abstract class BaseIndexManager<Entity> extends BaseReadManager { export abstract class BaseIndexManager<Entity> extends BaseReadManager {
protected result: PaginationResponse<Entity>; protected result: PaginationResponse<Entity>;
@ -16,26 +19,36 @@ export abstract class BaseIndexManager<Entity> extends BaseReadManager {
} }
async process(): Promise<void> { async process(): Promise<void> {
// const filterSearch: string[] = this.setFilterSearch(); const { joinRelations, selectRelations, countRelations } = this.relations;
// this.queryBuilder.andWhere( if (joinRelations?.length)
// new Brackets((qb) => { joinRelationHelper(joinRelations, this.tableName, this.queryBuilder);
// filterSearch.map((fSearch) => { if (selectRelations?.length)
// qb.orWhere(`${fSearch} ILIKE :query`, { joinRelationHelper(
// query: `%${ selectRelations,
// this.filterParam.q.trim().replace(/\s+/g, ' ') ?? '' this.tableName,
// }%`, this.queryBuilder,
// }); 'select',
// }); );
// }), if (countRelations?.length)
// ); joinRelationHelper(
countRelations,
this.tableName,
this.queryBuilder,
'count',
);
// new SpecificSearchFilter<Entity>( if (this.selects?.length) this.queryBuilder.select(this.selects);
// this.queryBuilder,
// this.tableName, new SpecificSearchFilter<Entity>(
// this.specificFilter, this.queryBuilder,
// ).getFilter(); this.tableName,
this.specificFilter,
).getFilter();
getOrderBy(this.filterParam, this.queryBuilder, this.tableName);
this.setQueryFilter(this.queryBuilder); this.setQueryFilter(this.queryBuilder);
setQueryFilterDefault(this.queryBuilder, this.filterParam, this.tableName);
this.result = await this.dataService.getIndex( this.result = await this.dataService.getIndex(
this.queryBuilder, this.queryBuilder,
@ -43,10 +56,6 @@ export abstract class BaseIndexManager<Entity> extends BaseReadManager {
); );
} }
setFilterSearch(): string[] {
return [];
}
abstract setQueryFilter( abstract setQueryFilter(
queryBuilder: SelectQueryBuilder<Entity>, queryBuilder: SelectQueryBuilder<Entity>,
): SelectQueryBuilder<Entity>; ): SelectQueryBuilder<Entity>;

View File

@ -23,7 +23,6 @@ export class BaseFilterDto implements BaseFilterEntity {
@IsNumber() @IsNumber()
limit = 10; limit = 10;
@ApiProperty({ type: String, required: false })
q: string; q: string;
@ApiProperty({ type: ['string'], required: false }) @ApiProperty({ type: ['string'], required: false })

View File

@ -32,6 +32,7 @@ export class LoginManager extends BaseCustomManager<UserEntity> {
username: this.data.username, username: this.data.username,
}, },
}); });
if (!this.userLogin) this.throwError();
const valid = await validatePassword( const valid = await validatePassword(
this.data.password, this.data.password,
@ -47,7 +48,6 @@ export class LoginManager extends BaseCustomManager<UserEntity> {
user_privilege_id: this.userLogin.user_privilege_id, user_privilege_id: this.userLogin.user_privilege_id,
}; };
console.log(this.session, 'das');
this.token = this.session.createAccessToken(tokenData); this.token = this.session.createAccessToken(tokenData);
const refreshToken = this.session.createAccessToken(tokenData); const refreshToken = this.session.createAccessToken(tokenData);

View File

@ -1,8 +1,11 @@
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { UserPrivilegeConfigurationEntity } from '../../../entities/user-privilege-configuration.entity'; import { UserPrivilegeConfigurationEntity } from '../../../entities/user-privilege-configuration.entity';
import { Param } from 'src/core/helpers/query/specific-search.helper';
import { SelectQueryBuilder } from 'typeorm'; import { SelectQueryBuilder } from 'typeorm';
import {
Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
@Injectable() @Injectable()
export class IndexUserPrivilegeConfigurationManager extends BaseIndexManager<UserPrivilegeConfigurationEntity> { export class IndexUserPrivilegeConfigurationManager extends BaseIndexManager<UserPrivilegeConfigurationEntity> {
@ -18,6 +21,18 @@ export class IndexUserPrivilegeConfigurationManager extends BaseIndexManager<Use
return; return;
} }
get relations(): RelationParam {
return {
joinRelations: [],
selectRelations: [],
countRelations: [],
};
}
get selects(): string[] {
return [];
}
get specificFilter(): Param[] { get specificFilter(): Param[] {
return; return;
} }
@ -25,7 +40,6 @@ export class IndexUserPrivilegeConfigurationManager extends BaseIndexManager<Use
setQueryFilter( setQueryFilter(
queryBuilder: SelectQueryBuilder<UserPrivilegeConfigurationEntity>, queryBuilder: SelectQueryBuilder<UserPrivilegeConfigurationEntity>,
): SelectQueryBuilder<UserPrivilegeConfigurationEntity> { ): SelectQueryBuilder<UserPrivilegeConfigurationEntity> {
console.log(this.filterParam, 'param');
if (this.filterParam.user_privilege_ids) { if (this.filterParam.user_privilege_ids) {
queryBuilder.andWhere(`user_privilege_id In (:...privilegeIds)`, { queryBuilder.andWhere(`user_privilege_id In (:...privilegeIds)`, {
privilegeIds: this.filterParam.user_privilege_ids, privilegeIds: this.filterParam.user_privilege_ids,

View File

@ -4,6 +4,7 @@ import { UserPrivilegeConfigurationEntity } from '../../entities/user-privilege-
import { UserPrivilegeConfigurationService } from '../../../data/service/user-privilege-configuration.service'; import { UserPrivilegeConfigurationService } from '../../../data/service/user-privilege-configuration.service';
import { IndexUserPrivilegeConfigurationManager } from './managers/index-user-privilege-configuration.manager'; import { IndexUserPrivilegeConfigurationManager } from './managers/index-user-privilege-configuration.manager';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
@Injectable() @Injectable()
export class UserPrivilegeConfigurationDataOrchestrator { export class UserPrivilegeConfigurationDataOrchestrator {
@ -24,7 +25,10 @@ export class UserPrivilegeConfigurationDataOrchestrator {
params, params,
): Promise<PaginationResponse<UserPrivilegeConfigurationEntity>> { ): Promise<PaginationResponse<UserPrivilegeConfigurationEntity>> {
this.indexManager.setFilterParam(params); this.indexManager.setFilterParam(params);
this.indexManager.setService(this.serviceData); this.indexManager.setService(
this.serviceData,
TABLE_NAME.USER_PRIVILEGE_CONFIGURATION,
);
await this.indexManager.execute(); await this.indexManager.execute();
return this.indexManager.getResult(); return this.indexManager.getResult();
} }

View File

@ -2,23 +2,10 @@ import { Injectable } from '@nestjs/common';
import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager';
import { UserPrivilegeEntity } from '../../../entities/user-privilege.entity'; import { UserPrivilegeEntity } from '../../../entities/user-privilege.entity';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity';
@Injectable() @Injectable()
export class DetailUserPrivilegeManager extends BaseDetailManager<UserPrivilegeEntity> { export class DetailUserPrivilegeManager extends BaseDetailManager<UserPrivilegeEntity> {
get setFindProperties(): any {
return {
id: this.dataId,
};
}
get selectData(): string[] {
return ['id'];
}
get relationData(): string[] {
return [];
}
async prepareData(): Promise<void> { async prepareData(): Promise<void> {
this.tableName = TABLE_NAME.USER_PRIVILEGE; this.tableName = TABLE_NAME.USER_PRIVILEGE;
return; return;
@ -31,4 +18,22 @@ export class DetailUserPrivilegeManager extends BaseDetailManager<UserPrivilegeE
async afterProcess(): Promise<void> { async afterProcess(): Promise<void> {
return; return;
} }
get relations(): RelationParam {
return {
joinRelations: [],
selectRelations: [],
countRelations: [],
};
}
get selects(): string[] {
return [];
}
get setFindProperties(): any {
return {
id: this.dataId,
};
}
} }

View File

@ -2,13 +2,14 @@ import { Injectable } from '@nestjs/common';
import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager';
import { UserPrivilegeEntity } from '../../../entities/user-privilege.entity'; import { UserPrivilegeEntity } from '../../../entities/user-privilege.entity';
import { SelectQueryBuilder } from 'typeorm'; import { SelectQueryBuilder } from 'typeorm';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import {
import { Param } from 'src/core/helpers/query/specific-search.helper'; Param,
RelationParam,
} from 'src/core/modules/domain/entities/base-filter.entity';
@Injectable() @Injectable()
export class IndexUserPrivilegeManager extends BaseIndexManager<UserPrivilegeEntity> { export class IndexUserPrivilegeManager extends BaseIndexManager<UserPrivilegeEntity> {
async prepareData(): Promise<void> { async prepareData(): Promise<void> {
this.tableName = TABLE_NAME.USER_PRIVILEGE;
return; return;
} }
@ -20,17 +21,30 @@ export class IndexUserPrivilegeManager extends BaseIndexManager<UserPrivilegeEnt
return; return;
} }
get specificFilter(): Param[] { get relations(): RelationParam {
return {
joinRelations: [],
selectRelations: [],
countRelations: [],
};
}
get selects(): string[] {
return []; return [];
} }
get specificFilter(): Param[] {
return [
{
cols: `${this.tableName}.name`,
data: this.filterParam.names,
},
];
}
setQueryFilter( setQueryFilter(
queryBuilder: SelectQueryBuilder<UserPrivilegeEntity>, queryBuilder: SelectQueryBuilder<UserPrivilegeEntity>,
): SelectQueryBuilder<UserPrivilegeEntity> { ): SelectQueryBuilder<UserPrivilegeEntity> {
return queryBuilder; return queryBuilder;
} }
setFilterSearch(): string[] {
return [];
}
} }

View File

@ -5,6 +5,7 @@ import { UserPrivilegeEntity } from '../../entities/user-privilege.entity';
import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; import { PaginationResponse } from 'src/core/response/domain/ok-response.interface';
import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator';
import { DetailUserPrivilegeManager } from './managers/detail-user-privilege.manager'; import { DetailUserPrivilegeManager } from './managers/detail-user-privilege.manager';
import { TABLE_NAME } from 'src/core/strings/constants/table.constants';
@Injectable() @Injectable()
export class UserPrivilegeReadOrchestrator extends BaseReadOrchestrator<UserPrivilegeEntity> { export class UserPrivilegeReadOrchestrator extends BaseReadOrchestrator<UserPrivilegeEntity> {
@ -18,14 +19,14 @@ export class UserPrivilegeReadOrchestrator extends BaseReadOrchestrator<UserPriv
async index(params): Promise<PaginationResponse<UserPrivilegeEntity>> { async index(params): Promise<PaginationResponse<UserPrivilegeEntity>> {
this.indexManager.setFilterParam(params); this.indexManager.setFilterParam(params);
this.indexManager.setService(this.serviceData); this.indexManager.setService(this.serviceData, TABLE_NAME.USER_PRIVILEGE);
await this.indexManager.execute(); await this.indexManager.execute();
return this.indexManager.getResult(); return this.indexManager.getResult();
} }
async detail(dataId: string): Promise<UserPrivilegeEntity> { async detail(dataId: string): Promise<UserPrivilegeEntity> {
this.detailManager.setData(dataId); this.detailManager.setData(dataId);
this.detailManager.setService(this.serviceData); this.detailManager.setService(this.serviceData, TABLE_NAME.USER_PRIVILEGE);
await this.detailManager.execute(); await this.detailManager.execute();
return this.detailManager.getResult(); return this.detailManager.getResult();
} }