mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
refactoring: custom views service.
fix: constraints of delete item from storage. fix: constraints of delete item category from storage. fix: localize database seeds files. fix: view meta data in accounts list response.
This commit is contained in:
@@ -1,15 +1,20 @@
|
||||
import { uniqBy } from 'lodash';
|
||||
import { forEach, uniqBy } from 'lodash';
|
||||
import {
|
||||
buildFilterRolesJoins,
|
||||
} from 'lib/ViewRolesBuilder';
|
||||
import { IModel } from 'interfaces';
|
||||
|
||||
export default class DynamicFilter {
|
||||
model: IModel;
|
||||
tableName: string;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param {String} tableName -
|
||||
*/
|
||||
constructor(tableName) {
|
||||
this.tableName = tableName;
|
||||
constructor(model) {
|
||||
this.model = model;
|
||||
this.tableName = model.tableName;
|
||||
this.filters = [];
|
||||
}
|
||||
|
||||
@@ -18,7 +23,7 @@ export default class DynamicFilter {
|
||||
* @param {*} filterRole -
|
||||
*/
|
||||
setFilter(filterRole) {
|
||||
filterRole.setTableName(this.tableName);
|
||||
filterRole.setModel(this.model);
|
||||
this.filters.push(filterRole);
|
||||
}
|
||||
|
||||
@@ -38,7 +43,23 @@ export default class DynamicFilter {
|
||||
buildersCallbacks.forEach((builderCallback) => {
|
||||
builderCallback(builder);
|
||||
});
|
||||
buildFilterRolesJoins(this.tableName, uniqBy(tableColumns, 'columnKey'))(builder);
|
||||
buildFilterRolesJoins(this.model, uniqBy(tableColumns, 'columnKey'))(builder);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve response metadata from all filters adapters.
|
||||
*/
|
||||
getResponseMeta() {
|
||||
const responseMeta = {};
|
||||
|
||||
this.filters.forEach((filter) => {
|
||||
const { responseMeta: filterMeta } = filter;
|
||||
|
||||
forEach(filterMeta, (value, key) => {
|
||||
responseMeta[key] = value;
|
||||
});
|
||||
});
|
||||
return responseMeta;
|
||||
}
|
||||
}
|
||||
@@ -14,14 +14,14 @@ export default class FilterRoles extends DynamicFilterRoleAbstructor {
|
||||
constructor(filterRoles: IFilterRole[]) {
|
||||
super();
|
||||
this.filterRoles = filterRoles;
|
||||
this.setResponseMeta();
|
||||
}
|
||||
|
||||
private buildLogicExpression(): string {
|
||||
let expression = '';
|
||||
this.filterRoles.forEach((role, index) => {
|
||||
expression += (index === 0) ?
|
||||
`${role.index} ` :
|
||||
`${role.condition} ${role.index} `;
|
||||
`${role.index} ` : `${role.condition} ${role.index} `;
|
||||
});
|
||||
return expression.trim();
|
||||
}
|
||||
@@ -32,7 +32,16 @@ export default class FilterRoles extends DynamicFilterRoleAbstructor {
|
||||
buildQuery() {
|
||||
return (builder) => {
|
||||
const logicExpression = this.buildLogicExpression();
|
||||
buildFilterQuery(this.tableName, this.filterRoles, logicExpression)(builder);
|
||||
buildFilterQuery(this.model, this.filterRoles, logicExpression)(builder);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets response meta.
|
||||
*/
|
||||
setResponseMeta() {
|
||||
this.responseMeta = {
|
||||
filterRoles: this.filterRoles
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
import { IFilterRole, IDynamicFilter } from "interfaces";
|
||||
import { IFilterRole, IDynamicFilter, IModel } from "interfaces";
|
||||
|
||||
export default class DynamicFilterAbstructor implements IDynamicFilter {
|
||||
filterRoles: IFilterRole[] = [];
|
||||
tableName: string;
|
||||
model: IModel;
|
||||
responseMeta: { [key: string]: any } = {};
|
||||
|
||||
setTableName(tableName) {
|
||||
this.tableName = tableName;
|
||||
setModel(model: IModel) {
|
||||
this.model = model;
|
||||
this.tableName = model.tableName;
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,11 @@ export default class DynamicFilterSortBy extends DynamicFilterRoleAbstructor {
|
||||
fieldKey: sortByFieldKey,
|
||||
order: sortDirection,
|
||||
};
|
||||
this.setResponseMeta();
|
||||
}
|
||||
|
||||
validate() {
|
||||
validateFieldKeyExistance(this.tableName, this.sortRole.fieldKey);
|
||||
validateFieldKeyExistance(this.model, this.sortRole.fieldKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,7 +28,7 @@ export default class DynamicFilterSortBy extends DynamicFilterRoleAbstructor {
|
||||
*/
|
||||
buildQuery() {
|
||||
return (builder) => {
|
||||
const fieldRelation = getRoleFieldColumn(this.tableName, this.sortRole.fieldKey);
|
||||
const fieldRelation = getRoleFieldColumn(this.model, this.sortRole.fieldKey);
|
||||
const comparatorColumn =
|
||||
fieldRelation.relationColumn ||
|
||||
`${this.tableName}.${fieldRelation.column}`;
|
||||
@@ -37,4 +38,14 @@ export default class DynamicFilterSortBy extends DynamicFilterRoleAbstructor {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets response meta.
|
||||
*/
|
||||
setResponseMeta() {
|
||||
this.responseMeta = {
|
||||
sortOrder: this.sortRole.fieldKey,
|
||||
sortBy: this.sortRole.order,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,29 @@
|
||||
import { IFilterRole } from 'interfaces';
|
||||
import { omit } from 'lodash';
|
||||
import { IView, IViewRole } from 'interfaces';
|
||||
import DynamicFilterRoleAbstructor from 'lib/DynamicFilter/DynamicFilterRoleAbstructor';
|
||||
import {
|
||||
validateViewRoles,
|
||||
buildFilterQuery,
|
||||
} from 'lib/ViewRolesBuilder';
|
||||
|
||||
export default class DynamicFilterViews extends DynamicFilterRoleAbstructor {
|
||||
viewId: number;
|
||||
logicExpression: string;
|
||||
filterRoles: IViewRole[];
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
* @param {*} filterRoles - Filter roles.
|
||||
* @param {*} logicExpression - Logic expression.
|
||||
* @param {IView} view -
|
||||
*/
|
||||
constructor(filterRoles: IFilterRole[], logicExpression: string) {
|
||||
constructor(view: IView) {
|
||||
super();
|
||||
|
||||
this.filterRoles = filterRoles;
|
||||
this.logicExpression = logicExpression
|
||||
this.viewId = view.id;
|
||||
this.filterRoles = view.roles;
|
||||
this.logicExpression = view.rolesLogicExpression
|
||||
.replace('AND', '&&')
|
||||
.replace('OR', '||');
|
||||
|
||||
this.setResponseMeta();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -28,20 +32,27 @@ export default class DynamicFilterViews extends DynamicFilterRoleAbstructor {
|
||||
buildLogicExpression() {
|
||||
return this.logicExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates filter roles.
|
||||
*/
|
||||
validate() {
|
||||
return validateViewRoles(this.filterRoles, this.logicExpression);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds database query of view roles.
|
||||
*/
|
||||
buildQuery() {
|
||||
return (builder) => {
|
||||
buildFilterQuery(this.tableName, this.filterRoles, this.logicExpression)(builder);
|
||||
buildFilterQuery(this.model, this.filterRoles, this.logicExpression)(builder);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets response meta.
|
||||
*/
|
||||
setResponseMeta() {
|
||||
this.responseMeta = {
|
||||
view: {
|
||||
logicExpression: this.logicExpression,
|
||||
filterRoles: this.filterRoles
|
||||
.map((filterRole) => ({ ...omit(filterRole, ['id', 'viewId']) })),
|
||||
customViewId: this.viewId,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
import { difference, filter } from 'lodash';
|
||||
import { difference } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { Lexer } from 'lib/LogicEvaluation/Lexer';
|
||||
import Parser from 'lib/LogicEvaluation/Parser';
|
||||
import QueryParser from 'lib/LogicEvaluation/QueryParser';
|
||||
import resourceFieldsKeys from 'data/ResourceFieldsKeys';
|
||||
import { IFilterRole } from 'interfaces';
|
||||
import { IFilterRole, IModel } from 'interfaces';
|
||||
|
||||
const numberRoleQueryBuilder = (role: IFilterRole, comparatorColumn: string) => {
|
||||
switch (role.comparator) {
|
||||
@@ -93,7 +92,7 @@ const dateQueryBuilder = (role: IFilterRole, comparatorColumn: string) => {
|
||||
if (hasTimeFormat) {
|
||||
const targetDateTime = moment(role.value).format(dateFormat);
|
||||
builder.where(comparatorColumn, '=', targetDateTime);
|
||||
} else {
|
||||
} else {
|
||||
const startDate = moment(role.value).startOf('day');
|
||||
const endDate = moment(role.value).endOf('day');
|
||||
|
||||
@@ -109,19 +108,19 @@ const dateQueryBuilder = (role: IFilterRole, comparatorColumn: string) => {
|
||||
* @param {String} tableName - Table name of target column.
|
||||
* @param {String} fieldKey - Target column key that stored in resource field.
|
||||
*/
|
||||
export function getRoleFieldColumn(tableName: string, fieldKey: string) {
|
||||
const tableFields = resourceFieldsKeys[tableName];
|
||||
export function getRoleFieldColumn(model: IModel, fieldKey: string) {
|
||||
const tableFields = model.fields;
|
||||
return (tableFields[fieldKey]) ? tableFields[fieldKey] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds roles queries.
|
||||
* @param {String} tableName -
|
||||
* @param {IModel} model -
|
||||
* @param {Object} role -
|
||||
*/
|
||||
export function buildRoleQuery(tableName: string, role: IFilterRole) {
|
||||
const fieldRelation = getRoleFieldColumn(tableName, role.fieldKey);
|
||||
const comparatorColumn = fieldRelation.relationColumn || `${tableName}.${fieldRelation.column}`;
|
||||
export function buildRoleQuery(model: IModel, role: IFilterRole) {
|
||||
const fieldRelation = getRoleFieldColumn(model, role.fieldKey);
|
||||
const comparatorColumn = fieldRelation.relationColumn || `${model.tableName}.${fieldRelation.column}`;
|
||||
|
||||
switch (fieldRelation.columnType) {
|
||||
case 'number':
|
||||
@@ -150,26 +149,26 @@ export const getTableFromRelationColumn = (column: string) => {
|
||||
* @param {String} tableName -
|
||||
* @param {Array} roles -
|
||||
*/
|
||||
export function buildFilterRolesJoins(tableName: string, roles: IFilterRole[]) {
|
||||
export function buildFilterRolesJoins(model: IModel, roles: IFilterRole[]) {
|
||||
return (builder) => {
|
||||
roles.forEach((role) => {
|
||||
const fieldColumn = getRoleFieldColumn(tableName, role.fieldKey);
|
||||
const fieldColumn = getRoleFieldColumn(model, role.fieldKey);
|
||||
|
||||
if (fieldColumn.relation) {
|
||||
const joinTable = getTableFromRelationColumn(fieldColumn.relation);
|
||||
builder.join(joinTable, `${tableName}.${fieldColumn.column}`, '=', fieldColumn.relation);
|
||||
builder.join(joinTable, `${model.tableName}.${fieldColumn.column}`, '=', fieldColumn.relation);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export function buildSortColumnJoin(tableName: string, sortColumnKey: string) {
|
||||
export function buildSortColumnJoin(model: IModel, sortColumnKey: string) {
|
||||
return (builder) => {
|
||||
const fieldColumn = getRoleFieldColumn(tableName, sortColumnKey);
|
||||
const fieldColumn = getRoleFieldColumn(model, sortColumnKey);
|
||||
|
||||
if (fieldColumn.relation) {
|
||||
const joinTable = getTableFromRelationColumn(fieldColumn.relation);
|
||||
builder.join(joinTable, `${tableName}.${fieldColumn.column}`, '=', fieldColumn.relation);
|
||||
builder.join(joinTable, `${model.tableName}.${fieldColumn.column}`, '=', fieldColumn.relation);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -180,11 +179,11 @@ export function buildSortColumnJoin(tableName: string, sortColumnKey: string) {
|
||||
* @param {Array} roles -
|
||||
* @return {Function}
|
||||
*/
|
||||
export function buildFilterRolesQuery(tableName: string, roles: IFilterRole[], logicExpression: string = '') {
|
||||
export function buildFilterRolesQuery(model: IModel, roles: IFilterRole[], logicExpression: string = '') {
|
||||
const rolesIndexSet = {};
|
||||
|
||||
roles.forEach((role) => {
|
||||
rolesIndexSet[role.index] = buildRoleQuery(tableName, role);
|
||||
rolesIndexSet[role.index] = buildRoleQuery(model, role);
|
||||
});
|
||||
// Lexer for logic expression.
|
||||
const lexer = new Lexer(logicExpression);
|
||||
@@ -204,9 +203,9 @@ export function buildFilterRolesQuery(tableName: string, roles: IFilterRole[], l
|
||||
* @param {Array} roles -
|
||||
* @param {String} logicExpression -
|
||||
*/
|
||||
export const buildFilterQuery = (tableName: string, roles, logicExpression: string) => {
|
||||
export const buildFilterQuery = (model: IModel, roles: IFilterRole[], logicExpression: string) => {
|
||||
return (builder) => {
|
||||
buildFilterRolesQuery(tableName, roles, logicExpression)(builder);
|
||||
buildFilterRolesQuery(model, roles, logicExpression)(builder);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -240,35 +239,33 @@ export function mapFilterRolesToDynamicFilter(roles) {
|
||||
* @param {String} columnKey -
|
||||
* @param {String} sortDirection -
|
||||
*/
|
||||
export function buildSortColumnQuery(tableName: string, columnKey: string, sortDirection: string) {
|
||||
const fieldRelation = getRoleFieldColumn(tableName, columnKey);
|
||||
const sortColumn = fieldRelation.relation || `${tableName}.${fieldRelation.column}`;
|
||||
export function buildSortColumnQuery(model: IModel, columnKey: string, sortDirection: string) {
|
||||
const fieldRelation = getRoleFieldColumn(model, columnKey);
|
||||
const sortColumn = fieldRelation.relation || `${model.tableName}.${fieldRelation.column}`;
|
||||
|
||||
return (builder) => {
|
||||
builder.orderBy(sortColumn, sortDirection);
|
||||
buildSortColumnJoin(tableName, columnKey)(builder);
|
||||
buildSortColumnJoin(model, columnKey)(builder);
|
||||
};
|
||||
}
|
||||
|
||||
export function validateFilterLogicExpression(logicExpression: string, indexes) {
|
||||
const logicExpIndexes = logicExpression.match(/\d+/g) || [];
|
||||
const diff = !difference(logicExpIndexes.map(Number), indexes).length;
|
||||
const diff = difference(logicExpIndexes.map(Number), indexes);
|
||||
|
||||
return (diff.length > 0) ? false : true;
|
||||
}
|
||||
|
||||
export function validateRolesLogicExpression(logicExpression: string, roles: IFilterRole[]) {
|
||||
return validateFilterLogicExpression(logicExpression, roles.map((r) => r.index));
|
||||
}
|
||||
|
||||
export function validateFieldKeyExistance(tableName: string, fieldKey: string) {
|
||||
if (!resourceFieldsKeys?.[tableName]?.[fieldKey])
|
||||
return fieldKey;
|
||||
else
|
||||
return false;
|
||||
export function validateFieldKeyExistance(model: any, fieldKey: string) {
|
||||
return model?.fields?.[fieldKey] || false;
|
||||
}
|
||||
|
||||
export function validateFilterRolesFieldsExistance(tableName, filterRoles: IFilterRole[]) {
|
||||
export function validateFilterRolesFieldsExistance(model, filterRoles: IFilterRole[]) {
|
||||
return filterRoles.filter((filterRole: IFilterRole) => {
|
||||
return validateFieldKeyExistance(tableName, filterRole.fieldKey);
|
||||
return !validateFieldKeyExistance(model, filterRole.fieldKey);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user