@fibery/expression-utils 9.1.4 → 9.2.0
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/expression-utils.js +50 -1
- package/lib/paramsPlaceholders.js +5 -1
- package/lib/utils.js +45 -0
- package/package.json +5 -5
- package/types.d.ts +10 -1
package/lib/expression-utils.js
CHANGED
|
@@ -127,7 +127,11 @@ const parseRelativeDatePlaceholder = placeholder => {
|
|
|
127
127
|
let unit = relativeDatePlaceholderMatch[2];
|
|
128
128
|
return {
|
|
129
129
|
isStartOfInterval,
|
|
130
|
-
unitForStart:
|
|
130
|
+
unitForStart:
|
|
131
|
+
// Usually the "start" unit is the same as the unit for relative date calculation.
|
|
132
|
+
// e.g. when we calculate the date "1 week ago", we want the beginning of the previous week.
|
|
133
|
+
// But sometimes they are different. We have hardcoded "day" for now, but this can be extended to any unit.
|
|
134
|
+
fullMatch.startsWith("$start-of-day") || fullMatch.startsWith("$end-of-day") ? "day" : isStartOfInterval !== undefined ? unit : undefined,
|
|
131
135
|
amount: Number.parseInt(relativeDatePlaceholderMatch[1]),
|
|
132
136
|
unit,
|
|
133
137
|
isBeforeNow: relativeDatePlaceholderMatch[3] === "before-now",
|
|
@@ -249,6 +253,11 @@ const assertIsValidExpression = expression => {
|
|
|
249
253
|
});
|
|
250
254
|
trace.assert(expression.length > 0, "empty expression does not make any sense");
|
|
251
255
|
};
|
|
256
|
+
const textTypes = ["fibery/text", "fibery/email", "fibery/url", "fibery/emoji"];
|
|
257
|
+
const dateTypes = ["fibery/date", "fibery/date-time"];
|
|
258
|
+
const dateRangeTypes = ["fibery/date-range", "fibery/date-time-range"];
|
|
259
|
+
const convertableDateTypes = ["fibery/date", "fibery/date-range"];
|
|
260
|
+
const numberTypes = ["fibery/int", "fibery/decimal"];
|
|
252
261
|
const dateRangeFunctions = new Set(["q/start", "q/end"]);
|
|
253
262
|
const firstLastFunctions = new Set(["q/first", "q/last"]);
|
|
254
263
|
const collectionOps = new Set(["q/count", "q/count-distinct", "q/sum", "q/min", "q/max", "q/avg", "q/join", "q/first", "q/last"]);
|
|
@@ -313,6 +322,38 @@ const collectFieldExpressions = (memo, expression) => {
|
|
|
313
322
|
throw new NotImplementedError(expression, "expression");
|
|
314
323
|
}
|
|
315
324
|
};
|
|
325
|
+
const getFieldObjectsByFieldExpression = ({
|
|
326
|
+
typeObject,
|
|
327
|
+
expression
|
|
328
|
+
}) => {
|
|
329
|
+
assertIsValidExpression(expression);
|
|
330
|
+
const fieldObjects = [];
|
|
331
|
+
let currentTypeObject = typeObject;
|
|
332
|
+
for (const fieldOrMultiFieldAccess of expression) {
|
|
333
|
+
if (isMultiFieldAccess(fieldOrMultiFieldAccess)) {
|
|
334
|
+
const [multiField, type] = fieldOrMultiFieldAccess;
|
|
335
|
+
const fieldObject = currentTypeObject.fieldObjectsByName[multiField];
|
|
336
|
+
fieldObjects.push(fieldObject);
|
|
337
|
+
const foundField = fieldObject.multiRelatedFieldObjects.find(f => f.holderType === type);
|
|
338
|
+
trace.assert(foundField, "incorrect expression for multi-field");
|
|
339
|
+
currentTypeObject = foundField.holderTypeObject;
|
|
340
|
+
} else {
|
|
341
|
+
const fieldObject = currentTypeObject.fieldObjectsByName[fieldOrMultiFieldAccess];
|
|
342
|
+
fieldObjects.push(fieldObject);
|
|
343
|
+
currentTypeObject = fieldObject.typeObject;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return fieldObjects;
|
|
347
|
+
};
|
|
348
|
+
const getFieldObjectByFieldExpression = (x // TODO: review types. using type assertion now to avoid rewriting half of app
|
|
349
|
+
) => ___default["default"].last(getFieldObjectsByFieldExpression(x));
|
|
350
|
+
const getFieldObjects = (expression, typeObject) => {
|
|
351
|
+
const fieldExpression = extractFieldExpressions(expression)[0];
|
|
352
|
+
return getFieldObjectsByFieldExpression({
|
|
353
|
+
typeObject,
|
|
354
|
+
expression: fieldExpression
|
|
355
|
+
});
|
|
356
|
+
};
|
|
316
357
|
|
|
317
358
|
/** @deprecated
|
|
318
359
|
* This method checks few expression forms, that we do not generate on frontend anymore(field-access shortcut, direct value as parameter).
|
|
@@ -387,6 +428,11 @@ const createExpressionVisitor = visitor => {
|
|
|
387
428
|
var utils = {
|
|
388
429
|
__proto__: null,
|
|
389
430
|
assertIsValidExpression: assertIsValidExpression,
|
|
431
|
+
textTypes: textTypes,
|
|
432
|
+
dateTypes: dateTypes,
|
|
433
|
+
dateRangeTypes: dateRangeTypes,
|
|
434
|
+
convertableDateTypes: convertableDateTypes,
|
|
435
|
+
numberTypes: numberTypes,
|
|
390
436
|
dateRangeFunctions: dateRangeFunctions,
|
|
391
437
|
firstLastFunctions: firstLastFunctions,
|
|
392
438
|
logicalOperators: logicalOperators,
|
|
@@ -405,6 +451,9 @@ var utils = {
|
|
|
405
451
|
isMultiFieldExpression: isMultiFieldExpression,
|
|
406
452
|
isFieldExpression: isFieldExpression,
|
|
407
453
|
isQueryExpression: isQueryExpression,
|
|
454
|
+
getFieldObjectsByFieldExpression: getFieldObjectsByFieldExpression,
|
|
455
|
+
getFieldObjectByFieldExpression: getFieldObjectByFieldExpression,
|
|
456
|
+
getFieldObjects: getFieldObjects,
|
|
408
457
|
extractFieldExpressions: extractFieldExpressions,
|
|
409
458
|
createExpressionVisitor: createExpressionVisitor
|
|
410
459
|
};
|
|
@@ -126,7 +126,11 @@ const parseRelativeDatePlaceholder = placeholder => {
|
|
|
126
126
|
let unit = relativeDatePlaceholderMatch[2];
|
|
127
127
|
return {
|
|
128
128
|
isStartOfInterval,
|
|
129
|
-
unitForStart:
|
|
129
|
+
unitForStart:
|
|
130
|
+
// Usually the "start" unit is the same as the unit for relative date calculation.
|
|
131
|
+
// e.g. when we calculate the date "1 week ago", we want the beginning of the previous week.
|
|
132
|
+
// But sometimes they are different. We have hardcoded "day" for now, but this can be extended to any unit.
|
|
133
|
+
fullMatch.startsWith("$start-of-day") || fullMatch.startsWith("$end-of-day") ? "day" : isStartOfInterval !== undefined ? unit : undefined,
|
|
130
134
|
amount: Number.parseInt(relativeDatePlaceholderMatch[1]),
|
|
131
135
|
unit,
|
|
132
136
|
isBeforeNow: relativeDatePlaceholderMatch[3] === "before-now",
|
package/lib/utils.js
CHANGED
|
@@ -23,6 +23,11 @@ const assertIsValidExpression = expression => {
|
|
|
23
23
|
});
|
|
24
24
|
trace.assert(expression.length > 0, "empty expression does not make any sense");
|
|
25
25
|
};
|
|
26
|
+
const textTypes = ["fibery/text", "fibery/email", "fibery/url", "fibery/emoji"];
|
|
27
|
+
const dateTypes = ["fibery/date", "fibery/date-time"];
|
|
28
|
+
const dateRangeTypes = ["fibery/date-range", "fibery/date-time-range"];
|
|
29
|
+
const convertableDateTypes = ["fibery/date", "fibery/date-range"];
|
|
30
|
+
const numberTypes = ["fibery/int", "fibery/decimal"];
|
|
26
31
|
const dateRangeFunctions = new Set(["q/start", "q/end"]);
|
|
27
32
|
const firstLastFunctions = new Set(["q/first", "q/last"]);
|
|
28
33
|
const collectionOps = new Set(["q/count", "q/count-distinct", "q/sum", "q/min", "q/max", "q/avg", "q/join", "q/first", "q/last"]);
|
|
@@ -87,6 +92,38 @@ const collectFieldExpressions = (memo, expression) => {
|
|
|
87
92
|
throw new NotImplementedError(expression, "expression");
|
|
88
93
|
}
|
|
89
94
|
};
|
|
95
|
+
const getFieldObjectsByFieldExpression = ({
|
|
96
|
+
typeObject,
|
|
97
|
+
expression
|
|
98
|
+
}) => {
|
|
99
|
+
assertIsValidExpression(expression);
|
|
100
|
+
const fieldObjects = [];
|
|
101
|
+
let currentTypeObject = typeObject;
|
|
102
|
+
for (const fieldOrMultiFieldAccess of expression) {
|
|
103
|
+
if (isMultiFieldAccess(fieldOrMultiFieldAccess)) {
|
|
104
|
+
const [multiField, type] = fieldOrMultiFieldAccess;
|
|
105
|
+
const fieldObject = currentTypeObject.fieldObjectsByName[multiField];
|
|
106
|
+
fieldObjects.push(fieldObject);
|
|
107
|
+
const foundField = fieldObject.multiRelatedFieldObjects.find(f => f.holderType === type);
|
|
108
|
+
trace.assert(foundField, "incorrect expression for multi-field");
|
|
109
|
+
currentTypeObject = foundField.holderTypeObject;
|
|
110
|
+
} else {
|
|
111
|
+
const fieldObject = currentTypeObject.fieldObjectsByName[fieldOrMultiFieldAccess];
|
|
112
|
+
fieldObjects.push(fieldObject);
|
|
113
|
+
currentTypeObject = fieldObject.typeObject;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return fieldObjects;
|
|
117
|
+
};
|
|
118
|
+
const getFieldObjectByFieldExpression = (x // TODO: review types. using type assertion now to avoid rewriting half of app
|
|
119
|
+
) => ___default["default"].last(getFieldObjectsByFieldExpression(x));
|
|
120
|
+
const getFieldObjects = (expression, typeObject) => {
|
|
121
|
+
const fieldExpression = extractFieldExpressions(expression)[0];
|
|
122
|
+
return getFieldObjectsByFieldExpression({
|
|
123
|
+
typeObject,
|
|
124
|
+
expression: fieldExpression
|
|
125
|
+
});
|
|
126
|
+
};
|
|
90
127
|
|
|
91
128
|
/** @deprecated
|
|
92
129
|
* This method checks few expression forms, that we do not generate on frontend anymore(field-access shortcut, direct value as parameter).
|
|
@@ -159,11 +196,17 @@ const createExpressionVisitor = visitor => {
|
|
|
159
196
|
};
|
|
160
197
|
|
|
161
198
|
exports.assertIsValidExpression = assertIsValidExpression;
|
|
199
|
+
exports.convertableDateTypes = convertableDateTypes;
|
|
162
200
|
exports.createExpressionVisitor = createExpressionVisitor;
|
|
163
201
|
exports.dateRangeFunctions = dateRangeFunctions;
|
|
202
|
+
exports.dateRangeTypes = dateRangeTypes;
|
|
203
|
+
exports.dateTypes = dateTypes;
|
|
164
204
|
exports.extractFieldExpressions = extractFieldExpressions;
|
|
165
205
|
exports.firstLastFunctions = firstLastFunctions;
|
|
166
206
|
exports.fromRootKeyword = fromRootKeyword;
|
|
207
|
+
exports.getFieldObjectByFieldExpression = getFieldObjectByFieldExpression;
|
|
208
|
+
exports.getFieldObjects = getFieldObjects;
|
|
209
|
+
exports.getFieldObjectsByFieldExpression = getFieldObjectsByFieldExpression;
|
|
167
210
|
exports.isAccessFunctionExpression = isAccessFunctionExpression;
|
|
168
211
|
exports.isBinaryExpression = isBinaryExpression;
|
|
169
212
|
exports.isCollectionFunctionExpression = isCollectionFunctionExpression;
|
|
@@ -178,4 +221,6 @@ exports.isQueryExpression = isQueryExpression;
|
|
|
178
221
|
exports.isVariableExpression = isVariableExpression;
|
|
179
222
|
exports.logicalOperators = logicalOperators;
|
|
180
223
|
exports.mathOperators = mathOperators;
|
|
224
|
+
exports.numberTypes = numberTypes;
|
|
181
225
|
exports.relationalOperators = relationalOperators;
|
|
226
|
+
exports.textTypes = textTypes;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/expression-utils",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.2.0",
|
|
4
4
|
"description": "utils for working with fibery api expressions",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./lib/expression-utils.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"lodash": "4.17.21",
|
|
28
28
|
"moment": "2.29.4",
|
|
29
|
-
"@fibery/helpers": "1.3.
|
|
29
|
+
"@fibery/helpers": "1.3.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@babel/core": "7.23.9",
|
|
@@ -34,11 +34,11 @@
|
|
|
34
34
|
"jest": "27.5.1",
|
|
35
35
|
"jest-junit": "13.0.0",
|
|
36
36
|
"microbundle": "0.15.1",
|
|
37
|
-
"@fibery/
|
|
38
|
-
"@fibery/
|
|
37
|
+
"@fibery/babel-preset": "7.4.0",
|
|
38
|
+
"@fibery/eslint-config": "8.6.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"@fibery/schema": "10.2.
|
|
41
|
+
"@fibery/schema": "10.2.7"
|
|
42
42
|
},
|
|
43
43
|
"jest": {
|
|
44
44
|
"testEnvironment": "node",
|
package/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
-
import {Schema, TypeObject
|
|
2
|
+
import {FieldObject, Schema, TypeObject} from "@fibery/schema";
|
|
3
3
|
|
|
4
4
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
5
|
export type $TSFixMe = any;
|
|
@@ -61,6 +61,14 @@ declare module "@fibery/expression-utils" {
|
|
|
61
61
|
firstLastFunctions: Set<string>;
|
|
62
62
|
isQueryExpression: (expression: $TSFixMe) => boolean;
|
|
63
63
|
isVariableExpression: (expression: $TSFixMe) => boolean;
|
|
64
|
+
isFunctionCallExpression: (expression: $TSFixMe) => boolean;
|
|
65
|
+
getFieldObjectByFieldExpression: (x: {typeObject: TypeObject; expression: Expression}) => FieldObject | undefined;
|
|
66
|
+
isFieldExpression: (expression: $TSFixMe) => boolean;
|
|
67
|
+
isBinaryExpression: (expression: $TSFixMe) => boolean;
|
|
68
|
+
isMultiFieldAccess: (expression: $TSFixMe) => boolean;
|
|
69
|
+
logicalOperators: Set<string>;
|
|
70
|
+
relationalOperators: Set<string>;
|
|
71
|
+
mathOperators: Set<string>;
|
|
64
72
|
};
|
|
65
73
|
export const contextVariables: {
|
|
66
74
|
getEntityQueryVariables: (
|
|
@@ -69,6 +77,7 @@ declare module "@fibery/expression-utils" {
|
|
|
69
77
|
};
|
|
70
78
|
export const paramsPlaceholders: {
|
|
71
79
|
formulaTodayDateParamPlaceholder: string;
|
|
80
|
+
formulaNowDateTimeParamPlaceholder: string;
|
|
72
81
|
dynamicFilterParamPrefix: string;
|
|
73
82
|
|
|
74
83
|
isDynamicFilterParam(paramValue: string): boolean;
|