WIP Advanced filter.

This commit is contained in:
Ahmed Bouhuolia
2020-03-23 15:11:07 +02:00
parent 58c67ee36e
commit 52f94c30f5
6 changed files with 414 additions and 47 deletions

View File

@@ -0,0 +1,46 @@
import { difference } from 'lodash';
import {
buildFilterQuery,
} from '../ViewRolesBuilder';
export default class FilterRoles {
/**
* Constructor method.
* @param {Array} filterRoles -
* @param {Array} resourceFields -
*/
constructor(tableName, filterRoles, resourceFields) {
this.filterRoles = filterRoles.map((role, index) => ({
...role,
index: index + 1,
columnKey: role.field_key,
}));
this.resourceFields = resourceFields;
this.tableName = tableName;
}
validateFilterRoles() {
const filterFieldsKeys = this.filterRoles.map((r) => r.field_key);
const resourceFieldsKeys = this.resourceFields.map((r) => r.key);
return difference(filterFieldsKeys, resourceFieldsKeys);
}
// @private
buildLogicExpression() {
let expression = '';
this.filterRoles.forEach((role, index) => {
expression += (index === 0)
? `${role.index} ` : `${role.condition} ${role.index} `;
});
return expression.trim();
}
// @public
buildQuery() {
const logicExpression = this.buildLogicExpression();
return (builder) => {
buildFilterQuery(this.tableName, this.filterRoles, logicExpression)(builder);
};
}
}

View File

@@ -5,41 +5,90 @@ import QueryParser from '@/lib/LogicEvaluation/QueryParser';
import resourceFieldsKeys from '@/data/ResourceFieldsKeys';
// const role = {
// compatotor: '',
// value: '',
// columnKey: '',
// columnSlug: '',
// index: 1,
// compatotor: String,
// value: String,
// columnKey: String,
// columnSlug: String,
// index: Number,
// }
export function buildRoleQuery(role) {
const columnName = resourceFieldsKeys[role.columnKey];
/**
* Get field column metadata and its relation with other tables.
* @param {String} tableName - Table name of target column.
* @param {String} columnKey - Target column key that stored in resource field.
*/
export function getRoleFieldColumn(tableName, columnKey) {
const tableFields = resourceFieldsKeys[tableName];
return (tableFields[columnKey]) ? tableFields[columnKey] : null;
}
/**
* Builds roles queries.
* @param {String} tableName -
* @param {Object} role -
*/
export function buildRoleQuery(tableName, role) {
const fieldRelation = getRoleFieldColumn(tableName, role.columnKey);
const comparatorColumn = fieldRelation.relation || `${tableName}.${fieldRelation.column}`;
console.log(comparatorColumn, role.value);
switch (role.comparator) {
case 'equals':
default:
return (builder) => {
builder.where(columnName, role.value);
builder.where(comparatorColumn, role.value);
};
case 'not_equal':
case 'not_equals':
return (builder) => {
builder.whereNot(columnName, role.value);
builder.whereNot(comparatorColumn, role.value);
};
case 'contain':
return (builder) => {
builder.where(comparatorColumn, 'LIKE', `%${role.value}%`);
};
}
}
/**
* Extract relation table name from relation.
* @param {String} column -
* @return {String} - join relation table.
*/
export const getTableFromRelationColumn = (column) => {
const splitedColumn = column.split('.');
return (splitedColumn.length > 0) ? splitedColumn[0] : '';
};
/**
* Builds view roles join queries.
* @param {String} tableName -
* @param {Array} roles -
*/
export function buildFilterRolesJoins(tableName, roles) {
return (builder) => {
roles.forEach((role) => {
const fieldColumn = getRoleFieldColumn(tableName, role.columnKey);
if (fieldColumn.relation) {
const joinTable = getTableFromRelationColumn(fieldColumn.relation);
builder.join(joinTable, `${tableName}.${fieldColumn.column}`, '=', fieldColumn.relation);
}
});
};
}
/**
* Builds database query from stored view roles.
*
* @param {Array} roles -
* @return {Function}
*/
export function viewRolesBuilder(roles, logicExpression = '') {
export function buildFilterRolesQuery(tableName, roles, logicExpression = '') {
const rolesIndexSet = {};
roles.forEach((role) => {
rolesIndexSet[role.index] = buildRoleQuery(role);
rolesIndexSet[role.index] = buildRoleQuery(tableName, role);
});
// Lexer for logic expression.
const lexer = new Lexer(logicExpression);
@@ -54,23 +103,36 @@ export function viewRolesBuilder(roles, logicExpression = '') {
}
/**
* Validates the view logic expression.
* @param {String} logicExpression
* @param {Array} indexes
* Builds filter query for query builder.
* @param {String} tableName -
* @param {Array} roles -
* @param {String} logicExpression -
*/
export function validateViewLogicExpression(logicExpression, indexes) {
export const buildFilterQuery = (tableName, roles, logicExpression) => {
return (builder) => {
buildFilterRolesJoins(tableName, roles)(builder);
buildFilterRolesQuery(tableName, roles, logicExpression)(builder);
};
};
/**
* Validates the view logic expression.
* @param {String} logicExpression -
* @param {Array} indexes -
*/
export function validateFilterLogicExpression(logicExpression, indexes) {
const logicExpIndexes = logicExpression.match(/\d+/g) || [];
return !difference(logicExpIndexes.map(Number), indexes).length;
}
/**
*
* Validates view roles.
* @param {Array} roles -
* @param {String} logicExpression -
* @return {Boolean}
*/
export function validateViewRoles(roles, logicExpression) {
return validateViewLogicExpression(logicExpression, roles.map((r) => r.index));
return validateFilterLogicExpression(logicExpression, roles.map((r) => r.index));
}
/**
@@ -82,7 +144,7 @@ export function mapViewRolesToConditionals(viewRoles) {
return viewRoles.map((viewRole) => ({
comparator: viewRole.comparator,
value: viewRole.value,
columnKey: viewRole.field.columnKey,
columnKey: viewRole.field.key,
slug: viewRole.field.slug,
index: viewRole.index,
}));