@adaptabletools/adaptable
Version:
Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements
359 lines (358 loc) • 13.3 kB
JavaScript
import { isAfter } from 'date-fns';
import { isBefore } from 'date-fns';
import { isEqual } from 'date-fns';
import { ExpressionEvaluationError } from '../../parser/src/ExpressionEvaluationError';
import { getStringValue, getStringValues } from './expressionFunctionUtils';
import { getTypedKeys } from '../Extensions/TypeExtensions';
import { normalizeDateParam } from './dateUtils';
export const booleanExpressionFunctions = {
TRUE: {
handler: () => {
return true;
},
description: 'Returns the boolean value TRUE',
category: 'logical',
returnType: 'boolean',
signatures: ['TRUE'],
examples: ['[column] = TRUE'],
},
FALSE: {
handler: () => {
return false;
},
description: 'Returns the boolean value FALSE',
category: 'logical',
returnType: 'boolean',
signatures: ['FALSE'],
examples: ['[column] = FALSE'],
},
AND: {
handler(args) {
return Boolean(args[0] && args[1]);
},
isHiddenFromMenu: true,
category: 'logical',
description: 'Returns true if both statements are true',
signatures: ['statement AND statement'],
examples: ['[col1] > 5 AND [col2] > 10'],
returnType: 'boolean',
inputs: ['boolean', 'boolean'],
},
OR: {
handler(args) {
return Boolean(args[0] || args[1]);
},
isHiddenFromMenu: true,
category: 'logical',
description: 'Returns true if either statement is true',
signatures: ['statement OR statement'],
examples: ['[col1] > 5 OR [col2] > 10'],
returnType: 'boolean',
inputs: ['boolean', 'boolean'],
},
NOT: {
handler(args) {
return Boolean(!args[0]);
},
isHiddenFromMenu: true,
category: 'logical',
description: 'Returns the negation of a statement',
signatures: ['!statement'],
examples: ['!([col1] > 5 AND [col2] > 10)'],
returnType: 'boolean',
inputs: ['boolean'],
},
EQ: {
handler(args, context) {
if (args[0] instanceof Date && args[1] instanceof Date) {
return isEqual(args[0], args[1]);
}
if (typeof args[0] === 'string' || typeof args[1] === 'string') {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first == second;
}
return args[0] == args[1];
},
isHiddenFromMenu: true,
category: 'comparison',
description: 'Returns true if the 2 (input) values are equal',
signatures: ['value = value', 'EQ(a: value, b: value)'],
examples: ['[col1] = 5', 'EQ([col1], 5)'],
returnType: 'boolean',
inputs: [
['number', 'number'],
['date', 'date'],
['text', 'text'],
['boolean', 'boolean'],
],
},
NEQ: {
handler(args, context) {
if (args[0] instanceof Date && args[1] instanceof Date) {
return !isEqual(args[0], args[1]);
}
if (typeof args[0] === 'string' || typeof args[1] === 'string') {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first != second;
}
return args[0] != args[1];
},
isHiddenFromMenu: true,
category: 'comparison',
description: 'Returns true if the 2 (input) values are NOT equal',
signatures: ['value != value', 'NEQ(a: value, b: value)'],
examples: ['[col1] != 5', 'NEQ([col1], 5)'],
returnType: 'boolean',
inputs: [
['number', 'number'],
['date', 'date'],
['text', 'text'],
['boolean', 'boolean'],
],
},
LT: {
handler(args, context) {
if (args[0] instanceof Date && args[1] instanceof Date) {
return isBefore(args[0], args[1]);
}
if (typeof args[0] === 'string' || typeof args[1] === 'string') {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first < second;
}
return args[0] < args[1];
},
isHiddenFromMenu: true,
category: 'comparison',
description: 'Returns true if the 1st input is less than 2nd input',
signatures: [
'number < number',
'date < date',
'LT(a: number, b: number)',
'LT(a: date, b: date)',
],
examples: ['[col1] < 5', 'LT([col1], 5)'],
returnType: 'boolean',
inputs: [
['number', 'number'],
['date', 'date'],
],
},
LTE: {
handler(args, context) {
if (args[0] instanceof Date && args[1] instanceof Date) {
return isBefore(args[0], args[1]) || isEqual(args[0], args[1]);
}
if (typeof args[0] === 'string' || typeof args[1] === 'string') {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first <= second;
}
return args[0] <= args[1];
},
isHiddenFromMenu: true,
category: 'comparison',
description: 'Returns true if 1st input is less than or equals 2nd input',
signatures: [
'number <= number',
'date <= date',
'LTE(a: number, b: number)',
'LTE(a: date, b: date)',
],
examples: ['[col1] <= 5', 'LTE([col1], 5)'],
returnType: 'boolean',
inputs: [
['number', 'number'],
['date', 'date'],
],
},
GT: {
handler(args, context) {
if (args[0] instanceof Date && args[1] instanceof Date) {
return isAfter(args[0], args[1]);
}
if (typeof args[0] === 'string' || typeof args[1] === 'string') {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first > second;
}
return args[0] > args[1];
},
isHiddenFromMenu: true,
category: 'comparison',
description: 'Returns true if the 1st input is greater than 2nd input',
signatures: [
'number > number',
'date > date',
'GT(a: number, b: number)',
'GT(a: date, b: date)',
],
examples: ['[col1] > 5', 'GT([col1], 5)'],
returnType: 'boolean',
inputs: [
['number', 'number'],
['date', 'date'],
],
},
GTE: {
handler(args, context) {
if (args[0] instanceof Date && args[1] instanceof Date) {
return isAfter(args[0], args[1]) || isEqual(args[0], args[1]);
}
if (typeof args[0] === 'string' || typeof args[1] === 'string') {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first >= second;
}
return args[0] >= args[1];
},
isHiddenFromMenu: true,
category: 'comparison',
description: 'Returns true if 1st input is greater than or equals 2nd input',
signatures: [
'number >= number',
'date >= date',
'GTE(a: number, b: number)',
'GTE(a: date, b: date)',
],
examples: ['[col1] >= 5', 'GTE([col1], 5)'],
returnType: 'boolean',
inputs: [
['number', 'number'],
['date', 'date'],
],
},
BETWEEN: {
handler([input, lower, upper]) {
if (typeof input !== 'number')
throw new ExpressionEvaluationError('BETWEEN', 'arg 1 should be a number');
return input >= lower && input <= upper;
},
category: 'comparison',
description: 'Returns true if 1st input is between 2nd and 3rd inputs',
signatures: ['BETWEEN(input: number, lower: number, upper: number)'],
examples: ['BETWEEN([col1], 10, 30)'],
returnType: 'boolean',
inputs: ['number', 'number', 'number'],
},
IN: {
handler([needle, haystack]) {
return haystack.includes(needle);
},
category: 'comparison',
description: 'Returns true if the left-hand side value is a constituent element of the right-hand side sequence',
signatures: ['values IN (value, value, ...value)'],
examples: ['[col1] IN (5, 10, AVG([col2],[col3]))'],
returnType: 'boolean',
inputs: [
['number', 'number[]'],
// Date is currently not supported in select
// ['date', 'date[]'],
['text', 'text[]'],
],
},
CONTAINS: {
handler(args, context) {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first.indexOf(second) !== -1;
},
category: 'strings',
description: 'Returns true if 1st input contains 2nd input',
signatures: ['CONTAINS(a: string, b: string)'],
examples: ['CONTAINS([col1], "S")'],
returnType: 'boolean',
inputs: ['text', 'text'],
},
STARTS_WITH: {
handler(args, context) {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first.startsWith(second);
},
category: 'strings',
description: 'Returns true if 1st input starts with the 2nd input',
signatures: ['STARTS_WITH(a: string, b: string)'],
examples: ['STARTS_WITH([col1], "S")'],
returnType: 'boolean',
inputs: ['text', 'text'],
},
ENDS_WITH: {
handler(args, context) {
const [first, second] = getStringValues(context, String(args[0]), String(args[1]));
return first.endsWith(second);
},
category: 'strings',
description: 'Returns true if 1st input ends with the 2nd input',
signatures: ['ENDS_WITH(a: string, b: string)'],
examples: ['ENDS_WITH([col1], "S")'],
returnType: 'boolean',
inputs: ['text', 'text'],
},
ANY_CONTAINS: {
handler(args, context) {
const searchTerm = getStringValue(context, String(args[0]));
return context.adaptableApi?.columnApi.getColumns().some((column) => {
const value = context.adaptableApi?.gridApi.getDisplayValueFromRowNode(context.node, column.columnId);
const columnValue = getStringValue(context, String(value));
return columnValue.indexOf(searchTerm) !== -1;
});
},
category: 'strings',
description: 'Returns true if any Column contains input',
signatures: ['ANY_CONTAINS(value)'],
examples: ['ANY_CONTAINS("abc")'],
returnType: 'boolean',
},
IS_NUMERIC: {
handler(args) {
return !isNaN(Number(args[0]));
},
isHiddenFromMenu: false,
description: 'Returns true if input is numeric',
signatures: ['IS_NUMERIC(a: number)'],
examples: ['IS_NUMERIC([columnName])'],
category: 'maths',
returnType: 'boolean',
inputs: ['number'],
},
REGEX: {
handler(args) {
// dont need context as here we always want case insenstivity in the Regex
const firstInput = String(args[0]);
const regex = String(args[1]);
return RegExp(regex).test(firstInput);
},
isHiddenFromMenu: false,
description: 'Returns true if Regular Expression matches',
signatures: ['REGEX(a: string, b: pattern)'],
examples: ['REGEX([col1], "[A-Z]+")'],
inputs: ['text', 'text'],
category: 'strings',
returnType: 'boolean',
},
IS_HOLIDAY: {
handler(args, context) {
const dateToCheck = normalizeDateParam(args[0]);
return context.adaptableApi.calendarApi.isHoliday(dateToCheck);
},
isHiddenFromMenu: false,
description: 'Returns true if input date is a Holiday',
signatures: ['IS_HOLIDAY(a: date)'],
examples: ['IS_HOLIDAY([columnName])'],
category: 'dates',
returnType: 'boolean',
inputs: ['date'],
},
IS_WORKDAY: {
handler(args, context) {
const dateToCheck = normalizeDateParam(args[0]);
return context.adaptableApi.calendarApi.isWorkingDay(dateToCheck);
},
isHiddenFromMenu: false,
description: 'Returns true if input date is a Working Day',
signatures: ['IS_WORKDAY(a: date)'],
examples: ['IS_WORKDAY([columnName])'],
category: 'dates',
returnType: 'boolean',
inputs: ['date'],
},
};
export const booleanExpressionFunctionsNames = getTypedKeys(booleanExpressionFunctions);
export const isBooleanAdaptableQlFunction = (functionName) => {
return booleanExpressionFunctionsNames.includes(functionName);
};