UNPKG

low-code-service

Version:

to handle workflow execution, handlebars execution and condition execution for low code service

252 lines (226 loc) 5.38 kB
import { get, set, cloneDeep } from 'lodash'; import sift from 'sift'; export const parseBoolean = function(string) { switch (String(string).toLowerCase()) { case 'true': case 'yes': case 'y': case '1': return true; case 'false': case 'no': case 'n': case '0': return false; default: return undefined; } }; export const sanitizeDataForFilters = (dataForFilters, rawConditionData) => { if (!(Array.isArray(rawConditionData) && rawConditionData.length)) { return dataForFilters; } try { const toRet = cloneDeep(dataForFilters); for (const conditionObj of rawConditionData) { if (!conditionObj.type) { continue; } if (conditionObj.type === 'number') { const sanitizedData = Number(get(toRet, conditionObj.field, 0)); set(toRet, conditionObj.field, sanitizedData); } if (conditionObj.type === 'boolean') { const sanitizedData = parseBoolean(get(toRet, conditionObj.field, false)); set(toRet, conditionObj.field, sanitizedData); } } return toRet; } catch (err) { // returning unsanitized data return dataForFilters; } }; export const validateDataUsingFilters = (filters, dataForFilters) => { for (const filter of filters) { const { whenCondition } = filter; let isWhenSatisfied = true; if (whenCondition) { const sanitizedData = sanitizeDataForFilters(dataForFilters, whenCondition); const shifted: any = converterForSIFT(filter); const whenSiftFunc = sift(shifted.when); try { isWhenSatisfied = whenSiftFunc(sanitizedData); } catch (err) { console.log(err); return false; } if (isWhenSatisfied) { return filter; } } } return false; }; function converterForSIFT(obj) { const cloneObj = cloneDeep(obj); //structuredClone(obj); //cloneDeep const { whenOperator, whenCondition } = cloneObj; const filter = {}; if (whenCondition && Array.isArray(whenCondition) && whenCondition.length) { filter['when'] = transform(whenOperator, whenCondition); } const result = filter; return result; } export const RELATIONAL_OPERATORS = { greater_than: { pretty_name: 'Greater Than', query: '$gt', value_required: true, sql_query: '>', }, greater_than_or_equal: { pretty_name: 'Greater than or equal', query: '$gte', value_required: true, sql_query: '>=', }, less_than: { pretty_name: 'Less than', query: '$lt', value_required: true, sql_query: '<', }, less_than_or_equal: { pretty_name: 'Less than or equal', query: '$lte', value_required: true, sql_query: '<=', }, equal_to: { pretty_name: 'Equal to', query: '$eq', value_required: true, sql_query: '=', }, not_equal_to: { pretty_name: 'Not Equal to', query: '$ne', value_required: true, sql_query: '!=', }, should_be_true: { pretty_name: 'Should be TRUE', query: '$eq', value_required: false, default_value: true, sql_query: 'IS TRUE', }, should_be_false: { pretty_name: 'Should be FALSE', query: '$eq', value_required: false, default_value: false, sql_query: 'IS FALSE', }, is_number: { pretty_name: 'Is number', query: '$type', value_required: false, default_value: 'number', }, is_text: { pretty_name: 'Is text', query: '$type', value_required: false, default_value: 'string', }, in: { pretty_name: 'In Array/List', query: '$in', value_required: true, render_type: 'TAG', default_value: [], sql_query: 'IN', }, nin: { pretty_name: 'Not In Array/List', query: '$nin', value_required: true, render_type: 'TAG', default_value: [], sql_query: 'NOT IN', }, is_required: { pretty_name: 'Is required', query: '$nin', value_required: false, default_value: [null, undefined, '', 0], }, regex: { pretty_name: 'Regex', query: '$regex', value_required: true, default_value: null, sql_query: 'LIKE', }, should_exist: { pretty_name: 'Should exist', query: '$exists', value_required: false, default_value: true, sql_query: 'IS NOT NULL', }, should_not_exist: { pretty_name: 'Should not exist', query: '$exists', value_required: false, default_value: false, sql_query: 'IS NULL', }, }; export const LOGICAL_OPERATORS = { AND: '$and', OR: '$or', }; function transform(operator, condition) { let result: any = null; const converter = (conditionObj) => { const { field, relation, value } = conditionObj; const relation_obj = RELATIONAL_OPERATORS[relation]; let relation_str: Object = {}; if (relation_obj.value_required) { relation_str = { [relation_obj.query]: value, }; } else { relation_str = { [relation_obj.query]: relation_obj.default_value, }; } return { [field]: relation_str, }; }; if (!operator) { //single value const validationObj = condition[0]; result = converter(validationObj); } else { //multiple value, operator (whatOperator) is required const requiredOperator = operator; const logicalOperatorCondition: Object = { [requiredOperator]: [], }; for (const validationObj of condition) { const convertedResult = validationObj.is_already_processed ? validationObj : converter(validationObj); if (convertedResult.is_already_processed) { delete convertedResult.is_already_processed; } logicalOperatorCondition[requiredOperator].push(convertedResult); } result = logicalOperatorCondition; } return result; }