@fibery/expression-utils 9.4.1 → 9.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +17 -1
- package/lib/index.js +6 -1
- package/lib/src/filter-expression/index.d.ts +11 -0
- package/lib/src/filter-expression/index.js +42 -0
- package/lib/src/filter-expression/operatorUtils.d.ts +39 -0
- package/lib/src/filter-expression/operatorUtils.js +174 -0
- package/lib/src/filter-expression/operators.d.ts +3017 -0
- package/lib/src/filter-expression/operators.js +717 -0
- package/lib/src/filter-expression/pattern-match.d.ts +17 -0
- package/lib/src/filter-expression/pattern-match.js +134 -0
- package/lib/src/filter-expression/patternMatchPlaceholders.d.ts +59 -0
- package/lib/src/filter-expression/patternMatchPlaceholders.js +143 -0
- package/lib/src/filter-expression/patternToExpression.d.ts +4 -0
- package/lib/src/filter-expression/patternToExpression.js +49 -0
- package/lib/src/filter-expression/types.d.ts +24 -0
- package/lib/src/filter-expression/types.js +2 -0
- package/lib/src/utils.d.ts +6 -0
- package/lib/src/utils.js +34 -1
- package/lib/src/visitors.d.ts +2 -2
- package/package.json +8 -2
package/lib/index.d.ts
CHANGED
|
@@ -2,5 +2,21 @@ import * as paramsPlaceholders from "./src/params-placeholders";
|
|
|
2
2
|
import * as utils from "./src/utils";
|
|
3
3
|
import * as visitors from "./src/visitors";
|
|
4
4
|
import * as contextVariables from "./src/context-variables";
|
|
5
|
-
|
|
5
|
+
import * as operators from "./src/filter-expression/operators";
|
|
6
|
+
declare const filterExpression: {
|
|
7
|
+
findMatchedFilter: (filterExpression: import("./src/types").Expression, params: import("./src/tsfixme").$TSFixMe, operators: Array<import("./src/filter-expression/types").Operator>, schema: import("@fibery/schema").Schema | null, type: string) => {
|
|
8
|
+
operator: import("./src/filter-expression/types").Operator;
|
|
9
|
+
value: any;
|
|
10
|
+
expression: import("./src/types").Expression | undefined;
|
|
11
|
+
type: string;
|
|
12
|
+
id: string;
|
|
13
|
+
} | null;
|
|
14
|
+
operators: typeof operators;
|
|
15
|
+
convertToExpression: (pattern: any, filterExpression: any, value: any, getNextParamName: any) => {
|
|
16
|
+
expression: any;
|
|
17
|
+
params: {};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export { utils, visitors, paramsPlaceholders, contextVariables, filterExpression };
|
|
6
21
|
export type { Expression, OrderBy, Query, Select, SubQuery, ExpressionVisitor, ExpressionVisitorWithDefault, } from "./src/types";
|
|
22
|
+
export type { Operator, ExpressionToFilterBy } from "./src/filter-expression/types";
|
package/lib/index.js
CHANGED
|
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.contextVariables = exports.paramsPlaceholders = exports.visitors = exports.utils = void 0;
|
|
36
|
+
exports.filterExpression = exports.contextVariables = exports.paramsPlaceholders = exports.visitors = exports.utils = void 0;
|
|
37
37
|
const paramsPlaceholders = __importStar(require("./src/params-placeholders"));
|
|
38
38
|
exports.paramsPlaceholders = paramsPlaceholders;
|
|
39
39
|
const utils = __importStar(require("./src/utils"));
|
|
@@ -42,3 +42,8 @@ const visitors = __importStar(require("./src/visitors"));
|
|
|
42
42
|
exports.visitors = visitors;
|
|
43
43
|
const contextVariables = __importStar(require("./src/context-variables"));
|
|
44
44
|
exports.contextVariables = contextVariables;
|
|
45
|
+
const filter_expression_1 = require("./src/filter-expression");
|
|
46
|
+
const patternToExpression_1 = require("./src/filter-expression/patternToExpression");
|
|
47
|
+
const operators = __importStar(require("./src/filter-expression/operators"));
|
|
48
|
+
const filterExpression = { findMatchedFilter: filter_expression_1.findMatchedFilter, operators, convertToExpression: patternToExpression_1.convertToExpression };
|
|
49
|
+
exports.filterExpression = filterExpression;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Expression } from "../types";
|
|
2
|
+
import { Operator } from "./types";
|
|
3
|
+
import { Schema } from "@fibery/schema";
|
|
4
|
+
import { $TSFixMe } from "../tsfixme";
|
|
5
|
+
export declare const findMatchedFilter: (filterExpression: Expression, params: $TSFixMe, operators: Array<Operator>, schema: Schema | null, type: string) => {
|
|
6
|
+
operator: Operator;
|
|
7
|
+
value: any;
|
|
8
|
+
expression: Expression | undefined;
|
|
9
|
+
type: string;
|
|
10
|
+
id: string;
|
|
11
|
+
} | null;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findMatchedFilter = void 0;
|
|
4
|
+
const pattern_match_1 = require("./pattern-match");
|
|
5
|
+
const uuid_1 = require("uuid");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const findMatchedFilter = (filterExpression, params, operators, schema, type) => {
|
|
8
|
+
if (!schema || !Object.hasOwn(schema.typeObjectsByName, type)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const typeObject = schema.typeObjectsByName[type];
|
|
12
|
+
for (const operator of operators) {
|
|
13
|
+
if (operator.customMatch) {
|
|
14
|
+
const { matchSuccess, value, expression } = operator.customMatch(filterExpression, params, typeObject);
|
|
15
|
+
if (matchSuccess) {
|
|
16
|
+
return { operator, value, expression, type, id: (0, uuid_1.v4)() };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const { matchSuccess, matches } = (0, pattern_match_1.doPatternMatch)(filterExpression, params, operator.pattern, typeObject);
|
|
21
|
+
if (matchSuccess) {
|
|
22
|
+
const paramMatches = matches.filter((x) => x.matchType === ":expression-match-type/param");
|
|
23
|
+
const expressionMatches = matches.filter((x) => x.matchType === ":expression-match-type/expression");
|
|
24
|
+
if (paramMatches.length > 1) {
|
|
25
|
+
throw new errors_1.NotImplementedError(`Operator pattern with several param placeholders`);
|
|
26
|
+
}
|
|
27
|
+
if (expressionMatches.length > 1) {
|
|
28
|
+
throw new errors_1.NotImplementedError(`Operator pattern with several expression placeholders`);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
operator,
|
|
32
|
+
value: paramMatches[0] && paramMatches[0].value,
|
|
33
|
+
expression: expressionMatches[0].value,
|
|
34
|
+
type,
|
|
35
|
+
id: (0, uuid_1.v4)(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
};
|
|
42
|
+
exports.findMatchedFilter = findMatchedFilter;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export function isDateTime(dateString: any): boolean;
|
|
2
|
+
export function getCompareOperatorForDateTime(id: any, title: any, operator: any, compareByStartInterval: any): {
|
|
3
|
+
id: any;
|
|
4
|
+
title: any;
|
|
5
|
+
customMatch: (where: any, params: any, typeObject: any) => {
|
|
6
|
+
matchSuccess: true;
|
|
7
|
+
expression: any;
|
|
8
|
+
value: any;
|
|
9
|
+
} | {
|
|
10
|
+
matchSuccess: boolean;
|
|
11
|
+
expression?: undefined;
|
|
12
|
+
value?: undefined;
|
|
13
|
+
};
|
|
14
|
+
customConvertToWhereExpression: (expression: any, value: any, getNextParamName: any) => {
|
|
15
|
+
expression: any[];
|
|
16
|
+
params: {
|
|
17
|
+
[x: number]: any;
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
type: string;
|
|
21
|
+
};
|
|
22
|
+
export function getWithinOperatorCustomConvertFn(leftPartExcluded: any): (expression: any, value: any, getNextParamName: any) => {
|
|
23
|
+
expression: (string | any[])[];
|
|
24
|
+
params: {
|
|
25
|
+
[x: number]: any;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export function getWithinOperatorCustomMatchFn(fieldPlaceholder: any, leftPartExcluded: any): (where: any, params: any, typeObject: any) => {
|
|
29
|
+
matchSuccess: true;
|
|
30
|
+
expression: any;
|
|
31
|
+
value: {
|
|
32
|
+
withinRangeStart: any;
|
|
33
|
+
withinRangeEnd: any;
|
|
34
|
+
};
|
|
35
|
+
} | {
|
|
36
|
+
matchSuccess: boolean;
|
|
37
|
+
expression?: undefined;
|
|
38
|
+
value?: undefined;
|
|
39
|
+
};
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getWithinOperatorCustomMatchFn = exports.getWithinOperatorCustomConvertFn = exports.getCompareOperatorForDateTime = exports.isDateTime = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const params_placeholders_1 = require("../params-placeholders");
|
|
9
|
+
const pattern_match_1 = require("./pattern-match");
|
|
10
|
+
const patternMatchPlaceholders_1 = require("./patternMatchPlaceholders");
|
|
11
|
+
const isoDateTimeSample = "2018-05-30T07:57:45.190Z";
|
|
12
|
+
const isoDateSample = "2018-05-30";
|
|
13
|
+
// we're considering date as date-time here because of field-convert
|
|
14
|
+
// from date to date-time, it changes field type but not touches constants in query-params
|
|
15
|
+
// so to keep filters and color-coding working we treat date as date-time here
|
|
16
|
+
// and later moment.js parses date string as date-time
|
|
17
|
+
const isDateTime = (dateString) => dateString.length === isoDateTimeSample.length || dateString.length === isoDateSample.length;
|
|
18
|
+
exports.isDateTime = isDateTime;
|
|
19
|
+
const getCompareOperatorForDateTime = (id, title, operator, compareByStartInterval) => ({
|
|
20
|
+
id,
|
|
21
|
+
title,
|
|
22
|
+
customMatch: (where, params, typeObject) => {
|
|
23
|
+
const { matchSuccess, matches: [fieldMatch, paramMatch], } = (0, pattern_match_1.doPatternMatch)(where, params, [
|
|
24
|
+
operator,
|
|
25
|
+
patternMatchPlaceholders_1.dateTimeOrDateTimeRangeExpressionPlaceholder,
|
|
26
|
+
(0, patternMatchPlaceholders_1.getParamPlaceholder)((x) => {
|
|
27
|
+
return params_placeholders_1.paramsPlaceholdersLookup[x] || (lodash_1.default.isString(x) && (0, exports.isDateTime)(x)) || (0, params_placeholders_1.parseRelativeDatePlaceholder)(x);
|
|
28
|
+
}),
|
|
29
|
+
], typeObject);
|
|
30
|
+
if (matchSuccess) {
|
|
31
|
+
const relativeDateInfo = (0, params_placeholders_1.parseRelativeDatePlaceholder)(paramMatch.value);
|
|
32
|
+
if (relativeDateInfo && relativeDateInfo.isStartOfInterval === compareByStartInterval) {
|
|
33
|
+
const value = (0, params_placeholders_1.toRelativeDatePlaceholder)({ ...relativeDateInfo, isStartOfInterval: undefined });
|
|
34
|
+
return { matchSuccess, expression: fieldMatch.value, value };
|
|
35
|
+
}
|
|
36
|
+
else if (params_placeholders_1.paramsPlaceholdersLookup[paramMatch.value]) {
|
|
37
|
+
const value = lodash_1.default.findKey(params_placeholders_1.dateToDateTimeIntervalLookup, (val) => compareByStartInterval ? val.start === paramMatch.value : val.end === paramMatch.value);
|
|
38
|
+
return { matchSuccess, expression: fieldMatch.value, value };
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
return {
|
|
42
|
+
matchSuccess,
|
|
43
|
+
expression: fieldMatch.value,
|
|
44
|
+
value: paramMatch.value,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return { matchSuccess: false };
|
|
49
|
+
},
|
|
50
|
+
customConvertToWhereExpression: (expression, value, getNextParamName) => {
|
|
51
|
+
const dateTimePlaceholders = params_placeholders_1.dateToDateTimeIntervalLookup[value];
|
|
52
|
+
let relativeDateInfo = null;
|
|
53
|
+
if (dateTimePlaceholders) {
|
|
54
|
+
const { start, end } = dateTimePlaceholders;
|
|
55
|
+
const intervalParamName = compareByStartInterval ? start : end;
|
|
56
|
+
return {
|
|
57
|
+
expression: [operator, expression, intervalParamName],
|
|
58
|
+
params: { [intervalParamName]: intervalParamName },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
else if ((relativeDateInfo = (0, params_placeholders_1.parseRelativeDatePlaceholder)(value))) {
|
|
62
|
+
const paramName = (0, params_placeholders_1.toRelativeDatePlaceholder)({
|
|
63
|
+
...relativeDateInfo,
|
|
64
|
+
isStartOfInterval: compareByStartInterval,
|
|
65
|
+
unitForStart: "day",
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
expression: [operator, expression, paramName],
|
|
69
|
+
params: { [paramName]: paramName },
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const dateParamName = getNextParamName();
|
|
74
|
+
return {
|
|
75
|
+
expression: [operator, expression, dateParamName],
|
|
76
|
+
params: { [dateParamName]: value },
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
type: ":operator-type/binary",
|
|
81
|
+
});
|
|
82
|
+
exports.getCompareOperatorForDateTime = getCompareOperatorForDateTime;
|
|
83
|
+
const getWithinRangeParam = ({ withinRangeValue, getNextParamName }) => {
|
|
84
|
+
// check that it's a relative date.
|
|
85
|
+
const withinRangeDateInfo = (0, params_placeholders_1.parseRelativeDatePlaceholder)(withinRangeValue);
|
|
86
|
+
if (withinRangeValue && withinRangeDateInfo) {
|
|
87
|
+
return { key: withinRangeValue, value: withinRangeValue };
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
return { key: getNextParamName(), value: withinRangeValue };
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
const getWithinOperatorCustomConvertFn = (leftPartExcluded) => {
|
|
94
|
+
return (expression, value, getNextParamName) => {
|
|
95
|
+
const { key: startParamKey, value: startParamValue } = getWithinRangeParam({
|
|
96
|
+
withinRangeValue: value.withinRangeStart,
|
|
97
|
+
getNextParamName,
|
|
98
|
+
compareByStartInterval: true,
|
|
99
|
+
});
|
|
100
|
+
const { key: endParamKey, value: endParamValue } = getWithinRangeParam({
|
|
101
|
+
withinRangeValue: value.withinRangeEnd,
|
|
102
|
+
getNextParamName,
|
|
103
|
+
compareByStartInterval: false,
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
// See https://the.fibery.io/SoftDev/bug/The-left-part-of-'is-within'-condition-is-not-included-into-filter-12264
|
|
107
|
+
expression: ["and", [leftPartExcluded ? ">" : ">=", expression, startParamKey], ["<=", expression, endParamKey]],
|
|
108
|
+
params: {
|
|
109
|
+
[startParamKey]: startParamValue,
|
|
110
|
+
[endParamKey]: endParamValue,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
exports.getWithinOperatorCustomConvertFn = getWithinOperatorCustomConvertFn;
|
|
116
|
+
const oldWithinPlaceholderToRelativeDateLookup = {
|
|
117
|
+
// we don't need $start-of-day at all for date. We can omit it, but it won't hurt in general.
|
|
118
|
+
[params_placeholders_1.weekAgoDateParamPlaceholder]: "$start-of-day-1-week-before-now-date",
|
|
119
|
+
[params_placeholders_1.monthAgoDateParamPlaceholder]: "$start-of-day-1-month-before-now-date",
|
|
120
|
+
[params_placeholders_1.yearAgoDateParamPlaceholder]: "$start-of-day-1-year-before-now-date",
|
|
121
|
+
[params_placeholders_1.weekFromNowDateParamPlaceholder]: "$start-of-day-1-week-after-now-date",
|
|
122
|
+
[params_placeholders_1.monthFromNowDateParamPlaceholder]: "$start-of-day-1-month-after-now-date",
|
|
123
|
+
[params_placeholders_1.yearFromNowDateParamPlaceholder]: "$start-of-day-1-year-after-now-date",
|
|
124
|
+
[params_placeholders_1.todayDateParamPlaceholder]: "$end-of-day-0-day-before-now-date",
|
|
125
|
+
[params_placeholders_1.weekAgoStartDateTimeParamPlaceholder]: "$start-of-day-1-week-before-now-date-time",
|
|
126
|
+
[params_placeholders_1.monthAgoStartDateTimeParamPlaceholder]: "$start-of-day-1-month-before-now-date-time",
|
|
127
|
+
[params_placeholders_1.yearAgoStartDateTimeParamPlaceholder]: "$start-of-day-1-year-before-now-date-time",
|
|
128
|
+
[params_placeholders_1.weekFromNowEndDateTimeParamPlaceholder]: "$start-of-day-1-week-after-now-date-time",
|
|
129
|
+
[params_placeholders_1.monthFromNowEndDateTimeParamPlaceholder]: "$start-of-day-1-month-after-now-date-time",
|
|
130
|
+
[params_placeholders_1.yearFromNowEndDateTimeParamPlaceholder]: "$start-of-day-1-year-after-now-date-time",
|
|
131
|
+
[params_placeholders_1.todayEndDateTimeParamPlaceholder]: "$end-of-day-0-day-before-now-date-time",
|
|
132
|
+
};
|
|
133
|
+
const getWithinRangeValue = (paramMatchValue) => {
|
|
134
|
+
if (Object.hasOwn(oldWithinPlaceholderToRelativeDateLookup, paramMatchValue)) {
|
|
135
|
+
return oldWithinPlaceholderToRelativeDateLookup[paramMatchValue];
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
return paramMatchValue;
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const matchWithinOperator = (pattern, where, params, typeObject) => {
|
|
142
|
+
const { matchSuccess, matches: [firstFieldMatch, firstParamMatch, secondFieldMatch, secondParamMatch], } = (0, pattern_match_1.doPatternMatch)(where, params, pattern, typeObject);
|
|
143
|
+
if (matchSuccess && lodash_1.default.isEqual(firstFieldMatch.value, secondFieldMatch.value)) {
|
|
144
|
+
return {
|
|
145
|
+
matchSuccess,
|
|
146
|
+
expression: firstFieldMatch.value,
|
|
147
|
+
value: {
|
|
148
|
+
withinRangeStart: getWithinRangeValue(firstParamMatch.value),
|
|
149
|
+
withinRangeEnd: getWithinRangeValue(secondParamMatch.value),
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
return { matchSuccess: false };
|
|
154
|
+
};
|
|
155
|
+
const getWithinOperatorCustomMatchFn = (fieldPlaceholder, leftPartExcluded) => {
|
|
156
|
+
return (where, params, typeObject) => {
|
|
157
|
+
const match = matchWithinOperator([
|
|
158
|
+
"and",
|
|
159
|
+
[">", fieldPlaceholder, (0, patternMatchPlaceholders_1.getParamPlaceholder)((x) => x !== null)],
|
|
160
|
+
["<=", fieldPlaceholder, (0, patternMatchPlaceholders_1.getParamPlaceholder)((x) => x !== null)],
|
|
161
|
+
], where, params, typeObject);
|
|
162
|
+
if (!match.matchSuccess && !leftPartExcluded) {
|
|
163
|
+
// see https://the.fibery.io/SoftDev/bug/The-left-part-of-'is-within'-condition-is-not-included-into-filter-12264
|
|
164
|
+
// we probably want to have the same for date-time, but then we will intersect with the "match" function of "operatorDateTimeIs".
|
|
165
|
+
return matchWithinOperator([
|
|
166
|
+
"and",
|
|
167
|
+
[">=", fieldPlaceholder, (0, patternMatchPlaceholders_1.getParamPlaceholder)((x) => x !== null)],
|
|
168
|
+
["<=", fieldPlaceholder, (0, patternMatchPlaceholders_1.getParamPlaceholder)((x) => x !== null)],
|
|
169
|
+
], where, params, typeObject);
|
|
170
|
+
}
|
|
171
|
+
return match;
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
exports.getWithinOperatorCustomMatchFn = getWithinOperatorCustomMatchFn;
|