mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
refactor: dynamic list to nestjs
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
import { forEach } from 'lodash';
|
||||
import { DynamicFilterAbstractor } from './DynamicFilterAbstractor';
|
||||
import { IDynamicFilter, IFilterRole } from './DynamicFilter.types';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { IFilterRole } from './DynamicFilter.types';
|
||||
import { DynamicFilterRoleAbstractor } from './DynamicFilterRoleAbstractor';
|
||||
import { MetableModel } from '../types/DynamicList.types';
|
||||
|
||||
export class DynamicFilter<R extends {}> extends DynamicFilterAbstractor {
|
||||
public model: MetableModel;
|
||||
public dynamicFilters: DynamicFilterRoleAbstractor[];
|
||||
|
||||
export class DynamicFilter extends DynamicFilterAbstractor {
|
||||
/**
|
||||
* Constructor.
|
||||
* @param {String} tableName -
|
||||
* @param {MetableModel} model - Metable model.
|
||||
*/
|
||||
constructor(model: typeof BaseModel) {
|
||||
constructor(model: MetableModel) {
|
||||
super();
|
||||
|
||||
this.model = model;
|
||||
@@ -29,7 +32,7 @@ export class DynamicFilter extends DynamicFilterAbstractor {
|
||||
|
||||
/**
|
||||
* Retrieve dynamic filter build queries.
|
||||
* @returns
|
||||
* @returns {Function[]}
|
||||
*/
|
||||
private dynamicFiltersBuildQuery = () => {
|
||||
return this.dynamicFilters.map((filter) => {
|
||||
@@ -72,16 +75,16 @@ export class DynamicFilter extends DynamicFilterAbstractor {
|
||||
/**
|
||||
* Retrieve response metadata from all filters adapters.
|
||||
*/
|
||||
public getResponseMeta = () => {
|
||||
public getResponseMeta = (): R => {
|
||||
const responseMeta = {};
|
||||
|
||||
this.dynamicFilters.forEach((filter) => {
|
||||
const { responseMeta: filterMeta } = filter;
|
||||
const filterMeta = filter.getResponseMeta();
|
||||
|
||||
forEach(filterMeta, (value, key) => {
|
||||
responseMeta[key] = value;
|
||||
});
|
||||
});
|
||||
return responseMeta;
|
||||
return responseMeta as R;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface IDynamicListFilter {
|
||||
customViewId?: number;
|
||||
filterRoles?: IFilterRole[];
|
||||
columnSortBy: ISortOrder;
|
||||
sortOrder: string;
|
||||
sortOrder: ISortOrder;
|
||||
stringifiedFilterRoles?: string;
|
||||
searchKeyword?: string;
|
||||
viewSlug?: string;
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { IDynamicFilter } from './DynamicFilter.types';
|
||||
import { MetableModel } from '../types/DynamicList.types';
|
||||
|
||||
export class DynamicFilterAbstractor {
|
||||
public model: typeof BaseModel;
|
||||
public model: MetableModel;
|
||||
public dynamicFilters: IDynamicFilter[];
|
||||
|
||||
/**
|
||||
* Extract relation table name from relation.
|
||||
* @param {String} column -
|
||||
* @param {String} column - Column name
|
||||
* @return {String} - join relation table.
|
||||
*/
|
||||
protected getTableFromRelationColumn = (column: string) => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-nocheck
|
||||
import { OPERATION } from '@/libs/logic-evaluation/Parser';
|
||||
|
||||
export default class QueryParser {
|
||||
export class DynamicFilterQueryParser {
|
||||
constructor(tree, queries) {
|
||||
this.tree = tree;
|
||||
this.queries = queries;
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
import moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
import { IFilterRole, IDynamicFilter } from './DynamicFilter.types';
|
||||
import Parser from '@/libs/logic-evaluation/Parser';
|
||||
import { Parser } from '@/libs/logic-evaluation/Parser';
|
||||
import { Lexer } from '@/libs/logic-evaluation/Lexer';
|
||||
import DynamicFilterQueryParser from './DynamicFilterQueryParser';
|
||||
import { DynamicFilterQueryParser } from './DynamicFilterQueryParser';
|
||||
import { COMPARATOR_TYPE, FIELD_TYPE } from './constants';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { IMetadataModel } from '../models/MetadataModel';
|
||||
|
||||
type MetadataModel = typeof BaseModel & IMetadataModel;
|
||||
import { MetableModel } from '../types/DynamicList.types';
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter {
|
||||
protected filterRoles: IFilterRole[] = [];
|
||||
protected tableName: string;
|
||||
protected model: MetadataModel;
|
||||
protected responseMeta: { [key: string]: any } = {};
|
||||
public filterRoles: IFilterRole[] = [];
|
||||
public tableName: string;
|
||||
public model: MetableModel;
|
||||
public responseMeta: { [key: string]: any } = {};
|
||||
public relationFields = [];
|
||||
|
||||
/**
|
||||
* Sets model the dynamic filter service.
|
||||
* @param {IModel} model
|
||||
*/
|
||||
public setModel(model: MetadataModel) {
|
||||
public setModel(model: MetableModel) {
|
||||
this.model = model;
|
||||
this.tableName = model.tableName;
|
||||
}
|
||||
@@ -118,7 +117,7 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter {
|
||||
* @param {IModel} model -
|
||||
* @param {} -
|
||||
*/
|
||||
private getFieldComparatorColumn = (field) => {
|
||||
protected getFieldComparatorColumn = (field) => {
|
||||
return field.fieldType === FIELD_TYPE.RELATION
|
||||
? this.getFieldComparatorRelationColumn(field)
|
||||
: `${this.tableName}.${field.column}`;
|
||||
@@ -129,7 +128,7 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter {
|
||||
* @param {IModel} model -
|
||||
* @param {Object} role -
|
||||
*/
|
||||
protected buildRoleQuery = (model: MetadataModel, role: IFilterRole) => {
|
||||
protected buildRoleQuery = (model: MetableModel, role: IFilterRole) => {
|
||||
const field = model.getField(role.fieldKey);
|
||||
const comparatorColumn = this.getFieldComparatorColumn(field);
|
||||
|
||||
@@ -384,10 +383,17 @@ export abstract class DynamicFilterRoleAbstractor implements IDynamicFilter {
|
||||
*/
|
||||
onInitialize() {}
|
||||
|
||||
buildQuery(): void {
|
||||
/**
|
||||
* Builds the query.
|
||||
*/
|
||||
buildQuery(): (builder: Knex.QueryBuilder) => void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the response meta.
|
||||
*/
|
||||
getResponseMeta() {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { IFilterRole } from './DynamicFilter.types';
|
||||
import { DynamicFilterFilterRoles } from './DynamicFilterFilterRoles';
|
||||
|
||||
export interface IDynamicFilterSearchResponseMeta {
|
||||
searchKeyword: string;
|
||||
}
|
||||
|
||||
export class DynamicFilterSearch extends DynamicFilterFilterRoles {
|
||||
private searchKeyword: string;
|
||||
|
||||
@@ -23,7 +27,7 @@ export class DynamicFilterSearch extends DynamicFilterFilterRoles {
|
||||
|
||||
/**
|
||||
* Retrieve the filter roles from model search roles.
|
||||
* @param {string} searchKeyword
|
||||
* @param {string} searchKeyword
|
||||
* @returns {IFilterRole[]}
|
||||
*/
|
||||
private getModelSearchFilterRoles(searchKeyword: string): IFilterRole[] {
|
||||
@@ -37,11 +41,21 @@ export class DynamicFilterSearch extends DynamicFilterFilterRoles {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Sets the response meta.
|
||||
*/
|
||||
setResponseMeta() {
|
||||
this.responseMeta = {
|
||||
searchKeyword: this.searchKeyword,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the response meta.
|
||||
* @returns {IDynamicFilterSearchResponseMeta}
|
||||
*/
|
||||
public getResponseMeta(): IDynamicFilterSearchResponseMeta {
|
||||
return {
|
||||
searchKeyword: this.searchKeyword,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { FIELD_TYPE } from './constants';
|
||||
import { DynamicFilterAbstractor } from './DynamicFilterAbstractor';
|
||||
import { DynamicFilterRoleAbstractor } from './DynamicFilterRoleAbstractor';
|
||||
|
||||
interface ISortRole {
|
||||
@@ -8,7 +7,10 @@ interface ISortRole {
|
||||
}
|
||||
|
||||
export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor {
|
||||
private sortRole: ISortRole = {};
|
||||
private sortRole: ISortRole = {
|
||||
fieldKey: '',
|
||||
order: '',
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
@@ -22,7 +24,6 @@ export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor {
|
||||
fieldKey: sortByFieldKey,
|
||||
order: sortDirection,
|
||||
};
|
||||
this.setResponseMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,7 +55,7 @@ export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor {
|
||||
* @param {IModel} field
|
||||
* @returns {string}
|
||||
*/
|
||||
private getFieldComparatorColumn = (field): string => {
|
||||
getFieldComparatorColumn = (field) => {
|
||||
return field.fieldType === FIELD_TYPE.RELATION
|
||||
? this.getFieldComparatorRelationColumn(field)
|
||||
: `${this.tableName}.${field.column}`;
|
||||
@@ -84,10 +85,10 @@ export class DynamicFilterSortBy extends DynamicFilterRoleAbstractor {
|
||||
/**
|
||||
* Sets response meta.
|
||||
*/
|
||||
public setResponseMeta() {
|
||||
this.responseMeta = {
|
||||
sortOrder: this.sortRole.fieldKey,
|
||||
sortBy: this.sortRole.order,
|
||||
public getResponseMeta(): ISortRole {
|
||||
return {
|
||||
fieldKey: this.sortRole.fieldKey,
|
||||
order: this.sortRole.order,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { omit } from 'lodash';
|
||||
import { DynamicFilterRoleAbstractor } from './DynamicFilterRoleAbstractor';
|
||||
import { IView } from '@/modules/Views/Views.types';
|
||||
|
||||
export class DynamicFilterViews extends DynamicFilterRoleAbstractor {
|
||||
private viewSlug: string;
|
||||
|
||||
@@ -6,7 +6,8 @@ import { DynamicListCustomView } from './DynamicListCustomView.service';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DynamicListFilterRoles } from './DynamicListFilterRoles.service';
|
||||
import { DynamicFilter } from './DynamicFilter';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { MetableModel } from './types/DynamicList.types';
|
||||
import { IFilterMeta } from '@/interfaces/Model';
|
||||
|
||||
@Injectable()
|
||||
export class DynamicListService {
|
||||
@@ -19,10 +20,13 @@ export class DynamicListService {
|
||||
|
||||
/**
|
||||
* Parses filter DTO.
|
||||
* @param {IMode} model -
|
||||
* @param {} filterDTO -
|
||||
* @param {MetableModel} model - Metable model.
|
||||
* @param {IDynamicListFilter} filterDTO - Dynamic list filter DTO.
|
||||
*/
|
||||
private parseFilterObject = (model, filterDTO) => {
|
||||
private parseFilterObject = (
|
||||
model: MetableModel,
|
||||
filterDTO: IDynamicListFilter,
|
||||
) => {
|
||||
return {
|
||||
// Merges the default properties with filter object.
|
||||
...(model.defaultSort
|
||||
@@ -37,15 +41,14 @@ export class DynamicListService {
|
||||
|
||||
/**
|
||||
* Dynamic listing.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {IModel} model - Model.
|
||||
* @param {IModel} model - Metable model.
|
||||
* @param {IDynamicListFilter} filter - Dynamic filter DTO.
|
||||
*/
|
||||
public dynamicList = async (
|
||||
model: typeof BaseModel,
|
||||
model: MetableModel,
|
||||
filter: IDynamicListFilter,
|
||||
) => {
|
||||
const dynamicFilter = new DynamicFilter(model);
|
||||
const dynamicFilter = new DynamicFilter<IFilterMeta>(model);
|
||||
|
||||
// Parses the filter object.
|
||||
const parsedFilter = this.parseFilterObject(model, filter);
|
||||
@@ -99,5 +102,5 @@ export class DynamicListService {
|
||||
? castArray(JSON.parse(filterRoles.stringifiedFilterRoles))
|
||||
: [],
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,22 @@ import { Injectable } from '@nestjs/common';
|
||||
import { ERRORS } from './constants';
|
||||
import { DynamicFilterViews } from './DynamicFilter';
|
||||
import { ServiceError } from '../Items/ServiceError';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { DynamicListServiceAbstract } from './DynamicListServiceAbstract';
|
||||
import { IView } from '../Views/Views.types';
|
||||
import { MetableModel } from './types/DynamicList.types';
|
||||
|
||||
@Injectable()
|
||||
export class DynamicListCustomView extends DynamicListServiceAbstract {
|
||||
/**
|
||||
* Retreive custom view or throws error not found.
|
||||
* @param {number} tenantId
|
||||
* @param {number} viewId
|
||||
* @param {string} viewSlug - View slug.
|
||||
* @param {MetableModel} model - Metable model.
|
||||
* @return {Promise<IView>}
|
||||
*/
|
||||
private getCustomViewOrThrowError = async (
|
||||
private async getCustomViewOrThrowError(
|
||||
viewSlug: string,
|
||||
model: BaseModel,
|
||||
) => {
|
||||
model: MetableModel,
|
||||
): Promise<IView> {
|
||||
// Finds the default view by the given view slug.
|
||||
const defaultView = model.getDefaultViewBySlug(viewSlug);
|
||||
|
||||
@@ -24,12 +25,12 @@ export class DynamicListCustomView extends DynamicListServiceAbstract {
|
||||
throw new ServiceError(ERRORS.VIEW_NOT_FOUND);
|
||||
}
|
||||
return defaultView;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic list custom view.
|
||||
* @param {IModel} model
|
||||
* @param {number} customViewId
|
||||
* @param {DynamicFilter} dynamicFilter - Dynamic filter.
|
||||
* @param {string} customViewSlug - Custom view slug.
|
||||
* @returns {DynamicFilterRoleAbstractor}
|
||||
*/
|
||||
public dynamicListCustomView = async (
|
||||
|
||||
@@ -3,10 +3,10 @@ import { Injectable } from '@nestjs/common';
|
||||
import validator from 'is-my-json-valid';
|
||||
import { IFilterRole } from './DynamicFilter/DynamicFilter.types';
|
||||
import { DynamicFilterAdvancedFilter } from './DynamicFilter/DynamicFilterAdvancedFilter';
|
||||
import { ERRORS } from './constants';
|
||||
import { ServiceError } from '../Items/ServiceError';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { DynamicFilterRoleAbstractor } from './DynamicFilter/DynamicFilterRoleAbstractor';
|
||||
import { MetableModel } from './types/DynamicList.types';
|
||||
import { ServiceError } from '../Items/ServiceError';
|
||||
import { ERRORS } from './constants';
|
||||
|
||||
@Injectable()
|
||||
export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor {
|
||||
@@ -34,12 +34,12 @@ export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor {
|
||||
|
||||
/**
|
||||
* Retrieve filter roles fields key that not exists on the given model.
|
||||
* @param {BaseModel} model
|
||||
* @param {MetableModel} model
|
||||
* @param {IFilterRole} filterRoles
|
||||
* @returns {string[]}
|
||||
*/
|
||||
private getFilterRolesFieldsNotExist = (
|
||||
model: BaseModel,
|
||||
model: MetableModel,
|
||||
filterRoles: IFilterRole[],
|
||||
): string[] => {
|
||||
return filterRoles
|
||||
@@ -49,12 +49,12 @@ export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor {
|
||||
|
||||
/**
|
||||
* Validates existance the fields of filter roles.
|
||||
* @param {BaseModel} model
|
||||
* @param {MetableModel} model
|
||||
* @param {IFilterRole[]} filterRoles
|
||||
* @throws {ServiceError}
|
||||
*/
|
||||
private validateFilterRolesFieldsExistance = (
|
||||
model: BaseModel,
|
||||
model: MetableModel,
|
||||
filterRoles: IFilterRole[],
|
||||
) => {
|
||||
const invalidFieldsKeys = this.getFilterRolesFieldsNotExist(
|
||||
@@ -82,12 +82,12 @@ export class DynamicListFilterRoles extends DynamicFilterRoleAbstractor {
|
||||
|
||||
/**
|
||||
* Dynamic list filter roles.
|
||||
* @param {BaseModel} model
|
||||
* @param {IFilterRole[]} filterRoles
|
||||
* @param {MetableModel} model - Metable model.
|
||||
* @param {IFilterRole[]} filterRoles - Filter roles.
|
||||
* @returns {DynamicFilterFilterRoles}
|
||||
*/
|
||||
public dynamicList = (
|
||||
model: BaseModel,
|
||||
model: MetableModel,
|
||||
filterRoles: IFilterRole[],
|
||||
): DynamicFilterAdvancedFilter => {
|
||||
const filterRolesParsed = R.compose(this.incrementFilterRolesIndex)(
|
||||
|
||||
@@ -4,10 +4,11 @@ import { ERRORS } from './constants';
|
||||
import { DynamicFilterSortBy } from './DynamicFilter';
|
||||
import { ServiceError } from '../Items/ServiceError';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { DynamicFilterRoleAbstractor } from './DynamicFilter/DynamicFilterRoleAbstractor';
|
||||
import { DynamicFilterAbstractor } from './DynamicFilter/DynamicFilterAbstractor';
|
||||
import { MetableModel } from './types/DynamicList.types';
|
||||
|
||||
@Injectable()
|
||||
export class DynamicListSortBy extends DynamicFilterRoleAbstractor {
|
||||
export class DynamicListSortBy extends DynamicFilterAbstractor {
|
||||
/**
|
||||
* Dynamic list sort by.
|
||||
* @param {BaseModel} model
|
||||
@@ -16,7 +17,7 @@ export class DynamicListSortBy extends DynamicFilterRoleAbstractor {
|
||||
* @returns {DynamicFilterSortBy}
|
||||
*/
|
||||
public dynamicSortBy(
|
||||
model: BaseModel,
|
||||
model: MetableModel,
|
||||
columnSortBy: string,
|
||||
sortOrder: ISortOrder,
|
||||
) {
|
||||
|
||||
@@ -11,7 +11,7 @@ const defaultModelMeta = {
|
||||
fields2: {},
|
||||
};
|
||||
|
||||
export interface IMetadataModel extends BaseModel {
|
||||
export interface IMetadataModel {
|
||||
meta: IModelMeta;
|
||||
parsedMeta: IModelMeta;
|
||||
fields: { [key: string]: IModelMetaField };
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { IModelMeta } from '@/interfaces/Model';
|
||||
import { ISearchRole } from '../DynamicFilter.types';
|
||||
import { ISearchRole } from '../DynamicFilter/DynamicFilter.types';
|
||||
|
||||
type GConstructor<T = {}> = new (...args: any[]) => T;
|
||||
|
||||
export interface ISearchableBaseModel {
|
||||
searchRoles: ISearchRole[];
|
||||
}
|
||||
|
||||
export const SearchableBaseModelMixin = <T extends GConstructor<BaseModel>>(
|
||||
Model: T,
|
||||
) =>
|
||||
@@ -11,7 +15,7 @@ export const SearchableBaseModelMixin = <T extends GConstructor<BaseModel>>(
|
||||
/**
|
||||
* Searchable model.
|
||||
*/
|
||||
static get searchable(): IModelMeta {
|
||||
static get searchable(): boolean {
|
||||
throw true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { ISortOrder } from '@/interfaces/Model';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
import { ICustomViewBaseModel } from '@/modules/CustomViews/CustomViewBaseModel';
|
||||
import { IFilterRole } from '../DynamicFilter/DynamicFilter.types';
|
||||
import { IMetadataModel } from '../models/MetadataModel';
|
||||
import { ISearchableBaseModel } from '../models/SearchableBaseModel';
|
||||
|
||||
export interface IDynamicListFilter {
|
||||
customViewId?: number;
|
||||
@@ -8,4 +12,9 @@ export interface IDynamicListFilter {
|
||||
sortOrder: string;
|
||||
stringifiedFilterRoles: string;
|
||||
searchKeyword?: string;
|
||||
}
|
||||
}
|
||||
|
||||
export type MetableModel = typeof BaseModel &
|
||||
IMetadataModel &
|
||||
ISearchableBaseModel &
|
||||
ICustomViewBaseModel;
|
||||
|
||||
Reference in New Issue
Block a user