@fibery/expression-utils 1.1.7 → 1.1.8
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/contextVariables.js +0 -1
- package/lib/expression-utils.js +30 -62
- package/lib/paramsPlaceholders.js +0 -4
- package/lib/utils.js +23 -26
- package/lib/visitors.js +27 -49
- package/package.json +8 -9
package/lib/contextVariables.js
CHANGED
|
@@ -6,7 +6,6 @@ var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
|
6
6
|
|
|
7
7
|
const getEntityQueryVariables = schema => {
|
|
8
8
|
const grouped = ___default["default"].groupBy(schema.typeObjects.filter(x => x.isDomain), typeObject => typeObject.pluralTitle);
|
|
9
|
-
|
|
10
9
|
return ___default["default"].flatten(Object.values(grouped).map(group => {
|
|
11
10
|
return group.map(typeObject => ({
|
|
12
11
|
typeObject,
|
package/lib/expression-utils.js
CHANGED
|
@@ -10,11 +10,9 @@ var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
|
|
|
10
10
|
const serializeDate = momentDate => {
|
|
11
11
|
return momentDate.format("YYYY-MM-DD");
|
|
12
12
|
};
|
|
13
|
-
|
|
14
13
|
const serializeDateTime = momentDate => {
|
|
15
14
|
return momentDate.toISOString();
|
|
16
15
|
};
|
|
17
|
-
|
|
18
16
|
const formulaTodayDateParamPlaceholder = "$formula-today-date-placeholder";
|
|
19
17
|
const formulaNowDateTimeParamPlaceholder = "$formula-now-date-time-placeholder";
|
|
20
18
|
const todayDateParamPlaceholder = "$today-date";
|
|
@@ -77,11 +75,9 @@ const paramsPlaceholdersLookup = {
|
|
|
77
75
|
};
|
|
78
76
|
const replacePlaceholdersInParams = params => params && ___default["default"].mapValues(params, (value, key) => {
|
|
79
77
|
const replaceFn = paramsPlaceholdersLookup[key];
|
|
80
|
-
|
|
81
78
|
if (replaceFn) {
|
|
82
79
|
return replaceFn();
|
|
83
80
|
}
|
|
84
|
-
|
|
85
81
|
return value;
|
|
86
82
|
});
|
|
87
83
|
const dateToDateTimeIntervalLookup = {
|
|
@@ -160,20 +156,17 @@ var paramsPlaceholders = {
|
|
|
160
156
|
};
|
|
161
157
|
|
|
162
158
|
function _extends() {
|
|
163
|
-
_extends = Object.assign
|
|
159
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
164
160
|
for (var i = 1; i < arguments.length; i++) {
|
|
165
161
|
var source = arguments[i];
|
|
166
|
-
|
|
167
162
|
for (var key in source) {
|
|
168
163
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
169
164
|
target[key] = source[key];
|
|
170
165
|
}
|
|
171
166
|
}
|
|
172
167
|
}
|
|
173
|
-
|
|
174
168
|
return target;
|
|
175
169
|
};
|
|
176
|
-
|
|
177
170
|
return _extends.apply(this, arguments);
|
|
178
171
|
}
|
|
179
172
|
|
|
@@ -181,15 +174,12 @@ const stringify = x => {
|
|
|
181
174
|
if (x === undefined) {
|
|
182
175
|
return "undefined";
|
|
183
176
|
}
|
|
184
|
-
|
|
185
177
|
return JSON.stringify(x);
|
|
186
178
|
};
|
|
187
|
-
|
|
188
179
|
class NotImplementedError extends Error {
|
|
189
180
|
constructor(value, itemType = undefined) {
|
|
190
181
|
super([`"${stringify(value)}"`, itemType, "is not implemented"].filter(x => x !== undefined).join(" "));
|
|
191
182
|
}
|
|
192
|
-
|
|
193
183
|
}
|
|
194
184
|
|
|
195
185
|
const assertIsValidExpression = expression => {
|
|
@@ -200,55 +190,56 @@ const assertIsValidExpression = expression => {
|
|
|
200
190
|
};
|
|
201
191
|
const dateRangeFunctions = new Set(["q/start", "q/end"]);
|
|
202
192
|
const firstLastFunctions = new Set(["q/first", "q/last"]);
|
|
203
|
-
const collectionOps = new Set(["q/count", "q/count-
|
|
193
|
+
const collectionOps = new Set(["q/count", "q/count-distinsct", "q/sum", "q/min", "q/max", "q/avg", "q/join", "q/first", "q/last"]);
|
|
194
|
+
// [op, left, right]
|
|
204
195
|
// [=, $true, $false]
|
|
205
196
|
// [=, $my-id, ["fibery/id"]]
|
|
197
|
+
const binaryOperations = new Set(["=", "!=", "<", ">", "<=", ">=", "in",
|
|
198
|
+
//asc: obsolete,use q/in
|
|
199
|
+
"q/contains", "q/not-contains", "+", "-", "*", "/", "and", "or",
|
|
200
|
+
//asc: obsolete. use q/and, q/or
|
|
201
|
+
"q/and", "q/or", "q/in", "q/not-in"]);
|
|
206
202
|
|
|
207
|
-
|
|
208
|
-
"q/contains", "q/not-contains", "+", "-", "*", "/", "and", "or", //asc: obsolete. use q/and, q/or
|
|
209
|
-
"q/and", "q/or", "q/in", "q/not-in"]); // TODO: get rid of this. Use visitors everywhere
|
|
210
|
-
|
|
203
|
+
// TODO: get rid of this. Use visitors everywhere
|
|
211
204
|
const naryOperations = new Set(["and", "or", "q/and", "q/or"]);
|
|
212
205
|
const logicalOperators = new Set(["and", "or", "q/and", "q/or"]);
|
|
213
206
|
const relationalOperators = new Set(["=", "!=", "<", ">", "<=", ">="]);
|
|
214
207
|
const mathOperators = new Set(["+", "-", "*", "/", "q/+", "q/-", "q/concat"]);
|
|
215
208
|
const isFunctionCallExpression = expression => expression.length > 1 && ___default["default"].isString(expression[0]) && (expression[0].startsWith("q/") || ["=", "!=", "<", ">", "<=", ">=", "+", "-", "*", "/", "in", "and", "or", "not-in"].includes(expression[0]));
|
|
209
|
+
const fromRootKeyword = "q/from-root";
|
|
210
|
+
const isFromRootFieldExpression = expression => ___default["default"].isArray(expression) && expression[0] === fromRootKeyword;
|
|
216
211
|
const isDateRangeFunctionExpression = expression => (expression.length === 2 || expression.length === 3) && dateRangeFunctions.has(expression[0]) && isFieldExpression(expression[1]);
|
|
217
|
-
const isCollectionFunctionExpression = expression =>
|
|
218
|
-
|
|
212
|
+
const isCollectionFunctionExpression = expression =>
|
|
213
|
+
//expression has length 3 in case of q/join
|
|
214
|
+
(expression.length === 2 || expression.length === 3) && collectionOps.has(expression[0]);
|
|
219
215
|
const isAccessFunctionExpression = expresion => expresion.length === 2 && expresion[0] === "q/access?" && isFieldExpression(expresion[1]);
|
|
220
216
|
const isBinaryExpression = expression => expression.length === 3 && binaryOperations.has(expression[0]);
|
|
221
217
|
const isNaryExpression = expression => expression.length > 1 && naryOperations.has(expression[0]);
|
|
222
218
|
const isVariableExpression = expression => ___default["default"].isString(expression) && expression.startsWith("$");
|
|
223
219
|
const isFieldExpression = expression => Array.isArray(expression) && expression.every(x => !isVariableExpression(x) && !binaryOperations.has(x) && ___default["default"].isString(x));
|
|
224
|
-
const isAxisFieldExpression = expression => isFieldExpression(expression) && expression.length === 1;
|
|
225
220
|
const isQueryExpression = expression => {
|
|
226
221
|
if (___default["default"].isObject(expression) && "q/from" in expression) {
|
|
227
|
-
const fromExpression = expression["q/from"];
|
|
228
|
-
|
|
222
|
+
const fromExpression = expression["q/from"];
|
|
223
|
+
//asc: fromExpression === null for denormalizeSelect for reference collection case
|
|
229
224
|
return fromExpression === null || isFieldExpression(fromExpression);
|
|
230
225
|
}
|
|
231
|
-
|
|
232
226
|
return false;
|
|
233
|
-
};
|
|
227
|
+
};
|
|
228
|
+
// [q/count, [..., collection]]
|
|
234
229
|
// [q/start, [..., range]]
|
|
235
230
|
// [q/end, [..., range]]
|
|
236
231
|
// [q/access?, [..., field-expr]]
|
|
237
|
-
|
|
238
232
|
const isFunctionExpression = expression => {
|
|
239
233
|
if (!Array.isArray(expression)) {
|
|
240
234
|
return false;
|
|
241
235
|
}
|
|
242
|
-
|
|
243
236
|
if (isFieldExpression(expression)) {
|
|
244
237
|
return false;
|
|
245
238
|
} else if (isDateRangeFunctionExpression(expression) || isCollectionFunctionExpression(expression) || isAccessFunctionExpression(expression)) {
|
|
246
239
|
return true;
|
|
247
240
|
}
|
|
248
|
-
|
|
249
241
|
throw new Error("invalid expression:" + JSON.stringify(expression));
|
|
250
242
|
};
|
|
251
|
-
|
|
252
243
|
const collectFieldExpressions = (memo, expression) => {
|
|
253
244
|
if (isVariableExpression(expression)) ; else if (isFunctionCallExpression(expression)) {
|
|
254
245
|
for (const part of expression.slice(1)) {
|
|
@@ -267,7 +258,6 @@ const collectFieldExpressions = (memo, expression) => {
|
|
|
267
258
|
const innerMemo = [];
|
|
268
259
|
expression["q/select"] && collectFieldExpressions(innerMemo, expression["q/select"]);
|
|
269
260
|
expression["q/where"] && collectFieldExpressions(innerMemo, expression["q/where"]);
|
|
270
|
-
|
|
271
261
|
for (const fieldExpression of innerMemo) {
|
|
272
262
|
memo.push([...expression["q/from"], ...fieldExpression]);
|
|
273
263
|
}
|
|
@@ -275,7 +265,6 @@ const collectFieldExpressions = (memo, expression) => {
|
|
|
275
265
|
throw new NotImplementedError(expression, "expression");
|
|
276
266
|
}
|
|
277
267
|
};
|
|
278
|
-
|
|
279
268
|
const extractFieldExpressions = expression => {
|
|
280
269
|
const memo = [];
|
|
281
270
|
collectFieldExpressions(memo, expression);
|
|
@@ -286,6 +275,7 @@ const createExpressionVisitor = visitor => {
|
|
|
286
275
|
const visitorDefault = {
|
|
287
276
|
visitVariableExpression: expression => expression,
|
|
288
277
|
visitFunctionCallExpression: ([fnName, ...args]) => [fnName, ...args.map(x => visitorWithDefault.visitExpression(x))],
|
|
278
|
+
visitFromRootFieldExpression: ([fromRootKeyword, ...rest]) => [fromRootKeyword, ...rest.map(x => visitorWithDefault.visitExpression(x))],
|
|
289
279
|
visitFieldExpression: expression => expression,
|
|
290
280
|
visitOrderByExpression: orderByExpression => orderByExpression.map(x => {
|
|
291
281
|
const [fieldExpression, orderDir] = x;
|
|
@@ -314,6 +304,8 @@ const createExpressionVisitor = visitor => {
|
|
|
314
304
|
throw new NotImplementedError(expression, "expression");
|
|
315
305
|
} else if (isVariableExpression(expression)) {
|
|
316
306
|
return visitorWithDefault.visitVariableExpression(expression, visitorDefault);
|
|
307
|
+
} else if (isFromRootFieldExpression(expression)) {
|
|
308
|
+
return visitorWithDefault.visitFromRootFieldExpression(expression, visitorDefault);
|
|
317
309
|
} else if (isFunctionCallExpression(expression)) {
|
|
318
310
|
return visitorWithDefault.visitFunctionCallExpression(expression, visitorDefault);
|
|
319
311
|
} else if (isFieldExpression(expression)) {
|
|
@@ -338,6 +330,8 @@ var utils = {
|
|
|
338
330
|
relationalOperators: relationalOperators,
|
|
339
331
|
mathOperators: mathOperators,
|
|
340
332
|
isFunctionCallExpression: isFunctionCallExpression,
|
|
333
|
+
fromRootKeyword: fromRootKeyword,
|
|
334
|
+
isFromRootFieldExpression: isFromRootFieldExpression,
|
|
341
335
|
isDateRangeFunctionExpression: isDateRangeFunctionExpression,
|
|
342
336
|
isCollectionFunctionExpression: isCollectionFunctionExpression,
|
|
343
337
|
isAccessFunctionExpression: isAccessFunctionExpression,
|
|
@@ -345,7 +339,6 @@ var utils = {
|
|
|
345
339
|
isNaryExpression: isNaryExpression,
|
|
346
340
|
isVariableExpression: isVariableExpression,
|
|
347
341
|
isFieldExpression: isFieldExpression,
|
|
348
|
-
isAxisFieldExpression: isAxisFieldExpression,
|
|
349
342
|
isQueryExpression: isQueryExpression,
|
|
350
343
|
isFunctionExpression: isFunctionExpression,
|
|
351
344
|
extractFieldExpressions: extractFieldExpressions,
|
|
@@ -361,7 +354,6 @@ const defaultIdsWithNamesOnFieldNotFound = ({
|
|
|
361
354
|
fieldExpressionInNamesTerms: [...fieldExpressionInNamesTerms, fieldId]
|
|
362
355
|
};
|
|
363
356
|
};
|
|
364
|
-
|
|
365
357
|
const visitFieldExpressionForReplaceIdsWithNamesVisitor = ({
|
|
366
358
|
expression,
|
|
367
359
|
typeObject,
|
|
@@ -388,7 +380,6 @@ const visitFieldExpressionForReplaceIdsWithNamesVisitor = ({
|
|
|
388
380
|
currentTypeObject: typeObject,
|
|
389
381
|
fieldExpressionInNamesTerms: []
|
|
390
382
|
});
|
|
391
|
-
|
|
392
383
|
const replaceIdsWithNamesVisitor = (typeObject, onFieldNotFound = defaultIdsWithNamesOnFieldNotFound) => {
|
|
393
384
|
const visitor = createExpressionVisitor({
|
|
394
385
|
visitFieldExpression: expression => visitFieldExpressionForReplaceIdsWithNamesVisitor({
|
|
@@ -408,7 +399,6 @@ const replaceIdsWithNamesVisitor = (typeObject, onFieldNotFound = defaultIdsWith
|
|
|
408
399
|
onFieldNotFound,
|
|
409
400
|
typeObject
|
|
410
401
|
}).currentTypeObject;
|
|
411
|
-
|
|
412
402
|
if (subQueryTypeObject) {
|
|
413
403
|
const subQueryVisitor = replaceIdsWithNamesVisitor(subQueryTypeObject, onFieldNotFound);
|
|
414
404
|
return _extends({}, subQueryExpression, {
|
|
@@ -420,13 +410,11 @@ const replaceIdsWithNamesVisitor = (typeObject, onFieldNotFound = defaultIdsWith
|
|
|
420
410
|
"q/order-by": subQueryVisitor.visitOrderByExpression(orderByExpression)
|
|
421
411
|
} : null);
|
|
422
412
|
}
|
|
423
|
-
|
|
424
413
|
return subQueryExpression;
|
|
425
414
|
}
|
|
426
415
|
});
|
|
427
416
|
return visitor;
|
|
428
417
|
};
|
|
429
|
-
|
|
430
418
|
const defaultNamesWithIdsOnFieldNotFound = ({
|
|
431
419
|
fieldExpressionInIdsTerms,
|
|
432
420
|
field
|
|
@@ -436,7 +424,6 @@ const defaultNamesWithIdsOnFieldNotFound = ({
|
|
|
436
424
|
fieldExpressionInIdsTerms: [...fieldExpressionInIdsTerms, field]
|
|
437
425
|
};
|
|
438
426
|
};
|
|
439
|
-
|
|
440
427
|
const visitFieldExpressionForReplaceNamesWithIdsVisitor = ({
|
|
441
428
|
expression,
|
|
442
429
|
onFieldNotFound,
|
|
@@ -463,7 +450,6 @@ const visitFieldExpressionForReplaceNamesWithIdsVisitor = ({
|
|
|
463
450
|
currentTypeObject: typeObject,
|
|
464
451
|
fieldExpressionInIdsTerms: []
|
|
465
452
|
});
|
|
466
|
-
|
|
467
453
|
const replaceNamesWithIdsVisitor = (typeObject, onFieldNotFound = defaultNamesWithIdsOnFieldNotFound) => {
|
|
468
454
|
const visitor = createExpressionVisitor({
|
|
469
455
|
visitFieldExpression: expression => visitFieldExpressionForReplaceNamesWithIdsVisitor({
|
|
@@ -483,7 +469,6 @@ const replaceNamesWithIdsVisitor = (typeObject, onFieldNotFound = defaultNamesWi
|
|
|
483
469
|
onFieldNotFound,
|
|
484
470
|
typeObject
|
|
485
471
|
}).currentTypeObject;
|
|
486
|
-
|
|
487
472
|
if (subQueryTypeObject) {
|
|
488
473
|
const subQueryVisitor = replaceNamesWithIdsVisitor(subQueryTypeObject, onFieldNotFound);
|
|
489
474
|
return _extends({}, subQueryExpression, {
|
|
@@ -495,7 +480,6 @@ const replaceNamesWithIdsVisitor = (typeObject, onFieldNotFound = defaultNamesWi
|
|
|
495
480
|
"q/order-by": subQueryVisitor.visitOrderByExpression(orderByExpression)
|
|
496
481
|
} : null);
|
|
497
482
|
}
|
|
498
|
-
|
|
499
483
|
return subQueryExpression;
|
|
500
484
|
}
|
|
501
485
|
});
|
|
@@ -505,12 +489,10 @@ const deleteExpressionsWithNotFoundFieldsVisitor = typeObject => {
|
|
|
505
489
|
const visitor = createExpressionVisitor({
|
|
506
490
|
visitFunctionCallExpression: ([fnName, ...args]) => {
|
|
507
491
|
const argsNew = args.map(x => visitor.visitExpression(x)).filter(Boolean);
|
|
508
|
-
|
|
509
492
|
if (logicalOperators.has(fnName)) {
|
|
510
493
|
if (argsNew.length > 0) {
|
|
511
494
|
return argsNew.length === 1 ? argsNew[0] : [fnName, ...argsNew];
|
|
512
495
|
}
|
|
513
|
-
|
|
514
496
|
return null;
|
|
515
497
|
} else {
|
|
516
498
|
return argsNew.length === args.length ? [fnName, ...argsNew] : null;
|
|
@@ -536,10 +518,8 @@ const deleteExpressionsWithNotFoundFieldsVisitor = typeObject => {
|
|
|
536
518
|
"q/order-by": orderByExpression
|
|
537
519
|
} = subQueryExpression;
|
|
538
520
|
const subQueryTypeObject = fromExpression.reduce((typeObject, field) => typeObject && typeObject.fieldObjectsByName.hasOwnProperty(field) ? typeObject.fieldObjectsByName[field].typeObject : null, typeObject);
|
|
539
|
-
|
|
540
521
|
if (subQueryTypeObject) {
|
|
541
522
|
const subQueryVisitor = deleteExpressionsWithNotFoundFieldsVisitor(subQueryTypeObject);
|
|
542
|
-
|
|
543
523
|
const subQueryExpressionNew = ___default["default"].pickBy(_extends({}, subQueryExpression, {
|
|
544
524
|
"q/from": visitor.visitFieldExpression(fromExpression),
|
|
545
525
|
"q/select": subQueryVisitor.visitExpression(selectExpression)
|
|
@@ -548,7 +528,6 @@ const deleteExpressionsWithNotFoundFieldsVisitor = typeObject => {
|
|
|
548
528
|
} : null, orderByExpression ? {
|
|
549
529
|
"q/order-by": subQueryVisitor.visitOrderByExpression(orderByExpression)
|
|
550
530
|
} : null));
|
|
551
|
-
|
|
552
531
|
const {
|
|
553
532
|
"q/select": selectExpressionNew
|
|
554
533
|
} = subQueryExpressionNew;
|
|
@@ -567,22 +546,26 @@ const expressionContainsAggregation = expression => {
|
|
|
567
546
|
const {
|
|
568
547
|
"q/select": selectExpression
|
|
569
548
|
} = queryExpression;
|
|
570
|
-
|
|
571
549
|
if (isCollectionFunctionExpression(selectExpression)) {
|
|
572
550
|
result = true;
|
|
573
551
|
}
|
|
552
|
+
},
|
|
553
|
+
visitFunctionCallExpression: (expression, visitorDefault) => {
|
|
554
|
+
if (firstLastFunctions.has(expression[0])) {
|
|
555
|
+
result = true;
|
|
556
|
+
} else {
|
|
557
|
+
visitorDefault.visitFunctionCallExpression(expression);
|
|
558
|
+
}
|
|
574
559
|
}
|
|
575
560
|
});
|
|
576
561
|
visitor.visitExpression(expression);
|
|
577
562
|
return result;
|
|
578
563
|
};
|
|
579
|
-
|
|
580
564
|
const defaultGetExpressionTypeOnFieldNotFound = () => {
|
|
581
565
|
return {
|
|
582
566
|
currentTypeObject: null
|
|
583
567
|
};
|
|
584
568
|
};
|
|
585
|
-
|
|
586
569
|
const getFieldAccessExpressionTypeObject = ({
|
|
587
570
|
expression,
|
|
588
571
|
typeObject,
|
|
@@ -593,14 +576,12 @@ const getFieldAccessExpressionTypeObject = ({
|
|
|
593
576
|
currentTypeObject
|
|
594
577
|
}, fieldId, index) => {
|
|
595
578
|
const fieldObject = currentTypeObject && currentTypeObject.fieldObjects.find(f => f.id === fieldId);
|
|
596
|
-
|
|
597
579
|
if (fieldObject) {
|
|
598
580
|
if (returnRefTypeInsteadOfId && index === expression.length - 1 && fieldObject.isId) {
|
|
599
581
|
return {
|
|
600
582
|
currentTypeObject
|
|
601
583
|
};
|
|
602
584
|
}
|
|
603
|
-
|
|
604
585
|
return {
|
|
605
586
|
currentTypeObject: fieldObject.typeObject
|
|
606
587
|
};
|
|
@@ -615,9 +596,7 @@ const getFieldAccessExpressionTypeObject = ({
|
|
|
615
596
|
});
|
|
616
597
|
return reduced.currentTypeObject;
|
|
617
598
|
};
|
|
618
|
-
|
|
619
599
|
const UNKNOWN_EXPRESSION_TYPE = "unknown";
|
|
620
|
-
|
|
621
600
|
const getExpressionTypeInternal = ({
|
|
622
601
|
expression,
|
|
623
602
|
typeObject,
|
|
@@ -632,11 +611,9 @@ const getExpressionTypeInternal = ({
|
|
|
632
611
|
},
|
|
633
612
|
visitFunctionCallExpression: function ([fnName, ...args]) {
|
|
634
613
|
const fnMeta = functionsMeta[fnName];
|
|
635
|
-
|
|
636
614
|
if (!fnMeta) {
|
|
637
615
|
throw new Error(`Function meta for "${fnName}" was not provided`);
|
|
638
616
|
}
|
|
639
|
-
|
|
640
617
|
const argTypes = args.map(arg => getExpressionTypeInternal({
|
|
641
618
|
expression: arg,
|
|
642
619
|
typeObject,
|
|
@@ -645,11 +622,9 @@ const getExpressionTypeInternal = ({
|
|
|
645
622
|
returnRefTypeInsteadOfId: false
|
|
646
623
|
}));
|
|
647
624
|
const overload = fnMeta.overloads.find(o => o["arg-types"].every((argType, index) => argTypes[index] === UNKNOWN_EXPRESSION_TYPE || argTypes[index] === argType));
|
|
648
|
-
|
|
649
625
|
if (!overload) {
|
|
650
626
|
throw new Error(`No overload with args ${argTypes.join(",")} found for "${fnName}" in meta`);
|
|
651
627
|
}
|
|
652
|
-
|
|
653
628
|
result = overload["result-type"];
|
|
654
629
|
},
|
|
655
630
|
visitQueryExpression: expression => {
|
|
@@ -663,16 +638,13 @@ const getExpressionTypeInternal = ({
|
|
|
663
638
|
onFieldNotFound,
|
|
664
639
|
returnRefTypeInsteadOfId
|
|
665
640
|
});
|
|
666
|
-
|
|
667
641
|
if (!fromTypeObject) {
|
|
668
642
|
result = null;
|
|
669
643
|
}
|
|
670
|
-
|
|
671
644
|
if (___default["default"].isPlainObject(selectExpression)) {
|
|
672
645
|
if (Object.values(selectExpression).length !== 1) {
|
|
673
646
|
throw new Error(`Cannot determine type of query expression ${JSON.stringify(expression)}`);
|
|
674
647
|
}
|
|
675
|
-
|
|
676
648
|
result = getExpressionTypeInternal({
|
|
677
649
|
expression: Object.values(selectExpression)[0],
|
|
678
650
|
typeObject: fromTypeObject,
|
|
@@ -690,7 +662,6 @@ const getExpressionTypeInternal = ({
|
|
|
690
662
|
});
|
|
691
663
|
}
|
|
692
664
|
},
|
|
693
|
-
|
|
694
665
|
visitFieldExpression(expression) {
|
|
695
666
|
const fieldAccessExpressionTypeObject = getFieldAccessExpressionTypeObject({
|
|
696
667
|
expression,
|
|
@@ -700,12 +671,10 @@ const getExpressionTypeInternal = ({
|
|
|
700
671
|
});
|
|
701
672
|
result = fieldAccessExpressionTypeObject && fieldAccessExpressionTypeObject.name;
|
|
702
673
|
}
|
|
703
|
-
|
|
704
674
|
});
|
|
705
675
|
visitor.visitExpression(expression);
|
|
706
676
|
return result;
|
|
707
677
|
};
|
|
708
|
-
|
|
709
678
|
const getExpressionType = ({
|
|
710
679
|
expression,
|
|
711
680
|
typeObject,
|
|
@@ -734,7 +703,6 @@ var visitors = {
|
|
|
734
703
|
|
|
735
704
|
const getEntityQueryVariables = schema => {
|
|
736
705
|
const grouped = ___default["default"].groupBy(schema.typeObjects.filter(x => x.isDomain), typeObject => typeObject.pluralTitle);
|
|
737
|
-
|
|
738
706
|
return ___default["default"].flatten(Object.values(grouped).map(group => {
|
|
739
707
|
return group.map(typeObject => ({
|
|
740
708
|
typeObject,
|
|
@@ -9,11 +9,9 @@ var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
|
|
|
9
9
|
const serializeDate = momentDate => {
|
|
10
10
|
return momentDate.format("YYYY-MM-DD");
|
|
11
11
|
};
|
|
12
|
-
|
|
13
12
|
const serializeDateTime = momentDate => {
|
|
14
13
|
return momentDate.toISOString();
|
|
15
14
|
};
|
|
16
|
-
|
|
17
15
|
const formulaTodayDateParamPlaceholder = "$formula-today-date-placeholder";
|
|
18
16
|
const formulaNowDateTimeParamPlaceholder = "$formula-now-date-time-placeholder";
|
|
19
17
|
const todayDateParamPlaceholder = "$today-date";
|
|
@@ -76,11 +74,9 @@ const paramsPlaceholdersLookup = {
|
|
|
76
74
|
};
|
|
77
75
|
const replacePlaceholdersInParams = params => params && ___default["default"].mapValues(params, (value, key) => {
|
|
78
76
|
const replaceFn = paramsPlaceholdersLookup[key];
|
|
79
|
-
|
|
80
77
|
if (replaceFn) {
|
|
81
78
|
return replaceFn();
|
|
82
79
|
}
|
|
83
|
-
|
|
84
80
|
return value;
|
|
85
81
|
});
|
|
86
82
|
const dateToDateTimeIntervalLookup = {
|
package/lib/utils.js
CHANGED
|
@@ -6,20 +6,17 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
6
6
|
var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
7
7
|
|
|
8
8
|
function _extends() {
|
|
9
|
-
_extends = Object.assign
|
|
9
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
10
10
|
for (var i = 1; i < arguments.length; i++) {
|
|
11
11
|
var source = arguments[i];
|
|
12
|
-
|
|
13
12
|
for (var key in source) {
|
|
14
13
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
15
14
|
target[key] = source[key];
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
|
-
|
|
20
18
|
return target;
|
|
21
19
|
};
|
|
22
|
-
|
|
23
20
|
return _extends.apply(this, arguments);
|
|
24
21
|
}
|
|
25
22
|
|
|
@@ -27,15 +24,12 @@ const stringify = x => {
|
|
|
27
24
|
if (x === undefined) {
|
|
28
25
|
return "undefined";
|
|
29
26
|
}
|
|
30
|
-
|
|
31
27
|
return JSON.stringify(x);
|
|
32
28
|
};
|
|
33
|
-
|
|
34
29
|
class NotImplementedError extends Error {
|
|
35
30
|
constructor(value, itemType = undefined) {
|
|
36
31
|
super([`"${stringify(value)}"`, itemType, "is not implemented"].filter(x => x !== undefined).join(" "));
|
|
37
32
|
}
|
|
38
|
-
|
|
39
33
|
}
|
|
40
34
|
|
|
41
35
|
const assertIsValidExpression = expression => {
|
|
@@ -46,55 +40,56 @@ const assertIsValidExpression = expression => {
|
|
|
46
40
|
};
|
|
47
41
|
const dateRangeFunctions = new Set(["q/start", "q/end"]);
|
|
48
42
|
const firstLastFunctions = new Set(["q/first", "q/last"]);
|
|
49
|
-
const collectionOps = new Set(["q/count", "q/count-
|
|
43
|
+
const collectionOps = new Set(["q/count", "q/count-distinsct", "q/sum", "q/min", "q/max", "q/avg", "q/join", "q/first", "q/last"]);
|
|
44
|
+
// [op, left, right]
|
|
50
45
|
// [=, $true, $false]
|
|
51
46
|
// [=, $my-id, ["fibery/id"]]
|
|
47
|
+
const binaryOperations = new Set(["=", "!=", "<", ">", "<=", ">=", "in",
|
|
48
|
+
//asc: obsolete,use q/in
|
|
49
|
+
"q/contains", "q/not-contains", "+", "-", "*", "/", "and", "or",
|
|
50
|
+
//asc: obsolete. use q/and, q/or
|
|
51
|
+
"q/and", "q/or", "q/in", "q/not-in"]);
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
"q/contains", "q/not-contains", "+", "-", "*", "/", "and", "or", //asc: obsolete. use q/and, q/or
|
|
55
|
-
"q/and", "q/or", "q/in", "q/not-in"]); // TODO: get rid of this. Use visitors everywhere
|
|
56
|
-
|
|
53
|
+
// TODO: get rid of this. Use visitors everywhere
|
|
57
54
|
const naryOperations = new Set(["and", "or", "q/and", "q/or"]);
|
|
58
55
|
const logicalOperators = new Set(["and", "or", "q/and", "q/or"]);
|
|
59
56
|
const relationalOperators = new Set(["=", "!=", "<", ">", "<=", ">="]);
|
|
60
57
|
const mathOperators = new Set(["+", "-", "*", "/", "q/+", "q/-", "q/concat"]);
|
|
61
58
|
const isFunctionCallExpression = expression => expression.length > 1 && ___default["default"].isString(expression[0]) && (expression[0].startsWith("q/") || ["=", "!=", "<", ">", "<=", ">=", "+", "-", "*", "/", "in", "and", "or", "not-in"].includes(expression[0]));
|
|
59
|
+
const fromRootKeyword = "q/from-root";
|
|
60
|
+
const isFromRootFieldExpression = expression => ___default["default"].isArray(expression) && expression[0] === fromRootKeyword;
|
|
62
61
|
const isDateRangeFunctionExpression = expression => (expression.length === 2 || expression.length === 3) && dateRangeFunctions.has(expression[0]) && isFieldExpression(expression[1]);
|
|
63
|
-
const isCollectionFunctionExpression = expression =>
|
|
64
|
-
|
|
62
|
+
const isCollectionFunctionExpression = expression =>
|
|
63
|
+
//expression has length 3 in case of q/join
|
|
64
|
+
(expression.length === 2 || expression.length === 3) && collectionOps.has(expression[0]);
|
|
65
65
|
const isAccessFunctionExpression = expresion => expresion.length === 2 && expresion[0] === "q/access?" && isFieldExpression(expresion[1]);
|
|
66
66
|
const isBinaryExpression = expression => expression.length === 3 && binaryOperations.has(expression[0]);
|
|
67
67
|
const isNaryExpression = expression => expression.length > 1 && naryOperations.has(expression[0]);
|
|
68
68
|
const isVariableExpression = expression => ___default["default"].isString(expression) && expression.startsWith("$");
|
|
69
69
|
const isFieldExpression = expression => Array.isArray(expression) && expression.every(x => !isVariableExpression(x) && !binaryOperations.has(x) && ___default["default"].isString(x));
|
|
70
|
-
const isAxisFieldExpression = expression => isFieldExpression(expression) && expression.length === 1;
|
|
71
70
|
const isQueryExpression = expression => {
|
|
72
71
|
if (___default["default"].isObject(expression) && "q/from" in expression) {
|
|
73
|
-
const fromExpression = expression["q/from"];
|
|
74
|
-
|
|
72
|
+
const fromExpression = expression["q/from"];
|
|
73
|
+
//asc: fromExpression === null for denormalizeSelect for reference collection case
|
|
75
74
|
return fromExpression === null || isFieldExpression(fromExpression);
|
|
76
75
|
}
|
|
77
|
-
|
|
78
76
|
return false;
|
|
79
|
-
};
|
|
77
|
+
};
|
|
78
|
+
// [q/count, [..., collection]]
|
|
80
79
|
// [q/start, [..., range]]
|
|
81
80
|
// [q/end, [..., range]]
|
|
82
81
|
// [q/access?, [..., field-expr]]
|
|
83
|
-
|
|
84
82
|
const isFunctionExpression = expression => {
|
|
85
83
|
if (!Array.isArray(expression)) {
|
|
86
84
|
return false;
|
|
87
85
|
}
|
|
88
|
-
|
|
89
86
|
if (isFieldExpression(expression)) {
|
|
90
87
|
return false;
|
|
91
88
|
} else if (isDateRangeFunctionExpression(expression) || isCollectionFunctionExpression(expression) || isAccessFunctionExpression(expression)) {
|
|
92
89
|
return true;
|
|
93
90
|
}
|
|
94
|
-
|
|
95
91
|
throw new Error("invalid expression:" + JSON.stringify(expression));
|
|
96
92
|
};
|
|
97
|
-
|
|
98
93
|
const collectFieldExpressions = (memo, expression) => {
|
|
99
94
|
if (isVariableExpression(expression)) ; else if (isFunctionCallExpression(expression)) {
|
|
100
95
|
for (const part of expression.slice(1)) {
|
|
@@ -113,7 +108,6 @@ const collectFieldExpressions = (memo, expression) => {
|
|
|
113
108
|
const innerMemo = [];
|
|
114
109
|
expression["q/select"] && collectFieldExpressions(innerMemo, expression["q/select"]);
|
|
115
110
|
expression["q/where"] && collectFieldExpressions(innerMemo, expression["q/where"]);
|
|
116
|
-
|
|
117
111
|
for (const fieldExpression of innerMemo) {
|
|
118
112
|
memo.push([...expression["q/from"], ...fieldExpression]);
|
|
119
113
|
}
|
|
@@ -121,7 +115,6 @@ const collectFieldExpressions = (memo, expression) => {
|
|
|
121
115
|
throw new NotImplementedError(expression, "expression");
|
|
122
116
|
}
|
|
123
117
|
};
|
|
124
|
-
|
|
125
118
|
const extractFieldExpressions = expression => {
|
|
126
119
|
const memo = [];
|
|
127
120
|
collectFieldExpressions(memo, expression);
|
|
@@ -132,6 +125,7 @@ const createExpressionVisitor = visitor => {
|
|
|
132
125
|
const visitorDefault = {
|
|
133
126
|
visitVariableExpression: expression => expression,
|
|
134
127
|
visitFunctionCallExpression: ([fnName, ...args]) => [fnName, ...args.map(x => visitorWithDefault.visitExpression(x))],
|
|
128
|
+
visitFromRootFieldExpression: ([fromRootKeyword, ...rest]) => [fromRootKeyword, ...rest.map(x => visitorWithDefault.visitExpression(x))],
|
|
135
129
|
visitFieldExpression: expression => expression,
|
|
136
130
|
visitOrderByExpression: orderByExpression => orderByExpression.map(x => {
|
|
137
131
|
const [fieldExpression, orderDir] = x;
|
|
@@ -160,6 +154,8 @@ const createExpressionVisitor = visitor => {
|
|
|
160
154
|
throw new NotImplementedError(expression, "expression");
|
|
161
155
|
} else if (isVariableExpression(expression)) {
|
|
162
156
|
return visitorWithDefault.visitVariableExpression(expression, visitorDefault);
|
|
157
|
+
} else if (isFromRootFieldExpression(expression)) {
|
|
158
|
+
return visitorWithDefault.visitFromRootFieldExpression(expression, visitorDefault);
|
|
163
159
|
} else if (isFunctionCallExpression(expression)) {
|
|
164
160
|
return visitorWithDefault.visitFunctionCallExpression(expression, visitorDefault);
|
|
165
161
|
} else if (isFieldExpression(expression)) {
|
|
@@ -180,12 +176,13 @@ exports.createExpressionVisitor = createExpressionVisitor;
|
|
|
180
176
|
exports.dateRangeFunctions = dateRangeFunctions;
|
|
181
177
|
exports.extractFieldExpressions = extractFieldExpressions;
|
|
182
178
|
exports.firstLastFunctions = firstLastFunctions;
|
|
179
|
+
exports.fromRootKeyword = fromRootKeyword;
|
|
183
180
|
exports.isAccessFunctionExpression = isAccessFunctionExpression;
|
|
184
|
-
exports.isAxisFieldExpression = isAxisFieldExpression;
|
|
185
181
|
exports.isBinaryExpression = isBinaryExpression;
|
|
186
182
|
exports.isCollectionFunctionExpression = isCollectionFunctionExpression;
|
|
187
183
|
exports.isDateRangeFunctionExpression = isDateRangeFunctionExpression;
|
|
188
184
|
exports.isFieldExpression = isFieldExpression;
|
|
185
|
+
exports.isFromRootFieldExpression = isFromRootFieldExpression;
|
|
189
186
|
exports.isFunctionCallExpression = isFunctionCallExpression;
|
|
190
187
|
exports.isFunctionExpression = isFunctionExpression;
|
|
191
188
|
exports.isNaryExpression = isNaryExpression;
|
package/lib/visitors.js
CHANGED
|
@@ -6,20 +6,17 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
|
6
6
|
var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
7
7
|
|
|
8
8
|
function _extends() {
|
|
9
|
-
_extends = Object.assign
|
|
9
|
+
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
10
10
|
for (var i = 1; i < arguments.length; i++) {
|
|
11
11
|
var source = arguments[i];
|
|
12
|
-
|
|
13
12
|
for (var key in source) {
|
|
14
13
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
15
14
|
target[key] = source[key];
|
|
16
15
|
}
|
|
17
16
|
}
|
|
18
17
|
}
|
|
19
|
-
|
|
20
18
|
return target;
|
|
21
19
|
};
|
|
22
|
-
|
|
23
20
|
return _extends.apply(this, arguments);
|
|
24
21
|
}
|
|
25
22
|
|
|
@@ -27,44 +24,47 @@ const stringify = x => {
|
|
|
27
24
|
if (x === undefined) {
|
|
28
25
|
return "undefined";
|
|
29
26
|
}
|
|
30
|
-
|
|
31
27
|
return JSON.stringify(x);
|
|
32
28
|
};
|
|
33
|
-
|
|
34
29
|
class NotImplementedError extends Error {
|
|
35
30
|
constructor(value, itemType = undefined) {
|
|
36
31
|
super([`"${stringify(value)}"`, itemType, "is not implemented"].filter(x => x !== undefined).join(" "));
|
|
37
32
|
}
|
|
38
|
-
|
|
39
33
|
}
|
|
40
34
|
|
|
41
|
-
const
|
|
35
|
+
const firstLastFunctions = new Set(["q/first", "q/last"]);
|
|
36
|
+
const collectionOps = new Set(["q/count", "q/count-distinsct", "q/sum", "q/min", "q/max", "q/avg", "q/join", "q/first", "q/last"]);
|
|
37
|
+
// [op, left, right]
|
|
42
38
|
// [=, $true, $false]
|
|
43
39
|
// [=, $my-id, ["fibery/id"]]
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
"q/contains", "q/not-contains", "+", "-", "*", "/", "and", "or",
|
|
47
|
-
|
|
40
|
+
const binaryOperations = new Set(["=", "!=", "<", ">", "<=", ">=", "in",
|
|
41
|
+
//asc: obsolete,use q/in
|
|
42
|
+
"q/contains", "q/not-contains", "+", "-", "*", "/", "and", "or",
|
|
43
|
+
//asc: obsolete. use q/and, q/or
|
|
44
|
+
"q/and", "q/or", "q/in", "q/not-in"]);
|
|
48
45
|
const logicalOperators = new Set(["and", "or", "q/and", "q/or"]);
|
|
49
46
|
const isFunctionCallExpression = expression => expression.length > 1 && ___default["default"].isString(expression[0]) && (expression[0].startsWith("q/") || ["=", "!=", "<", ">", "<=", ">=", "+", "-", "*", "/", "in", "and", "or", "not-in"].includes(expression[0]));
|
|
50
|
-
const
|
|
51
|
-
|
|
47
|
+
const fromRootKeyword = "q/from-root";
|
|
48
|
+
const isFromRootFieldExpression = expression => ___default["default"].isArray(expression) && expression[0] === fromRootKeyword;
|
|
49
|
+
const isCollectionFunctionExpression = expression =>
|
|
50
|
+
//expression has length 3 in case of q/join
|
|
51
|
+
(expression.length === 2 || expression.length === 3) && collectionOps.has(expression[0]);
|
|
52
52
|
const isVariableExpression = expression => ___default["default"].isString(expression) && expression.startsWith("$");
|
|
53
53
|
const isFieldExpression = expression => Array.isArray(expression) && expression.every(x => !isVariableExpression(x) && !binaryOperations.has(x) && ___default["default"].isString(x));
|
|
54
54
|
const isQueryExpression = expression => {
|
|
55
55
|
if (___default["default"].isObject(expression) && "q/from" in expression) {
|
|
56
|
-
const fromExpression = expression["q/from"];
|
|
57
|
-
|
|
56
|
+
const fromExpression = expression["q/from"];
|
|
57
|
+
//asc: fromExpression === null for denormalizeSelect for reference collection case
|
|
58
58
|
return fromExpression === null || isFieldExpression(fromExpression);
|
|
59
59
|
}
|
|
60
|
-
|
|
61
60
|
return false;
|
|
62
|
-
};
|
|
61
|
+
};
|
|
63
62
|
const createExpressionVisitor = visitor => {
|
|
64
63
|
let visitorWithDefault = null;
|
|
65
64
|
const visitorDefault = {
|
|
66
65
|
visitVariableExpression: expression => expression,
|
|
67
66
|
visitFunctionCallExpression: ([fnName, ...args]) => [fnName, ...args.map(x => visitorWithDefault.visitExpression(x))],
|
|
67
|
+
visitFromRootFieldExpression: ([fromRootKeyword, ...rest]) => [fromRootKeyword, ...rest.map(x => visitorWithDefault.visitExpression(x))],
|
|
68
68
|
visitFieldExpression: expression => expression,
|
|
69
69
|
visitOrderByExpression: orderByExpression => orderByExpression.map(x => {
|
|
70
70
|
const [fieldExpression, orderDir] = x;
|
|
@@ -93,6 +93,8 @@ const createExpressionVisitor = visitor => {
|
|
|
93
93
|
throw new NotImplementedError(expression, "expression");
|
|
94
94
|
} else if (isVariableExpression(expression)) {
|
|
95
95
|
return visitorWithDefault.visitVariableExpression(expression, visitorDefault);
|
|
96
|
+
} else if (isFromRootFieldExpression(expression)) {
|
|
97
|
+
return visitorWithDefault.visitFromRootFieldExpression(expression, visitorDefault);
|
|
96
98
|
} else if (isFunctionCallExpression(expression)) {
|
|
97
99
|
return visitorWithDefault.visitFunctionCallExpression(expression, visitorDefault);
|
|
98
100
|
} else if (isFieldExpression(expression)) {
|
|
@@ -117,7 +119,6 @@ const defaultIdsWithNamesOnFieldNotFound = ({
|
|
|
117
119
|
fieldExpressionInNamesTerms: [...fieldExpressionInNamesTerms, fieldId]
|
|
118
120
|
};
|
|
119
121
|
};
|
|
120
|
-
|
|
121
122
|
const visitFieldExpressionForReplaceIdsWithNamesVisitor = ({
|
|
122
123
|
expression,
|
|
123
124
|
typeObject,
|
|
@@ -144,7 +145,6 @@ const visitFieldExpressionForReplaceIdsWithNamesVisitor = ({
|
|
|
144
145
|
currentTypeObject: typeObject,
|
|
145
146
|
fieldExpressionInNamesTerms: []
|
|
146
147
|
});
|
|
147
|
-
|
|
148
148
|
const replaceIdsWithNamesVisitor = (typeObject, onFieldNotFound = defaultIdsWithNamesOnFieldNotFound) => {
|
|
149
149
|
const visitor = createExpressionVisitor({
|
|
150
150
|
visitFieldExpression: expression => visitFieldExpressionForReplaceIdsWithNamesVisitor({
|
|
@@ -164,7 +164,6 @@ const replaceIdsWithNamesVisitor = (typeObject, onFieldNotFound = defaultIdsWith
|
|
|
164
164
|
onFieldNotFound,
|
|
165
165
|
typeObject
|
|
166
166
|
}).currentTypeObject;
|
|
167
|
-
|
|
168
167
|
if (subQueryTypeObject) {
|
|
169
168
|
const subQueryVisitor = replaceIdsWithNamesVisitor(subQueryTypeObject, onFieldNotFound);
|
|
170
169
|
return _extends({}, subQueryExpression, {
|
|
@@ -176,13 +175,11 @@ const replaceIdsWithNamesVisitor = (typeObject, onFieldNotFound = defaultIdsWith
|
|
|
176
175
|
"q/order-by": subQueryVisitor.visitOrderByExpression(orderByExpression)
|
|
177
176
|
} : null);
|
|
178
177
|
}
|
|
179
|
-
|
|
180
178
|
return subQueryExpression;
|
|
181
179
|
}
|
|
182
180
|
});
|
|
183
181
|
return visitor;
|
|
184
182
|
};
|
|
185
|
-
|
|
186
183
|
const defaultNamesWithIdsOnFieldNotFound = ({
|
|
187
184
|
fieldExpressionInIdsTerms,
|
|
188
185
|
field
|
|
@@ -192,7 +189,6 @@ const defaultNamesWithIdsOnFieldNotFound = ({
|
|
|
192
189
|
fieldExpressionInIdsTerms: [...fieldExpressionInIdsTerms, field]
|
|
193
190
|
};
|
|
194
191
|
};
|
|
195
|
-
|
|
196
192
|
const visitFieldExpressionForReplaceNamesWithIdsVisitor = ({
|
|
197
193
|
expression,
|
|
198
194
|
onFieldNotFound,
|
|
@@ -219,7 +215,6 @@ const visitFieldExpressionForReplaceNamesWithIdsVisitor = ({
|
|
|
219
215
|
currentTypeObject: typeObject,
|
|
220
216
|
fieldExpressionInIdsTerms: []
|
|
221
217
|
});
|
|
222
|
-
|
|
223
218
|
const replaceNamesWithIdsVisitor = (typeObject, onFieldNotFound = defaultNamesWithIdsOnFieldNotFound) => {
|
|
224
219
|
const visitor = createExpressionVisitor({
|
|
225
220
|
visitFieldExpression: expression => visitFieldExpressionForReplaceNamesWithIdsVisitor({
|
|
@@ -239,7 +234,6 @@ const replaceNamesWithIdsVisitor = (typeObject, onFieldNotFound = defaultNamesWi
|
|
|
239
234
|
onFieldNotFound,
|
|
240
235
|
typeObject
|
|
241
236
|
}).currentTypeObject;
|
|
242
|
-
|
|
243
237
|
if (subQueryTypeObject) {
|
|
244
238
|
const subQueryVisitor = replaceNamesWithIdsVisitor(subQueryTypeObject, onFieldNotFound);
|
|
245
239
|
return _extends({}, subQueryExpression, {
|
|
@@ -251,7 +245,6 @@ const replaceNamesWithIdsVisitor = (typeObject, onFieldNotFound = defaultNamesWi
|
|
|
251
245
|
"q/order-by": subQueryVisitor.visitOrderByExpression(orderByExpression)
|
|
252
246
|
} : null);
|
|
253
247
|
}
|
|
254
|
-
|
|
255
248
|
return subQueryExpression;
|
|
256
249
|
}
|
|
257
250
|
});
|
|
@@ -261,12 +254,10 @@ const deleteExpressionsWithNotFoundFieldsVisitor = typeObject => {
|
|
|
261
254
|
const visitor = createExpressionVisitor({
|
|
262
255
|
visitFunctionCallExpression: ([fnName, ...args]) => {
|
|
263
256
|
const argsNew = args.map(x => visitor.visitExpression(x)).filter(Boolean);
|
|
264
|
-
|
|
265
257
|
if (logicalOperators.has(fnName)) {
|
|
266
258
|
if (argsNew.length > 0) {
|
|
267
259
|
return argsNew.length === 1 ? argsNew[0] : [fnName, ...argsNew];
|
|
268
260
|
}
|
|
269
|
-
|
|
270
261
|
return null;
|
|
271
262
|
} else {
|
|
272
263
|
return argsNew.length === args.length ? [fnName, ...argsNew] : null;
|
|
@@ -292,10 +283,8 @@ const deleteExpressionsWithNotFoundFieldsVisitor = typeObject => {
|
|
|
292
283
|
"q/order-by": orderByExpression
|
|
293
284
|
} = subQueryExpression;
|
|
294
285
|
const subQueryTypeObject = fromExpression.reduce((typeObject, field) => typeObject && typeObject.fieldObjectsByName.hasOwnProperty(field) ? typeObject.fieldObjectsByName[field].typeObject : null, typeObject);
|
|
295
|
-
|
|
296
286
|
if (subQueryTypeObject) {
|
|
297
287
|
const subQueryVisitor = deleteExpressionsWithNotFoundFieldsVisitor(subQueryTypeObject);
|
|
298
|
-
|
|
299
288
|
const subQueryExpressionNew = ___default["default"].pickBy(_extends({}, subQueryExpression, {
|
|
300
289
|
"q/from": visitor.visitFieldExpression(fromExpression),
|
|
301
290
|
"q/select": subQueryVisitor.visitExpression(selectExpression)
|
|
@@ -304,7 +293,6 @@ const deleteExpressionsWithNotFoundFieldsVisitor = typeObject => {
|
|
|
304
293
|
} : null, orderByExpression ? {
|
|
305
294
|
"q/order-by": subQueryVisitor.visitOrderByExpression(orderByExpression)
|
|
306
295
|
} : null));
|
|
307
|
-
|
|
308
296
|
const {
|
|
309
297
|
"q/select": selectExpressionNew
|
|
310
298
|
} = subQueryExpressionNew;
|
|
@@ -323,22 +311,26 @@ const expressionContainsAggregation = expression => {
|
|
|
323
311
|
const {
|
|
324
312
|
"q/select": selectExpression
|
|
325
313
|
} = queryExpression;
|
|
326
|
-
|
|
327
314
|
if (isCollectionFunctionExpression(selectExpression)) {
|
|
328
315
|
result = true;
|
|
329
316
|
}
|
|
317
|
+
},
|
|
318
|
+
visitFunctionCallExpression: (expression, visitorDefault) => {
|
|
319
|
+
if (firstLastFunctions.has(expression[0])) {
|
|
320
|
+
result = true;
|
|
321
|
+
} else {
|
|
322
|
+
visitorDefault.visitFunctionCallExpression(expression);
|
|
323
|
+
}
|
|
330
324
|
}
|
|
331
325
|
});
|
|
332
326
|
visitor.visitExpression(expression);
|
|
333
327
|
return result;
|
|
334
328
|
};
|
|
335
|
-
|
|
336
329
|
const defaultGetExpressionTypeOnFieldNotFound = () => {
|
|
337
330
|
return {
|
|
338
331
|
currentTypeObject: null
|
|
339
332
|
};
|
|
340
333
|
};
|
|
341
|
-
|
|
342
334
|
const getFieldAccessExpressionTypeObject = ({
|
|
343
335
|
expression,
|
|
344
336
|
typeObject,
|
|
@@ -349,14 +341,12 @@ const getFieldAccessExpressionTypeObject = ({
|
|
|
349
341
|
currentTypeObject
|
|
350
342
|
}, fieldId, index) => {
|
|
351
343
|
const fieldObject = currentTypeObject && currentTypeObject.fieldObjects.find(f => f.id === fieldId);
|
|
352
|
-
|
|
353
344
|
if (fieldObject) {
|
|
354
345
|
if (returnRefTypeInsteadOfId && index === expression.length - 1 && fieldObject.isId) {
|
|
355
346
|
return {
|
|
356
347
|
currentTypeObject
|
|
357
348
|
};
|
|
358
349
|
}
|
|
359
|
-
|
|
360
350
|
return {
|
|
361
351
|
currentTypeObject: fieldObject.typeObject
|
|
362
352
|
};
|
|
@@ -371,9 +361,7 @@ const getFieldAccessExpressionTypeObject = ({
|
|
|
371
361
|
});
|
|
372
362
|
return reduced.currentTypeObject;
|
|
373
363
|
};
|
|
374
|
-
|
|
375
364
|
const UNKNOWN_EXPRESSION_TYPE = "unknown";
|
|
376
|
-
|
|
377
365
|
const getExpressionTypeInternal = ({
|
|
378
366
|
expression,
|
|
379
367
|
typeObject,
|
|
@@ -388,11 +376,9 @@ const getExpressionTypeInternal = ({
|
|
|
388
376
|
},
|
|
389
377
|
visitFunctionCallExpression: function ([fnName, ...args]) {
|
|
390
378
|
const fnMeta = functionsMeta[fnName];
|
|
391
|
-
|
|
392
379
|
if (!fnMeta) {
|
|
393
380
|
throw new Error(`Function meta for "${fnName}" was not provided`);
|
|
394
381
|
}
|
|
395
|
-
|
|
396
382
|
const argTypes = args.map(arg => getExpressionTypeInternal({
|
|
397
383
|
expression: arg,
|
|
398
384
|
typeObject,
|
|
@@ -401,11 +387,9 @@ const getExpressionTypeInternal = ({
|
|
|
401
387
|
returnRefTypeInsteadOfId: false
|
|
402
388
|
}));
|
|
403
389
|
const overload = fnMeta.overloads.find(o => o["arg-types"].every((argType, index) => argTypes[index] === UNKNOWN_EXPRESSION_TYPE || argTypes[index] === argType));
|
|
404
|
-
|
|
405
390
|
if (!overload) {
|
|
406
391
|
throw new Error(`No overload with args ${argTypes.join(",")} found for "${fnName}" in meta`);
|
|
407
392
|
}
|
|
408
|
-
|
|
409
393
|
result = overload["result-type"];
|
|
410
394
|
},
|
|
411
395
|
visitQueryExpression: expression => {
|
|
@@ -419,16 +403,13 @@ const getExpressionTypeInternal = ({
|
|
|
419
403
|
onFieldNotFound,
|
|
420
404
|
returnRefTypeInsteadOfId
|
|
421
405
|
});
|
|
422
|
-
|
|
423
406
|
if (!fromTypeObject) {
|
|
424
407
|
result = null;
|
|
425
408
|
}
|
|
426
|
-
|
|
427
409
|
if (___default["default"].isPlainObject(selectExpression)) {
|
|
428
410
|
if (Object.values(selectExpression).length !== 1) {
|
|
429
411
|
throw new Error(`Cannot determine type of query expression ${JSON.stringify(expression)}`);
|
|
430
412
|
}
|
|
431
|
-
|
|
432
413
|
result = getExpressionTypeInternal({
|
|
433
414
|
expression: Object.values(selectExpression)[0],
|
|
434
415
|
typeObject: fromTypeObject,
|
|
@@ -446,7 +427,6 @@ const getExpressionTypeInternal = ({
|
|
|
446
427
|
});
|
|
447
428
|
}
|
|
448
429
|
},
|
|
449
|
-
|
|
450
430
|
visitFieldExpression(expression) {
|
|
451
431
|
const fieldAccessExpressionTypeObject = getFieldAccessExpressionTypeObject({
|
|
452
432
|
expression,
|
|
@@ -456,12 +436,10 @@ const getExpressionTypeInternal = ({
|
|
|
456
436
|
});
|
|
457
437
|
result = fieldAccessExpressionTypeObject && fieldAccessExpressionTypeObject.name;
|
|
458
438
|
}
|
|
459
|
-
|
|
460
439
|
});
|
|
461
440
|
visitor.visitExpression(expression);
|
|
462
441
|
return result;
|
|
463
442
|
};
|
|
464
|
-
|
|
465
443
|
const getExpressionType = ({
|
|
466
444
|
expression,
|
|
467
445
|
typeObject,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fibery/expression-utils",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "utils for working with fibery api expressions",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./lib/expression-utils.js",
|
|
@@ -22,27 +22,26 @@
|
|
|
22
22
|
],
|
|
23
23
|
"private": false,
|
|
24
24
|
"dependencies": {
|
|
25
|
+
"@fibery/helpers": "1.0.2",
|
|
25
26
|
"lodash": "4.17.21",
|
|
26
|
-
"moment": "2.20.1"
|
|
27
|
-
"@fibery/helpers": "1.0.2"
|
|
27
|
+
"moment": "2.20.1"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@babel/core": "7.
|
|
31
|
-
"babel-jest": "27.5.1",
|
|
32
|
-
"babel-loader": "8.2.5",
|
|
30
|
+
"@babel/core": "7.20.5",
|
|
33
31
|
"@fibery/babel-preset": "7.2.0",
|
|
34
|
-
"@fibery/eslint-config": "8.
|
|
32
|
+
"@fibery/eslint-config": "8.2.0",
|
|
35
33
|
"jest": "27.5.1",
|
|
36
34
|
"jest-junit": "13.0.0",
|
|
37
35
|
"microbundle": "0.15.0"
|
|
38
36
|
},
|
|
39
37
|
"peerDependencies": {
|
|
40
|
-
"@fibery/schema": "^8.0
|
|
38
|
+
"@fibery/schema": "^8.1.0"
|
|
41
39
|
},
|
|
42
40
|
"scripts": {
|
|
43
41
|
"build": "rm -rf lib && microbundle paramsPlaceholders.js utils.js visitors.js contextVariables.js index.js -o lib -f cjs --no-compress --target node --sourcemap false",
|
|
44
42
|
"test": "node scripts/test.js",
|
|
45
|
-
"test:ci": "yarn test --
|
|
43
|
+
"test:ci": "yarn test --reporters=default --reporters=jest-junit",
|
|
44
|
+
"test:coverage": "yarn test --coverage --coverageDirectory=${JEST_COVERAGE_RESULT_DIR:-$(pwd)}/coverage/expression-utils --reporters=default --reporters=jest-junit",
|
|
46
45
|
"lint": "eslint ."
|
|
47
46
|
},
|
|
48
47
|
"jest": {
|