@tellaro/tql 4.0.3 → 5.0.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/dist/index.js +72 -64
- package/dist/src/completionProvider.js +73 -75
- package/dist/src/index.d.ts +2 -1
- package/dist/src/ordering.d.ts +32 -0
- package/dist/src/ordering.js +141 -0
- package/dist/src/types.d.ts +22 -2
- package/dist/src/validator.d.ts +14 -12
- package/dist/src/validator.js +127 -107
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,90 +1,98 @@
|
|
|
1
|
-
import { AGGREGATION_FUNCTIONS as t, BOOLEAN_PREDICATE_MUTATORS as o, BOOLEAN_PREDICATE_MUTATOR_SET as i, COLLECTION_OPERATORS as T, COMPARISON_OPERATORS as a, DATE_HISTOGRAM_CALENDAR_INTERVALS as E, DATE_HISTOGRAM_FIXED_UNITS as
|
|
2
|
-
import { TqlParser as f, dateHistogramIntervalProblem as h, formatParseError as x, geoPrecisionProblem as
|
|
3
|
-
import { CASE_SENSITIVE_MEMBERSHIP_OPERATORS as V, CASE_SENSITIVE_OPERATORS as
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
1
|
+
import { AGGREGATION_FUNCTIONS as t, BOOLEAN_PREDICATE_MUTATORS as o, BOOLEAN_PREDICATE_MUTATOR_SET as i, COLLECTION_OPERATORS as T, COMPARISON_OPERATORS as a, DATE_HISTOGRAM_CALENDAR_INTERVALS as E, DATE_HISTOGRAM_FIXED_UNITS as O, GEO_GRID_PRECISION as S, GROUP_BY_BUCKET_FUNCTIONS as l, KEYWORDS as R, LOGICAL_OPERATORS as _, MUTATORS as n, NEGATION_SYMBOL_OPERATORS as A, SYMBOL_OPERATORS as s, TYPE_HINTS as g, TqlTokenizer as m, VISUALIZATION_TYPES as I, findPreviousToken as P, findTokenAtPosition as N, findTokenBefore as C, findTokensInRange as c, tokenizeTql as d, tokenizeTqlNoWhitespace as p } from "./src/tokenizer.js";
|
|
2
|
+
import { TqlParser as f, dateHistogramIntervalProblem as h, formatParseError as x, geoPrecisionProblem as M, getTqlErrors as U, isValidTql as u, parseTql as y, rangeBoundariesProblem as D } from "./src/parser.js";
|
|
3
|
+
import { CASE_SENSITIVE_MEMBERSHIP_OPERATORS as V, CASE_SENSITIVE_OPERATORS as q, CASE_SENSITIVE_WHOLE_VALUE_OPERATORS as z, MAX_REGEX_PATTERN_LENGTH as F, TqlValidator as Y, casePreservingForm as B, caseSensitiveSupport as H, formatValidationResult as k, getTqlIssues as v, isValidTqlSyntax as b, validateTql as Q } from "./src/validator.js";
|
|
4
|
+
import { ORDERABLE_FIELD_TYPES as X, ORDERING_OPERATORS as K, checkOrderingComparison as w, isOrderingOperator as Z, literalIsOrderable as j, orderingRefusalMessage as J, orderingVerdict as $ } from "./src/ordering.js";
|
|
5
|
+
import { getCompletionTriggerCharacters as re, getCompletions as te, getWordAtPosition as oe, shouldTriggerCompletion as ie } from "./src/completionProvider.js";
|
|
6
|
+
import { findClosestMatch as ae, fuzzyFilter as Ee, fuzzyMatch as Oe, highlightMatch as Se, levenshteinDistance as le } from "./src/fuzzyMatcher.js";
|
|
7
|
+
import { SchemaCache as _e, createSchemaCache as ne, getCachedField as Ae, getCachedFieldNames as se, getCachedFieldType as ge, getSchemaCache as me } from "./src/schemaCache.js";
|
|
8
|
+
import { ComplexityAnalyzer as Pe, analyzeComplexity as Ne, getComplexityMetrics as Ce, getComplexityWarnings as ce, isHighComplexity as de } from "./src/complexityAnalyzer.js";
|
|
9
|
+
import { SemanticPreview as Le, flattenLogicTree as fe, formatLogicTreeAscii as he, formatLogicTreeNode as xe, generatePreview as Me, getFieldUsage as Ue, getLogicTree as ue, getLogicTreeDepth as ye, getOperatorSummary as De, getUniqueFields as Ge } from "./src/semanticPreview.js";
|
|
10
|
+
import { buildStatsQuery as qe, parseVizHintString as ze } from "./src/builder.js";
|
|
11
|
+
import { QUERY_PLAN_EXPLAIN_KEYS as Ye, QUERY_PLAN_EXPLAIN_VERSION as Be, QUERY_PLAN_RULES as He, summarizeQueryPlan as ke } from "./src/queryPlan.js";
|
|
11
12
|
export {
|
|
12
13
|
t as AGGREGATION_FUNCTIONS,
|
|
13
14
|
o as BOOLEAN_PREDICATE_MUTATORS,
|
|
14
15
|
i as BOOLEAN_PREDICATE_MUTATOR_SET,
|
|
15
16
|
V as CASE_SENSITIVE_MEMBERSHIP_OPERATORS,
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
q as CASE_SENSITIVE_OPERATORS,
|
|
18
|
+
z as CASE_SENSITIVE_WHOLE_VALUE_OPERATORS,
|
|
18
19
|
T as COLLECTION_OPERATORS,
|
|
19
20
|
a as COMPARISON_OPERATORS,
|
|
20
|
-
|
|
21
|
+
Pe as ComplexityAnalyzer,
|
|
21
22
|
E as DATE_HISTOGRAM_CALENDAR_INTERVALS,
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
O as DATE_HISTOGRAM_FIXED_UNITS,
|
|
24
|
+
S as GEO_GRID_PRECISION,
|
|
24
25
|
l as GROUP_BY_BUCKET_FUNCTIONS,
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
R as KEYWORDS,
|
|
27
|
+
_ as LOGICAL_OPERATORS,
|
|
27
28
|
F as MAX_REGEX_PATTERN_LENGTH,
|
|
28
29
|
n as MUTATORS,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
A as NEGATION_SYMBOL_OPERATORS,
|
|
31
|
+
X as ORDERABLE_FIELD_TYPES,
|
|
32
|
+
K as ORDERING_OPERATORS,
|
|
33
|
+
Ye as QUERY_PLAN_EXPLAIN_KEYS,
|
|
34
|
+
Be as QUERY_PLAN_EXPLAIN_VERSION,
|
|
35
|
+
He as QUERY_PLAN_RULES,
|
|
33
36
|
s as SYMBOL_OPERATORS,
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
_e as SchemaCache,
|
|
38
|
+
Le as SemanticPreview,
|
|
36
39
|
g as TYPE_HINTS,
|
|
37
40
|
f as TqlParser,
|
|
38
41
|
m as TqlTokenizer,
|
|
39
42
|
Y as TqlValidator,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
I as VISUALIZATION_TYPES,
|
|
44
|
+
Ne as analyzeComplexity,
|
|
45
|
+
qe as buildStatsQuery,
|
|
43
46
|
B as casePreservingForm,
|
|
44
47
|
H as caseSensitiveSupport,
|
|
45
|
-
|
|
48
|
+
w as checkOrderingComparison,
|
|
49
|
+
ne as createSchemaCache,
|
|
46
50
|
h as dateHistogramIntervalProblem,
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
ae as findClosestMatch,
|
|
52
|
+
P as findPreviousToken,
|
|
49
53
|
N as findTokenAtPosition,
|
|
50
54
|
C as findTokenBefore,
|
|
51
55
|
c as findTokensInRange,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
fe as flattenLogicTree,
|
|
57
|
+
he as formatLogicTreeAscii,
|
|
58
|
+
xe as formatLogicTreeNode,
|
|
55
59
|
x as formatParseError,
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
60
|
+
k as formatValidationResult,
|
|
61
|
+
Ee as fuzzyFilter,
|
|
62
|
+
Oe as fuzzyMatch,
|
|
63
|
+
Me as generatePreview,
|
|
64
|
+
M as geoPrecisionProblem,
|
|
65
|
+
Ae as getCachedField,
|
|
66
|
+
se as getCachedFieldNames,
|
|
67
|
+
ge as getCachedFieldType,
|
|
68
|
+
re as getCompletionTriggerCharacters,
|
|
69
|
+
te as getCompletions,
|
|
70
|
+
Ce as getComplexityMetrics,
|
|
71
|
+
ce as getComplexityWarnings,
|
|
72
|
+
Ue as getFieldUsage,
|
|
73
|
+
ue as getLogicTree,
|
|
74
|
+
ye as getLogicTreeDepth,
|
|
75
|
+
De as getOperatorSummary,
|
|
76
|
+
me as getSchemaCache,
|
|
77
|
+
U as getTqlErrors,
|
|
78
|
+
v as getTqlIssues,
|
|
79
|
+
Ge as getUniqueFields,
|
|
80
|
+
oe as getWordAtPosition,
|
|
81
|
+
Se as highlightMatch,
|
|
82
|
+
de as isHighComplexity,
|
|
83
|
+
Z as isOrderingOperator,
|
|
79
84
|
u as isValidTql,
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
b as isValidTqlSyntax,
|
|
86
|
+
le as levenshteinDistance,
|
|
87
|
+
j as literalIsOrderable,
|
|
88
|
+
J as orderingRefusalMessage,
|
|
89
|
+
$ as orderingVerdict,
|
|
82
90
|
y as parseTql,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
ze as parseVizHintString,
|
|
92
|
+
D as rangeBoundariesProblem,
|
|
93
|
+
ie as shouldTriggerCompletion,
|
|
94
|
+
ke as summarizeQueryPlan,
|
|
95
|
+
d as tokenizeTql,
|
|
96
|
+
p as tokenizeTqlNoWhitespace,
|
|
97
|
+
Q as validateTql
|
|
90
98
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { BOOLEAN_PREDICATE_MUTATORS as E, tokenizeTql as T, COMPARISON_OPERATORS as
|
|
2
|
-
import { fuzzyMatch as
|
|
1
|
+
import { BOOLEAN_PREDICATE_MUTATORS as E, tokenizeTql as T, COMPARISON_OPERATORS as $, LOGICAL_OPERATORS as R, GROUP_BY_BUCKET_FUNCTIONS as P, AGGREGATION_FUNCTIONS as D, VISUALIZATION_TYPES as M, TYPE_HINTS as z, MUTATORS as U } from "./tokenizer.js";
|
|
2
|
+
import { fuzzyMatch as v } from "./fuzzyMatcher.js";
|
|
3
3
|
import { getSchemaCache as I } from "./schemaCache.js";
|
|
4
|
-
import { ALL_FIELD_TYPES as
|
|
4
|
+
import { ALL_FIELD_TYPES as c, BETWEEN_FIELD_TYPES as w, ORDERED_FIELD_TYPES as f } from "./validator.js";
|
|
5
5
|
const F = [
|
|
6
6
|
{
|
|
7
7
|
label: "Simple equality",
|
|
@@ -105,24 +105,24 @@ const F = [
|
|
|
105
105
|
description: "Top 10 results by count",
|
|
106
106
|
category: "Stats"
|
|
107
107
|
}
|
|
108
|
-
],
|
|
108
|
+
], q = {
|
|
109
109
|
eq: { detail: "Equals", documentation: "Exact match comparison" },
|
|
110
110
|
ne: { detail: "Not equals", documentation: "Match any value except this one" },
|
|
111
111
|
gt: {
|
|
112
112
|
detail: "Greater than",
|
|
113
|
-
documentation: "Ordered comparison
|
|
113
|
+
documentation: "Ordered comparison, on numeric, date and ip fields only: a keyword or text field is refused (tql#302). With no schema the value must be a number, a date or an ip. An array-valued field matches if ANY element does."
|
|
114
114
|
},
|
|
115
115
|
gte: {
|
|
116
116
|
detail: "Greater than or equal",
|
|
117
|
-
documentation: "Ordered comparison
|
|
117
|
+
documentation: "Ordered comparison, on numeric, date and ip fields only: a keyword or text field is refused (tql#302). With no schema the value must be a number, a date or an ip. An array-valued field matches if ANY element does."
|
|
118
118
|
},
|
|
119
119
|
lt: {
|
|
120
120
|
detail: "Less than",
|
|
121
|
-
documentation: "Ordered comparison
|
|
121
|
+
documentation: "Ordered comparison, on numeric, date and ip fields only: a keyword or text field is refused (tql#302). With no schema the value must be a number, a date or an ip. An array-valued field matches if ANY element does."
|
|
122
122
|
},
|
|
123
123
|
lte: {
|
|
124
124
|
detail: "Less than or equal",
|
|
125
|
-
documentation: "Ordered comparison
|
|
125
|
+
documentation: "Ordered comparison, on numeric, date and ip fields only: a keyword or text field is refused (tql#302). With no schema the value must be a number, a date or an ip. An array-valued field matches if ANY element does."
|
|
126
126
|
},
|
|
127
127
|
contains: { detail: "Contains substring", documentation: "Case-insensitive substring match" },
|
|
128
128
|
not_contains: { detail: "Does not contain", documentation: "Negative substring match" },
|
|
@@ -138,7 +138,7 @@ const F = [
|
|
|
138
138
|
not_matches: { detail: "Not matching pattern", documentation: "Negative pattern match" },
|
|
139
139
|
between: {
|
|
140
140
|
detail: "Between range",
|
|
141
|
-
documentation: "Inclusive range. Usage: field between A AND B, or field between [A, B]. Numeric
|
|
141
|
+
documentation: "Inclusive range. Usage: field between A AND B, or field between [A, B]. Numeric, date and ip fields only: a keyword or text field is refused (tql#302), and with no schema both bounds must be numbers, dates or ips."
|
|
142
142
|
},
|
|
143
143
|
not_between: { detail: "Not between range", documentation: "Exclude values in range" },
|
|
144
144
|
in: { detail: "In list", documentation: 'Usage: field in ["a", "b", "c"]' },
|
|
@@ -211,7 +211,7 @@ const F = [
|
|
|
211
211
|
sum: { detail: "Sum", documentation: "Sum of numeric array elements" },
|
|
212
212
|
min: { detail: "Minimum", documentation: "Minimum value in array" },
|
|
213
213
|
max: { detail: "Maximum", documentation: "Maximum value in array" }
|
|
214
|
-
},
|
|
214
|
+
}, g = {
|
|
215
215
|
// String outputs
|
|
216
216
|
lowercase: "keyword",
|
|
217
217
|
uppercase: "keyword",
|
|
@@ -257,32 +257,29 @@ const F = [
|
|
|
257
257
|
geo: "object",
|
|
258
258
|
// Array output (returns array of strings)
|
|
259
259
|
split: "keyword"
|
|
260
|
-
},
|
|
260
|
+
}, G = {
|
|
261
261
|
// Equality and membership — every field type, by NAME rather than by a transcribed list.
|
|
262
|
-
eq:
|
|
263
|
-
ne:
|
|
264
|
-
in:
|
|
265
|
-
not_in:
|
|
262
|
+
eq: c,
|
|
263
|
+
ne: c,
|
|
264
|
+
in: c,
|
|
265
|
+
not_in: c,
|
|
266
266
|
// Existence. `is null` is the SAME PREDICATE as `not exists`, so these four lists must be
|
|
267
267
|
// equal. They were not: `nested` and `object` were offered for `exists` and withheld from
|
|
268
268
|
// `is`, so the completion menu published one of two spellings of one operation depending
|
|
269
269
|
// on the field type. Pinned by `tests/collectionAndNullSemantics.spec.ts`.
|
|
270
|
-
exists:
|
|
271
|
-
not_exists:
|
|
272
|
-
is:
|
|
273
|
-
is_not:
|
|
274
|
-
// Ordered comparison — numeric, date and
|
|
275
|
-
// `validator.ts`:
|
|
276
|
-
//
|
|
277
|
-
// field's menu hid an operator every layer of the product supports.
|
|
270
|
+
exists: c,
|
|
271
|
+
not_exists: c,
|
|
272
|
+
is: c,
|
|
273
|
+
is_not: c,
|
|
274
|
+
// Ordered comparison — numeric, date and ip only (tql#302). See ORDERED_FIELD_TYPES in
|
|
275
|
+
// `validator.ts`: every engine refuses them on any other type, so offering one on a
|
|
276
|
+
// keyword field's menu would offer a query that cannot run.
|
|
278
277
|
gt: f,
|
|
279
278
|
gte: f,
|
|
280
279
|
lt: f,
|
|
281
280
|
lte: f,
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
between: v,
|
|
285
|
-
not_between: v,
|
|
281
|
+
between: w,
|
|
282
|
+
not_between: w,
|
|
286
283
|
// String operators (text/keyword only)
|
|
287
284
|
contains: ["text", "keyword"],
|
|
288
285
|
not_contains: ["text", "keyword"],
|
|
@@ -312,12 +309,12 @@ const F = [
|
|
|
312
309
|
// filter reads as "no restriction" — so the negated halves were offered on every type
|
|
313
310
|
// while their positive twins were withheld. Permissive by omission is not the same as
|
|
314
311
|
// permissive by decision, and only one of them survives someone reading the table.
|
|
315
|
-
any:
|
|
316
|
-
all:
|
|
317
|
-
none:
|
|
318
|
-
not_any:
|
|
319
|
-
not_all:
|
|
320
|
-
not_none:
|
|
312
|
+
any: c,
|
|
313
|
+
all: c,
|
|
314
|
+
none: c,
|
|
315
|
+
not_any: c,
|
|
316
|
+
not_all: c,
|
|
317
|
+
not_none: c
|
|
321
318
|
};
|
|
322
319
|
class Y {
|
|
323
320
|
cache = /* @__PURE__ */ new Map();
|
|
@@ -354,7 +351,7 @@ function H(e, t, i) {
|
|
|
354
351
|
const n = T(e.substring(0, t)).filter((l) => l.type !== "whitespace");
|
|
355
352
|
if (n.length === 0)
|
|
356
353
|
return { type: "start" };
|
|
357
|
-
const a = n[n.length - 1], s = n.length > 1 ? n[n.length - 2] : null,
|
|
354
|
+
const a = n[n.length - 1], s = n.length > 1 ? n[n.length - 2] : null, u = a.end === t && !e[t - 1]?.match(/\s/), d = u ? a.value : void 0;
|
|
358
355
|
if (a.type === "logicalOp")
|
|
359
356
|
return { type: "start" };
|
|
360
357
|
if (a.type === "paren" && a.value === "(") {
|
|
@@ -362,7 +359,7 @@ function H(e, t, i) {
|
|
|
362
359
|
if (r && r.type === "visualization")
|
|
363
360
|
return { type: "in_viz_params" };
|
|
364
361
|
}
|
|
365
|
-
if (a.type === "comma" || a.type === "field" &&
|
|
362
|
+
if (a.type === "comma" || a.type === "field" && u) {
|
|
366
363
|
const l = n.indexOf(a);
|
|
367
364
|
for (let r = l - 1; r >= 0; r--) {
|
|
368
365
|
if (n[r].type === "paren" && n[r].value === "(") {
|
|
@@ -377,13 +374,13 @@ function H(e, t, i) {
|
|
|
377
374
|
return { type: "after_paren" };
|
|
378
375
|
if (a.type === "arrow")
|
|
379
376
|
return { type: "after_arrow", partialText: d };
|
|
380
|
-
if (s?.type === "doubleColon" &&
|
|
377
|
+
if (s?.type === "doubleColon" && u)
|
|
381
378
|
return { type: "after_double_colon", partialText: d };
|
|
382
379
|
if (a.type === "doubleColon")
|
|
383
380
|
return { type: "after_double_colon" };
|
|
384
|
-
if (a.type === "visualization" &&
|
|
381
|
+
if (a.type === "visualization" && u)
|
|
385
382
|
return { type: "after_arrow", partialText: d };
|
|
386
|
-
if (a.type === "typeHint" &&
|
|
383
|
+
if (a.type === "typeHint" && u)
|
|
387
384
|
return { type: "after_double_colon", partialText: d };
|
|
388
385
|
if (a.type === "keyword" && a.value.toLowerCase() === "stats")
|
|
389
386
|
return { type: "after_stats", partialText: d };
|
|
@@ -397,7 +394,7 @@ function H(e, t, i) {
|
|
|
397
394
|
if (n[r].type === "keyword" && n[r].value.toLowerCase() === "by" || n[r].type === "pipe") break;
|
|
398
395
|
}
|
|
399
396
|
}
|
|
400
|
-
if (a.type === "field" && !
|
|
397
|
+
if (a.type === "field" && !u) {
|
|
401
398
|
const l = n.indexOf(a);
|
|
402
399
|
for (let r = l - 1; r >= 0; r--) {
|
|
403
400
|
if (n[r].type === "keyword" && n[r].value.toLowerCase() === "by") {
|
|
@@ -414,9 +411,9 @@ function H(e, t, i) {
|
|
|
414
411
|
if (a.type === "pipe")
|
|
415
412
|
return { type: "after_pipe", partialText: d };
|
|
416
413
|
if (a.type === "mutator") {
|
|
417
|
-
if (
|
|
414
|
+
if (u)
|
|
418
415
|
return { type: "after_pipe", partialText: d };
|
|
419
|
-
const l = a.value.toLowerCase(), r =
|
|
416
|
+
const l = a.value.toLowerCase(), r = g[l];
|
|
420
417
|
return {
|
|
421
418
|
type: "after_mutator",
|
|
422
419
|
mutatorName: l,
|
|
@@ -424,9 +421,9 @@ function H(e, t, i) {
|
|
|
424
421
|
};
|
|
425
422
|
}
|
|
426
423
|
if (a.type === "aggregation")
|
|
427
|
-
return
|
|
424
|
+
return u ? { type: "after_stats", partialText: d } : { type: "after_value" };
|
|
428
425
|
if (a.type === "field") {
|
|
429
|
-
if (
|
|
426
|
+
if (u)
|
|
430
427
|
return s?.type === "pipe" ? { type: "after_pipe", partialText: d } : { type: "start", partialText: d };
|
|
431
428
|
if (s?.type === "pipe")
|
|
432
429
|
return { type: "after_pipe", partialText: a.value };
|
|
@@ -434,28 +431,28 @@ function H(e, t, i) {
|
|
|
434
431
|
return { type: "after_field", fieldName: a.value, fieldType: l };
|
|
435
432
|
}
|
|
436
433
|
if (a.type === "operator") {
|
|
437
|
-
if (
|
|
434
|
+
if (u) {
|
|
438
435
|
if (s?.type === "field") {
|
|
439
436
|
const l = h(s.value, i);
|
|
440
437
|
return { type: "after_field", fieldName: s.value, fieldType: l, partialText: d };
|
|
441
438
|
}
|
|
442
439
|
if (s?.type === "mutator") {
|
|
443
|
-
const l = s.value.toLowerCase(), r =
|
|
440
|
+
const l = s.value.toLowerCase(), r = g[l];
|
|
444
441
|
return { type: "after_mutator", mutatorName: l, mutatorOutputType: r, partialText: d };
|
|
445
442
|
}
|
|
446
443
|
}
|
|
447
444
|
return { type: "after_operator", operatorName: a.value };
|
|
448
445
|
}
|
|
449
446
|
if (a.type === "string" || a.type === "number" || a.type === "boolean" || a.type === "null")
|
|
450
|
-
return
|
|
447
|
+
return u ? { type: "at_value_end" } : { type: "after_value" };
|
|
451
448
|
if (a.type === "paren" && a.value === ")")
|
|
452
449
|
return { type: "after_value" };
|
|
453
|
-
if (s?.type === "field" &&
|
|
450
|
+
if (s?.type === "field" && u) {
|
|
454
451
|
const l = h(s.value, i);
|
|
455
452
|
return { type: "after_field", fieldName: s.value, fieldType: l, partialText: d };
|
|
456
453
|
}
|
|
457
|
-
if (s?.type === "mutator" &&
|
|
458
|
-
const l = s.value.toLowerCase(), r =
|
|
454
|
+
if (s?.type === "mutator" && u) {
|
|
455
|
+
const l = s.value.toLowerCase(), r = g[l];
|
|
459
456
|
return { type: "after_mutator", mutatorName: l, mutatorOutputType: r, partialText: d };
|
|
460
457
|
}
|
|
461
458
|
return { type: "unknown", partialText: d };
|
|
@@ -477,10 +474,10 @@ function le(e, t = {}) {
|
|
|
477
474
|
a.push(...b(n.partialText, n.mutatorOutputType));
|
|
478
475
|
break;
|
|
479
476
|
case "after_operator":
|
|
480
|
-
a.push(...
|
|
477
|
+
a.push(...K(n.fieldName, t));
|
|
481
478
|
break;
|
|
482
479
|
case "after_value":
|
|
483
|
-
a.push(...
|
|
480
|
+
a.push(...A());
|
|
484
481
|
break;
|
|
485
482
|
case "at_value_end":
|
|
486
483
|
break;
|
|
@@ -540,26 +537,26 @@ function le(e, t = {}) {
|
|
|
540
537
|
a.push(...ae(n.partialText));
|
|
541
538
|
break;
|
|
542
539
|
case "after_stats":
|
|
543
|
-
a.push(...
|
|
540
|
+
a.push(...N(n.partialText));
|
|
544
541
|
break;
|
|
545
542
|
case "after_by":
|
|
546
543
|
a.push(...x(t.fields, n.partialText)), a.push(...J(n.partialText));
|
|
547
544
|
break;
|
|
548
545
|
default:
|
|
549
|
-
a.push(...x(t.fields, n.partialText)), a.push(...b(n.partialText)), a.push(...
|
|
546
|
+
a.push(...x(t.fields, n.partialText)), a.push(...b(n.partialText)), a.push(...A());
|
|
550
547
|
}
|
|
551
|
-
t.includeAggregations && n.type === "start" && a.push(...
|
|
548
|
+
t.includeAggregations && n.type === "start" && a.push(...N(n.partialText));
|
|
552
549
|
let s = a;
|
|
553
|
-
const
|
|
550
|
+
const u = t.fuzzyMatching !== !1, d = t.minFuzzyScore ?? 0;
|
|
554
551
|
if (n.partialText) {
|
|
555
552
|
const l = n.partialText.toLowerCase();
|
|
556
|
-
if (
|
|
553
|
+
if (u) {
|
|
557
554
|
const r = [];
|
|
558
555
|
for (const m of a) {
|
|
559
|
-
const p =
|
|
560
|
-
|
|
556
|
+
const p = v(l, m.label), _ = m.filterText ? v(l, m.filterText) : { matched: !1, score: 0 }, y = p.score >= _.score ? p : _;
|
|
557
|
+
y.matched && y.score >= d && r.push({
|
|
561
558
|
...m,
|
|
562
|
-
matchScore:
|
|
559
|
+
matchScore: y.score,
|
|
563
560
|
matchedIndices: p.matched ? p.matchedIndices : void 0
|
|
564
561
|
});
|
|
565
562
|
}
|
|
@@ -576,10 +573,10 @@ function x(e, t) {
|
|
|
576
573
|
return j(t);
|
|
577
574
|
const i = [];
|
|
578
575
|
for (const o of e) {
|
|
579
|
-
const n =
|
|
576
|
+
const n = C(o);
|
|
580
577
|
if (i.push(n), o.nested)
|
|
581
578
|
for (const a of o.nested) {
|
|
582
|
-
const s =
|
|
579
|
+
const s = C(a, o.name);
|
|
583
580
|
i.push(s);
|
|
584
581
|
}
|
|
585
582
|
}
|
|
@@ -608,7 +605,7 @@ function j(e) {
|
|
|
608
605
|
sortOrder: 10
|
|
609
606
|
}));
|
|
610
607
|
}
|
|
611
|
-
function
|
|
608
|
+
function C(e, t) {
|
|
612
609
|
const i = t ? `${t}.${e.name}` : e.name;
|
|
613
610
|
return {
|
|
614
611
|
label: i,
|
|
@@ -621,12 +618,12 @@ function N(e, t) {
|
|
|
621
618
|
};
|
|
622
619
|
}
|
|
623
620
|
function b(e, t) {
|
|
624
|
-
let i = [
|
|
621
|
+
let i = [...$];
|
|
625
622
|
return t && (i = i.filter((o) => {
|
|
626
|
-
const n =
|
|
623
|
+
const n = G[o];
|
|
627
624
|
return !n || n.includes(t);
|
|
628
625
|
})), e && (i = i.filter((o) => o.toLowerCase().includes(e.toLowerCase()))), i.map((o, n) => {
|
|
629
|
-
const a =
|
|
626
|
+
const a = q[o] || { detail: o, documentation: "" }, s = W(o, t);
|
|
630
627
|
return {
|
|
631
628
|
label: o,
|
|
632
629
|
insertText: s,
|
|
@@ -637,7 +634,7 @@ function b(e, t) {
|
|
|
637
634
|
};
|
|
638
635
|
});
|
|
639
636
|
}
|
|
640
|
-
function
|
|
637
|
+
function W(e, t) {
|
|
641
638
|
const i = [
|
|
642
639
|
"contains",
|
|
643
640
|
"not_contains",
|
|
@@ -653,9 +650,9 @@ function K(e, t) {
|
|
|
653
650
|
"not_matches"
|
|
654
651
|
], o = ["exists", "not_exists"], n = ["is", "is_not"];
|
|
655
652
|
if (e === "in" || e === "not_in")
|
|
656
|
-
return
|
|
653
|
+
return O(t) ? `${e} [$1]` : `${e} ["$1"]`;
|
|
657
654
|
if (e === "between" || e === "not_between")
|
|
658
|
-
return
|
|
655
|
+
return O(t) ? `${e} $1 AND $2` : `${e} "$1" AND "$2"`;
|
|
659
656
|
if (n.includes(e))
|
|
660
657
|
return `${e} null`;
|
|
661
658
|
if (o.includes(e))
|
|
@@ -680,6 +677,7 @@ function K(e, t) {
|
|
|
680
677
|
return `${e} $1`;
|
|
681
678
|
// Numbers, no quotes
|
|
682
679
|
case "date":
|
|
680
|
+
case "date_nanos":
|
|
683
681
|
return `${e} "$1"`;
|
|
684
682
|
// Dates typically quoted
|
|
685
683
|
case "ip":
|
|
@@ -689,11 +687,11 @@ function K(e, t) {
|
|
|
689
687
|
return `${e} `;
|
|
690
688
|
}
|
|
691
689
|
}
|
|
692
|
-
function
|
|
690
|
+
function O(e) {
|
|
693
691
|
return e === "long" || e === "integer" || e === "double" || e === "float" || e === "short" || e === "byte" || e === "half_float" || e === "scaled_float" || e === "unsigned_long";
|
|
694
692
|
}
|
|
695
|
-
function
|
|
696
|
-
return
|
|
693
|
+
function A() {
|
|
694
|
+
return R.filter((e) => e !== "NOT").map(
|
|
697
695
|
(e, t) => L(e, t)
|
|
698
696
|
);
|
|
699
697
|
}
|
|
@@ -706,7 +704,7 @@ function L(e, t = 0) {
|
|
|
706
704
|
sortOrder: 30 + t
|
|
707
705
|
};
|
|
708
706
|
}
|
|
709
|
-
function
|
|
707
|
+
function K(e, t) {
|
|
710
708
|
const i = [];
|
|
711
709
|
return e && t?.fieldValues?.[e] && t.fieldValues[e].forEach((n, a) => {
|
|
712
710
|
i.push({
|
|
@@ -772,7 +770,7 @@ function X(e) {
|
|
|
772
770
|
}
|
|
773
771
|
);
|
|
774
772
|
}
|
|
775
|
-
function
|
|
773
|
+
function N(e) {
|
|
776
774
|
return D.filter(
|
|
777
775
|
(t) => !e || t.toLowerCase().includes(e.toLowerCase())
|
|
778
776
|
).map((t, i) => ({
|
|
@@ -898,7 +896,7 @@ function se(e, t) {
|
|
|
898
896
|
function de() {
|
|
899
897
|
return [" ", "(", ".", '"', "'", "|", ":", "="];
|
|
900
898
|
}
|
|
901
|
-
function
|
|
899
|
+
function ue(e, t, i) {
|
|
902
900
|
if (!e) return !1;
|
|
903
901
|
if (i === " " || i === "(" || i === "." || i === "|" || i === ":" || i === "=") return !0;
|
|
904
902
|
const o = T(e.substring(0, t)), n = o[o.length - 1];
|
|
@@ -909,5 +907,5 @@ export {
|
|
|
909
907
|
de as getCompletionTriggerCharacters,
|
|
910
908
|
le as getCompletions,
|
|
911
909
|
se as getWordAtPosition,
|
|
912
|
-
|
|
910
|
+
ue as shouldTriggerCompletion
|
|
913
911
|
};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @packageDocumentation
|
|
8
8
|
*/
|
|
9
|
-
export type { TqlToken, TqlTokenType, TqlExpression, TqlBinaryExpression, TqlUnaryExpression, TqlComparisonExpression, TqlCollectionExpression, TqlMutatorExpression, TqlAggregationExpression, TqlStatsExpression, TqlGroupByBucket, TqlLatLon, TqlGroupByLevel, TqlGroupByMetadata, TqlRowBucketMeta, TqlStatsRow, TqlGroupExpression, TqlLiteral, TqlFieldReference, TqlComparisonOperator, TqlLogicalOperator, TqlCollectionOperator, TqlMutator, TqlAggregationFunction, TqlTypeHint, TqlVisualizationType, TqlVizParams, TqlVizHint, TqlParseResult, TqlParseError, TqlParseWarning, TqlErrorCode, TqlWarningCode, TqlValidationResult, TqlValidationOptions, TqlFieldType, CaseSensitiveSupport, TqlCompletionItem, TqlCompletionKind, TqlCompletionContext, TqlCompletionOptions, TqlFieldSchema, TqlSnippet, TqlInputProps, TqlInputEmits, TqlInputExpose } from './types';
|
|
9
|
+
export type { TqlToken, TqlTokenType, TqlExpression, TqlBinaryExpression, TqlUnaryExpression, TqlComparisonExpression, TqlCollectionExpression, TqlMutatorExpression, TqlAggregationExpression, TqlStatsExpression, TqlGroupByBucket, TqlLatLon, TqlGroupByLevel, TqlGroupByMetadata, TqlRowBucketMeta, TqlStatsRow, TqlGroupExpression, TqlLiteral, TqlFieldReference, TqlComparisonOperator, TqlLogicalOperator, TqlCollectionOperator, TqlMutator, TqlAggregationFunction, TqlTypeHint, TqlVisualizationType, TqlVizParams, TqlVizHint, TqlParseResult, TqlParseError, TqlOrderingRefusal, TqlParseWarning, TqlErrorCode, TqlWarningCode, TqlValidationResult, TqlValidationOptions, TqlFieldType, CaseSensitiveSupport, TqlCompletionItem, TqlCompletionKind, TqlCompletionContext, TqlCompletionOptions, TqlFieldSchema, TqlSnippet, TqlInputProps, TqlInputEmits, TqlInputExpose } from './types';
|
|
10
10
|
export { TqlTokenizer, tokenizeTql, tokenizeTqlNoWhitespace, findTokenAtPosition, findTokensInRange, findTokenBefore, findPreviousToken, COMPARISON_OPERATORS, SYMBOL_OPERATORS, NEGATION_SYMBOL_OPERATORS, LOGICAL_OPERATORS, COLLECTION_OPERATORS, MUTATORS, BOOLEAN_PREDICATE_MUTATORS, BOOLEAN_PREDICATE_MUTATOR_SET, AGGREGATION_FUNCTIONS, GROUP_BY_BUCKET_FUNCTIONS, DATE_HISTOGRAM_CALENDAR_INTERVALS, DATE_HISTOGRAM_FIXED_UNITS, GEO_GRID_PRECISION, TYPE_HINTS, VISUALIZATION_TYPES, KEYWORDS } from './tokenizer';
|
|
11
11
|
export { TqlParser, parseTql, isValidTql, getTqlErrors, formatParseError, dateHistogramIntervalProblem, geoPrecisionProblem, rangeBoundariesProblem } from './parser';
|
|
12
12
|
export { TqlValidator, validateTql, isValidTqlSyntax, getTqlIssues, formatValidationResult, caseSensitiveSupport, casePreservingForm, CASE_SENSITIVE_OPERATORS, CASE_SENSITIVE_WHOLE_VALUE_OPERATORS, CASE_SENSITIVE_MEMBERSHIP_OPERATORS, MAX_REGEX_PATTERN_LENGTH } from './validator';
|
|
13
|
+
export { ORDERING_OPERATORS, ORDERABLE_FIELD_TYPES, isOrderingOperator, literalIsOrderable, orderingVerdict, orderingRefusalMessage, checkOrderingComparison } from './ordering';
|
|
13
14
|
export { getCompletions, getWordAtPosition, getCompletionTriggerCharacters, shouldTriggerCompletion } from './completionProvider';
|
|
14
15
|
export { fuzzyMatch, levenshteinDistance, findClosestMatch, fuzzyFilter, highlightMatch, type FuzzyMatchResult, type FuzzyMatchOptions } from './fuzzyMatcher';
|
|
15
16
|
export { SchemaCache, getSchemaCache, createSchemaCache, getCachedFieldNames, getCachedFieldType, getCachedField, type CachedSchema } from './schemaCache';
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TqlFieldType, TqlLiteral, TqlOrderingRefusal } from './types';
|
|
2
|
+
/** Every spelling of an ordering comparator the parser produces. */
|
|
3
|
+
export declare const ORDERING_OPERATORS: readonly string[];
|
|
4
|
+
/** The field types an ordering comparator is valid on, in the order the error lists them. */
|
|
5
|
+
export declare const ORDERABLE_FIELD_TYPES: readonly string[];
|
|
6
|
+
/** Type names a refusal reports as themselves; see `orderingVerdict`. */
|
|
7
|
+
export declare const REPORTED_TYPE_NAMES: ReadonlySet<string>;
|
|
8
|
+
export declare function isOrderingOperator(operator: string): boolean;
|
|
9
|
+
export type { TqlOrderingRefusal };
|
|
10
|
+
/** The refusal text. Byte-identical to Python's `TQLOrderingTypeError` and Rust's `OrderingTypeError`. */
|
|
11
|
+
export declare function orderingRefusalMessage(refusal: Omit<TqlOrderingRefusal, "allowedTypes">): string;
|
|
12
|
+
/** Is this literal a number, a date or an ip address? Judged on its text: quoting is not the rule. */
|
|
13
|
+
export declare function literalIsOrderable(literal: TqlLiteral): boolean;
|
|
14
|
+
/** `null` when nothing is known about the field's type; else its type and whether it is orderable. */
|
|
15
|
+
export type TqlFieldTypeVerdict = {
|
|
16
|
+
reported: string;
|
|
17
|
+
orderable: boolean;
|
|
18
|
+
} | null;
|
|
19
|
+
/**
|
|
20
|
+
* The verdict for `field` from a flat schema. A field is orderable when it, or a DIRECT subfield
|
|
21
|
+
* the schema lists (`f.num`), has an orderable type — the engines aim the clause at that subfield.
|
|
22
|
+
*/
|
|
23
|
+
export declare function orderingVerdict(field: string, fieldTypes?: Record<string, TqlFieldType | TqlFieldType[]>): TqlFieldTypeVerdict;
|
|
24
|
+
/** Refuse one ordering comparison with no meaningful order, or return `null`. See the module doc. */
|
|
25
|
+
export declare function checkOrderingComparison(args: {
|
|
26
|
+
field: string;
|
|
27
|
+
operator: string;
|
|
28
|
+
value: TqlLiteral | TqlLiteral[];
|
|
29
|
+
verdict: TqlFieldTypeVerdict;
|
|
30
|
+
typeHint?: string;
|
|
31
|
+
hasFieldMutators: boolean;
|
|
32
|
+
}): TqlOrderingRefusal | null;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const h = [
|
|
2
|
+
"gt",
|
|
3
|
+
"gte",
|
|
4
|
+
"lt",
|
|
5
|
+
"lte",
|
|
6
|
+
">",
|
|
7
|
+
">=",
|
|
8
|
+
"<",
|
|
9
|
+
"<=",
|
|
10
|
+
"between",
|
|
11
|
+
"not_between",
|
|
12
|
+
"!between"
|
|
13
|
+
], c = [
|
|
14
|
+
"long",
|
|
15
|
+
"integer",
|
|
16
|
+
"short",
|
|
17
|
+
"byte",
|
|
18
|
+
"double",
|
|
19
|
+
"float",
|
|
20
|
+
"half_float",
|
|
21
|
+
"scaled_float",
|
|
22
|
+
"unsigned_long",
|
|
23
|
+
"date",
|
|
24
|
+
"date_nanos",
|
|
25
|
+
"ip"
|
|
26
|
+
], w = /* @__PURE__ */ new Set([
|
|
27
|
+
"keyword",
|
|
28
|
+
"text",
|
|
29
|
+
"long",
|
|
30
|
+
"double",
|
|
31
|
+
"boolean",
|
|
32
|
+
"date",
|
|
33
|
+
"ip",
|
|
34
|
+
"wildcard",
|
|
35
|
+
"object",
|
|
36
|
+
"nested",
|
|
37
|
+
"geo_point",
|
|
38
|
+
"unsigned_long",
|
|
39
|
+
"match_only_text",
|
|
40
|
+
"annotated_text",
|
|
41
|
+
"unknown"
|
|
42
|
+
]), y = /* @__PURE__ */ new Set(["integer", "int", "number", "decimal", "float", "double", "date", "ip"]), _ = /* @__PURE__ */ new Set(["string", "str", "boolean", "bool", "geo", "object"]);
|
|
43
|
+
function E(e) {
|
|
44
|
+
return h.includes(e);
|
|
45
|
+
}
|
|
46
|
+
function $(e) {
|
|
47
|
+
const t = e.operator === "!between" ? "not_between" : e.operator, s = e.literal === void 0 ? `field '${e.field}' of type '${e.fieldType}'` : `field '${e.field}' of unknown type with the literal '${e.literal}'`;
|
|
48
|
+
let r = `Cannot apply ordering operator '${t}' to ${s}. Ordering operators (gt, gte, lt, lte, between) are valid only on numeric, date and ip fields (allowed types: ${c.join(", ")}).`;
|
|
49
|
+
return e.literal !== void 0 && (r += " With no field type known, the literal must be a number, a date or an ip address."), r;
|
|
50
|
+
}
|
|
51
|
+
const O = /^[+-]?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?$/, f = /^[0-9]{4}-[0-9]{2}-[0-9]{2}([T ][0-9]{2}:[0-9]{2}(:[0-9]{2}([.,][0-9]+)?)?(Z|[+-][0-9]{2}(:?[0-9]{2})?)?)?$/, p = /^([+-][0-9]+[yMwdhHms]|\/[yMwdhHms])*$/, g = /^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])){3}$/, v = /^[0-9A-Fa-f]{1,4}$/;
|
|
52
|
+
function A(e) {
|
|
53
|
+
if (!e.includes(":") || !/^[0-9A-Fa-f:.]+$/.test(e))
|
|
54
|
+
return !1;
|
|
55
|
+
const t = e.split("::");
|
|
56
|
+
if (t.length > 2)
|
|
57
|
+
return !1;
|
|
58
|
+
const s = (n) => n === "" ? [] : n.split(":"), r = s(t[0]), i = t.length === 2 ? s(t[1]) : [];
|
|
59
|
+
if (r === null || i === null)
|
|
60
|
+
return !1;
|
|
61
|
+
const a = [...r, ...i];
|
|
62
|
+
let u = 0;
|
|
63
|
+
for (let n = 0; n < a.length; n++) {
|
|
64
|
+
const l = a[n];
|
|
65
|
+
if (n === a.length - 1 && !e.endsWith("::") && l.includes(".")) {
|
|
66
|
+
if (!g.test(l)) return !1;
|
|
67
|
+
u += 2;
|
|
68
|
+
} else if (v.test(l))
|
|
69
|
+
u += 1;
|
|
70
|
+
else
|
|
71
|
+
return !1;
|
|
72
|
+
}
|
|
73
|
+
return t.length === 2 ? u <= 7 : u === 8;
|
|
74
|
+
}
|
|
75
|
+
function m(e) {
|
|
76
|
+
if (e.startsWith("now"))
|
|
77
|
+
return p.test(e.slice(3));
|
|
78
|
+
const t = e.indexOf("||");
|
|
79
|
+
return t === -1 ? f.test(e) : f.test(e.slice(0, t)) && p.test(e.slice(t + 2));
|
|
80
|
+
}
|
|
81
|
+
function R(e) {
|
|
82
|
+
if (e.valueType === "number") return !0;
|
|
83
|
+
if (e.valueType !== "string" || typeof e.value != "string") return !1;
|
|
84
|
+
const t = e.value;
|
|
85
|
+
return O.test(t) || m(t) || g.test(t) || A(t);
|
|
86
|
+
}
|
|
87
|
+
function T(e) {
|
|
88
|
+
return e.value === null ? "null" : String(e.value);
|
|
89
|
+
}
|
|
90
|
+
function S(e, t) {
|
|
91
|
+
const s = t?.[e];
|
|
92
|
+
if (s === void 0) return null;
|
|
93
|
+
const r = Array.isArray(s) ? s : [s];
|
|
94
|
+
if (r.length === 0) return null;
|
|
95
|
+
let i = r.some((n) => c.includes(n));
|
|
96
|
+
const a = r.every((n) => n === "object" || n === "nested");
|
|
97
|
+
if (!i && !a && t) {
|
|
98
|
+
const n = `${e}.`;
|
|
99
|
+
for (const [l, o] of Object.entries(t)) {
|
|
100
|
+
if (!l.startsWith(n) || l.slice(n.length).includes(".")) continue;
|
|
101
|
+
if ((Array.isArray(o) ? o : [o]).some((b) => c.includes(b))) {
|
|
102
|
+
i = !0;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { reported: r.map((n) => i || w.has(n) ? n : "unknown").join(" or "), orderable: i };
|
|
108
|
+
}
|
|
109
|
+
function D(e) {
|
|
110
|
+
const { field: t, operator: s, value: r, verdict: i, typeHint: a, hasFieldMutators: u } = e;
|
|
111
|
+
if (!E(s)) return null;
|
|
112
|
+
const n = (o, d) => ({
|
|
113
|
+
field: t,
|
|
114
|
+
fieldType: o,
|
|
115
|
+
operator: s === "!between" ? "not_between" : s,
|
|
116
|
+
...d === void 0 ? {} : { literal: d },
|
|
117
|
+
allowedTypes: [...c]
|
|
118
|
+
});
|
|
119
|
+
if (!u) {
|
|
120
|
+
if (i !== null)
|
|
121
|
+
return i.orderable ? null : n(i.reported);
|
|
122
|
+
const o = (a ?? "").toLowerCase();
|
|
123
|
+
if (y.has(o)) return null;
|
|
124
|
+
if (_.has(o)) return n(o);
|
|
125
|
+
}
|
|
126
|
+
const l = Array.isArray(r) ? r : [r];
|
|
127
|
+
for (const o of l)
|
|
128
|
+
if (o.type === "literal" && !R(o))
|
|
129
|
+
return n("unknown", T(o));
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
export {
|
|
133
|
+
c as ORDERABLE_FIELD_TYPES,
|
|
134
|
+
h as ORDERING_OPERATORS,
|
|
135
|
+
w as REPORTED_TYPE_NAMES,
|
|
136
|
+
D as checkOrderingComparison,
|
|
137
|
+
E as isOrderingOperator,
|
|
138
|
+
R as literalIsOrderable,
|
|
139
|
+
$ as orderingRefusalMessage,
|
|
140
|
+
S as orderingVerdict
|
|
141
|
+
};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -293,6 +293,18 @@ export interface TqlParseError {
|
|
|
293
293
|
severity: "error";
|
|
294
294
|
code: TqlErrorCode;
|
|
295
295
|
suggestion?: string;
|
|
296
|
+
/** Set on `UNORDERABLE_FIELD`: the field, its type, the operator and the allowed types. */
|
|
297
|
+
ordering?: TqlOrderingRefusal;
|
|
298
|
+
}
|
|
299
|
+
/** An ordering comparator refused on a field with no meaningful order (tql#302). */
|
|
300
|
+
export interface TqlOrderingRefusal {
|
|
301
|
+
field: string;
|
|
302
|
+
/** Mapped type, the type hint, or `"unknown"` when the literal was refused. */
|
|
303
|
+
fieldType: string;
|
|
304
|
+
operator: string;
|
|
305
|
+
/** Set when no field type was known and the LITERAL was refused. */
|
|
306
|
+
literal?: string;
|
|
307
|
+
allowedTypes: string[];
|
|
296
308
|
}
|
|
297
309
|
export interface TqlParseWarning {
|
|
298
310
|
message: string;
|
|
@@ -335,7 +347,15 @@ export type TqlErrorCode = "UNEXPECTED_TOKEN" | "UNEXPECTED_END" | "UNBALANCED_P
|
|
|
335
347
|
* malformed `range` boundaries, a duplicate `filters` label. Mirrors
|
|
336
348
|
* `cross_language_tests/fixtures/test_cases/validation/stats_bucket_errors.json`.
|
|
337
349
|
*/
|
|
338
|
-
| "INVALID_STATS_BUCKET"
|
|
350
|
+
| "INVALID_STATS_BUCKET"
|
|
351
|
+
/**
|
|
352
|
+
* An ordering comparator (`gt`/`gte`/`lt`/`lte`, `between`) on a field with no meaningful
|
|
353
|
+
* order (tql#302): a mapped type that is not numeric, date or ip, or — with no type known —
|
|
354
|
+
* a literal that is not a number, a date or an ip address. Both engines refuse the same
|
|
355
|
+
* query with the same message (`TQLOrderingTypeError` / `OrderingTypeError`). The error's
|
|
356
|
+
* `ordering` field carries the details.
|
|
357
|
+
*/
|
|
358
|
+
| "UNORDERABLE_FIELD";
|
|
339
359
|
export type TqlWarningCode = "UNKNOWN_FIELD" | "TYPE_MISMATCH" | "DEPRECATED_OPERATOR" | "REDUNDANT_PARENS"
|
|
340
360
|
/**
|
|
341
361
|
* The query parses, but only ONE of the two engines accepts it.
|
|
@@ -412,7 +432,7 @@ export interface TqlValidationOptions {
|
|
|
412
432
|
* documents the predicate and its two blind spots.
|
|
413
433
|
*/
|
|
414
434
|
export type CaseSensitiveSupport = "supported" | "unsupported" | "unknown";
|
|
415
|
-
export type TqlFieldType = "text" | "keyword" | "long" | "integer" | "short" | "byte" | "double" | "float" | "half_float" | "scaled_float" | "unsigned_long" | "date" | "boolean" | "ip" | "nested" | "object" | "geo_point";
|
|
435
|
+
export type TqlFieldType = "text" | "keyword" | "long" | "integer" | "short" | "byte" | "double" | "float" | "half_float" | "scaled_float" | "unsigned_long" | "date" | "date_nanos" | "boolean" | "ip" | "nested" | "object" | "geo_point";
|
|
416
436
|
export interface TqlCompletionItem {
|
|
417
437
|
label: string;
|
|
418
438
|
insertText: string;
|
package/dist/src/validator.d.ts
CHANGED
|
@@ -29,22 +29,18 @@ export declare const ALL_FIELD_TYPES: TqlFieldType[];
|
|
|
29
29
|
*/
|
|
30
30
|
export declare const NUMERIC_FIELD_TYPES: TqlFieldType[];
|
|
31
31
|
/**
|
|
32
|
-
* The types an ORDERED comparison (`gt`/`gte`/`lt`/`lte`) is defined over
|
|
32
|
+
* The types an ORDERED comparison (`gt`/`gte`/`lt`/`lte`) is defined over: numeric, date and
|
|
33
|
+
* ip — exactly `ORDERABLE_FIELD_TYPES` in `./ordering` (`date_nanos` joined this union in
|
|
34
|
+
* tql#302, so a `date_nanos` field's completion menu offers them).
|
|
33
35
|
*
|
|
34
|
-
*
|
|
35
|
-
* comparison
|
|
36
|
-
*
|
|
37
|
-
* range over an analyzed field compares tokens, not the value the user typed.
|
|
36
|
+
* `keyword` used to be here, because both evaluators fell back to a lexicographic string
|
|
37
|
+
* comparison. That fallback is what made `os.version gte "10"` match Windows 7, and every
|
|
38
|
+
* engine now refuses it (tql#302); `validate()` reports it as `UNORDERABLE_FIELD`.
|
|
38
39
|
*/
|
|
39
40
|
export declare const ORDERED_FIELD_TYPES: TqlFieldType[];
|
|
40
41
|
/**
|
|
41
|
-
* The types `between` / `not_between` are defined over
|
|
42
|
-
*
|
|
43
|
-
* `ORDERED_FIELD_TYPES` minus `keyword`. The four ordered operators and `between` are NOT
|
|
44
|
-
* the same set, and the difference is Python's, not this package's: `keyword_ops` in
|
|
45
|
-
* `_validate_simple_type_compatibility` lists `gt`/`gte`/`lt`/`lte` and excludes `between`.
|
|
46
|
-
* `tests/collectionAndNullSemantics.spec.ts` pins that exclusion against the Python source,
|
|
47
|
-
* so this constant self-retires if Python ever adds it.
|
|
42
|
+
* The types `between` / `not_between` are defined over: the same set as the four ordered
|
|
43
|
+
* operators since tql#302 (they differed only by `keyword`, which neither allows now).
|
|
48
44
|
*/
|
|
49
45
|
export declare const BETWEEN_FIELD_TYPES: TqlFieldType[];
|
|
50
46
|
/**
|
|
@@ -220,6 +216,12 @@ export declare class TqlValidator {
|
|
|
220
216
|
/**
|
|
221
217
|
* Suggest a similar field name using Levenshtein distance
|
|
222
218
|
*/
|
|
219
|
+
/**
|
|
220
|
+
* Report an ordering comparator with no meaningful order as `UNORDERABLE_FIELD`. Returns
|
|
221
|
+
* whether it did. A field with mutators (`f | length gt 5`) is judged by its literal, as the
|
|
222
|
+
* engines judge it.
|
|
223
|
+
*/
|
|
224
|
+
private validateOrdering;
|
|
223
225
|
private suggestField;
|
|
224
226
|
/**
|
|
225
227
|
* Calculate Levenshtein distance between two strings
|
package/dist/src/validator.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { isOrderingOperator as h, checkOrderingComparison as b, orderingVerdict as m, orderingRefusalMessage as v } from "./ordering.js";
|
|
2
|
+
import { parseTql as E } from "./parser.js";
|
|
3
|
+
const _ = 1e3, r = [
|
|
3
4
|
"text",
|
|
4
5
|
"keyword",
|
|
5
6
|
"long",
|
|
@@ -12,12 +13,13 @@ const g = 1e3, r = [
|
|
|
12
13
|
"scaled_float",
|
|
13
14
|
"unsigned_long",
|
|
14
15
|
"date",
|
|
16
|
+
"date_nanos",
|
|
15
17
|
"boolean",
|
|
16
18
|
"ip",
|
|
17
19
|
"nested",
|
|
18
20
|
"object",
|
|
19
21
|
"geo_point"
|
|
20
|
-
],
|
|
22
|
+
], k = [
|
|
21
23
|
"long",
|
|
22
24
|
"integer",
|
|
23
25
|
"short",
|
|
@@ -27,7 +29,7 @@ const g = 1e3, r = [
|
|
|
27
29
|
"half_float",
|
|
28
30
|
"scaled_float",
|
|
29
31
|
"unsigned_long"
|
|
30
|
-
],
|
|
32
|
+
], d = [...k, "date", "date_nanos", "ip"], g = d, T = {
|
|
31
33
|
// Equality (all types) — and now that is what it says.
|
|
32
34
|
//
|
|
33
35
|
// The transcribed twelve-element list this replaces claimed "all types" while omitting
|
|
@@ -39,29 +41,21 @@ const g = 1e3, r = [
|
|
|
39
41
|
"=": r,
|
|
40
42
|
"!=": r,
|
|
41
43
|
eq_ci: ["text", "keyword"],
|
|
42
|
-
// Ordered comparison — numeric, date
|
|
44
|
+
// Ordered comparison — numeric, date and ip (tql#302). These rows no longer produce the
|
|
45
|
+
// soft warning: `validateOrdering` reports every ordering comparator on another type as the
|
|
46
|
+
// `UNORDERABLE_FIELD` ERROR the engines' refusal deserves. They stay here because the
|
|
47
|
+
// completion menu is checked against this table (completionOperatorTableParity.spec.ts).
|
|
43
48
|
//
|
|
44
|
-
//
|
|
45
|
-
// first and falls back to a LEXICOGRAPHIC string comparison when both sides are strings,
|
|
46
|
-
// Python does the same, and Python's own validator lists all four in `keyword_ops`
|
|
47
|
-
// (`_validate_simple_type_compatibility`). Warning here was a false positive against every
|
|
48
|
-
// layer at once — `host.name gte "m"` is a query the editor flagged, the validator
|
|
49
|
-
// accepts, the evaluator answers and the cluster serves.
|
|
50
|
-
//
|
|
51
|
-
// `text` stays out, and that is the same source's judgement rather than an omission:
|
|
52
|
-
// `text_ops` excludes the four, because a range over an ANALYZED field compares tokens
|
|
53
|
-
// rather than the value the user typed. `between` also stays out — see the note on it.
|
|
54
|
-
//
|
|
55
|
-
// Every numeric width is listed via ALL_NUMERIC_FIELD_TYPES so the five narrow ones cannot
|
|
49
|
+
// Every numeric width is listed via NUMERIC_FIELD_TYPES so the five narrow ones cannot
|
|
56
50
|
// fall out again the way they did from `eq`.
|
|
57
|
-
gt:
|
|
58
|
-
gte:
|
|
59
|
-
lt:
|
|
60
|
-
lte:
|
|
61
|
-
">":
|
|
62
|
-
">=":
|
|
63
|
-
"<":
|
|
64
|
-
"<=":
|
|
51
|
+
gt: d,
|
|
52
|
+
gte: d,
|
|
53
|
+
lt: d,
|
|
54
|
+
lte: d,
|
|
55
|
+
">": d,
|
|
56
|
+
">=": d,
|
|
57
|
+
"<": d,
|
|
58
|
+
"<=": d,
|
|
65
59
|
// String operations
|
|
66
60
|
//
|
|
67
61
|
// ## The `_cs` operators list `text`, and that is deliberate — the rule lives in the caller
|
|
@@ -147,19 +141,12 @@ const g = 1e3, r = [
|
|
|
147
141
|
matches: ["text", "keyword"],
|
|
148
142
|
not_matches: ["text", "keyword"],
|
|
149
143
|
"!matches": ["text", "keyword"],
|
|
150
|
-
// Range. Numeric and
|
|
151
|
-
//
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
// `keyword` and `text` stay out, and that is a decision rather than an omission: Python's
|
|
158
|
-
// `keyword_ops` excludes `between` while including `gte`, which is the divergence pinned
|
|
159
|
-
// in `tests/collectionAndNullSemantics.spec.ts`.
|
|
160
|
-
between: u,
|
|
161
|
-
not_between: u,
|
|
162
|
-
"!between": u,
|
|
144
|
+
// Range. Numeric, date and ip, via the named constant — the same set as the four ordered
|
|
145
|
+
// operators since tql#302; on any other type `validateOrdering` reports the engines'
|
|
146
|
+
// refusal as an ERROR, and these rows never warn.
|
|
147
|
+
between: g,
|
|
148
|
+
not_between: g,
|
|
149
|
+
"!between": g,
|
|
163
150
|
// Membership — the same set as `eq`, because `in` IS a disjunction of equalities and both
|
|
164
151
|
// evaluators implement it that way. The transcribed list this replaces omitted the five
|
|
165
152
|
// narrow numeric widths plus `nested`, `object` and `geo_point`.
|
|
@@ -226,11 +213,11 @@ const g = 1e3, r = [
|
|
|
226
213
|
"!any": r,
|
|
227
214
|
"!all": r,
|
|
228
215
|
"!none": r
|
|
229
|
-
},
|
|
216
|
+
}, f = {
|
|
230
217
|
cidr: ["ip"],
|
|
231
218
|
not_cidr: ["ip"],
|
|
232
219
|
"!cidr": ["ip"]
|
|
233
|
-
},
|
|
220
|
+
}, A = [
|
|
234
221
|
"contains_cs",
|
|
235
222
|
"not_contains_cs",
|
|
236
223
|
"!contains_cs",
|
|
@@ -240,25 +227,25 @@ const g = 1e3, r = [
|
|
|
240
227
|
"endswith_cs",
|
|
241
228
|
"not_endswith_cs",
|
|
242
229
|
"!endswith_cs"
|
|
243
|
-
],
|
|
230
|
+
], w = [
|
|
244
231
|
"in_cs",
|
|
245
232
|
"not_in_cs",
|
|
246
233
|
"!in_cs"
|
|
247
|
-
],
|
|
248
|
-
...
|
|
249
|
-
...
|
|
234
|
+
], $ = [
|
|
235
|
+
...A,
|
|
236
|
+
...w
|
|
250
237
|
];
|
|
251
|
-
function
|
|
238
|
+
function u(o, t) {
|
|
252
239
|
const e = t?.[o];
|
|
253
240
|
return e === void 0 ? [] : Array.isArray(e) ? e : [e];
|
|
254
241
|
}
|
|
255
|
-
function
|
|
242
|
+
function R(o, t) {
|
|
256
243
|
if (!t)
|
|
257
244
|
return "unknown";
|
|
258
|
-
const e =
|
|
245
|
+
const e = u(o, t);
|
|
259
246
|
if (e.length === 0)
|
|
260
247
|
return "unknown";
|
|
261
|
-
if (e.includes("keyword") ||
|
|
248
|
+
if (e.includes("keyword") || u(`${o}.keyword`, t).includes("keyword"))
|
|
262
249
|
return "present";
|
|
263
250
|
const i = `${o}.`;
|
|
264
251
|
for (const [n, s] of Object.entries(t))
|
|
@@ -266,18 +253,18 @@ function E(o, t) {
|
|
|
266
253
|
return "present";
|
|
267
254
|
return "absent";
|
|
268
255
|
}
|
|
269
|
-
function
|
|
270
|
-
if (
|
|
256
|
+
function I(o, t, e) {
|
|
257
|
+
if (!$.includes(t))
|
|
271
258
|
return "supported";
|
|
272
|
-
const i =
|
|
259
|
+
const i = R(o, e);
|
|
273
260
|
if (i !== "absent")
|
|
274
261
|
return i === "present" ? "supported" : "unknown";
|
|
275
|
-
if (!
|
|
262
|
+
if (!w.includes(t))
|
|
276
263
|
return "unsupported";
|
|
277
|
-
const n =
|
|
264
|
+
const n = u(o, e);
|
|
278
265
|
return n.length > 0 && n.every((s) => s === "text") ? "unsupported" : "supported";
|
|
279
266
|
}
|
|
280
|
-
const
|
|
267
|
+
const S = {
|
|
281
268
|
eq: ["string", "number", "boolean"],
|
|
282
269
|
ne: ["string", "number", "boolean"],
|
|
283
270
|
"=": ["string", "number", "boolean"],
|
|
@@ -346,7 +333,7 @@ const T = {
|
|
|
346
333
|
"!all": ["string", "number", "boolean"],
|
|
347
334
|
"!none": ["string", "number", "boolean"]
|
|
348
335
|
};
|
|
349
|
-
class
|
|
336
|
+
class O {
|
|
350
337
|
options;
|
|
351
338
|
errors;
|
|
352
339
|
warnings;
|
|
@@ -359,7 +346,7 @@ class A {
|
|
|
359
346
|
validate(t) {
|
|
360
347
|
if (this.errors = [], this.warnings = [], !t)
|
|
361
348
|
return { valid: !0, errors: [], warnings: [] };
|
|
362
|
-
const e =
|
|
349
|
+
const e = E(t);
|
|
363
350
|
return this.errors.push(...e.errors), this.warnings.push(...e.warnings), e.ast && this.validateExpression(e.ast), {
|
|
364
351
|
valid: this.errors.length === 0,
|
|
365
352
|
errors: this.errors,
|
|
@@ -477,7 +464,7 @@ class A {
|
|
|
477
464
|
*/
|
|
478
465
|
validateComparison(t) {
|
|
479
466
|
const e = t.field.type === "field" ? t.field.name : "computed";
|
|
480
|
-
|
|
467
|
+
this.options.availableFields && this.options.strictMode && !this.options.availableFields.includes(e) && t.field.type === "field" && this.addWarning(
|
|
481
468
|
`Unknown field '${e}'`,
|
|
482
469
|
t.field.start,
|
|
483
470
|
t.field.end,
|
|
@@ -485,25 +472,27 @@ class A {
|
|
|
485
472
|
1,
|
|
486
473
|
"UNKNOWN_FIELD",
|
|
487
474
|
`Did you mean: ${this.suggestField(e)}`
|
|
488
|
-
)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
475
|
+
);
|
|
476
|
+
const i = this.validateOrdering(t);
|
|
477
|
+
if (this.options.fieldTypes && t.field.type === "field") {
|
|
478
|
+
const s = u(e, this.options.fieldTypes), a = s.join(" or ");
|
|
479
|
+
if (s.length > 0) {
|
|
480
|
+
const l = f[t.operator];
|
|
481
|
+
l && !s.some((c) => l.includes(c)) && this.addError(
|
|
482
|
+
`Operator '${t.operator}' requires field type ${l.join(" or ")}, but '${e}' is type '${a}'`,
|
|
494
483
|
t.start,
|
|
495
484
|
t.end,
|
|
496
485
|
1,
|
|
497
486
|
1,
|
|
498
487
|
"TYPE_MISMATCH",
|
|
499
|
-
`Use '${t.operator}' only with ${
|
|
488
|
+
`Use '${t.operator}' only with ${l.join(" or ")} fields`
|
|
500
489
|
);
|
|
501
490
|
}
|
|
502
491
|
}
|
|
503
|
-
let
|
|
504
|
-
if (t.field.type === "field" &&
|
|
505
|
-
|
|
506
|
-
const
|
|
492
|
+
let n = !1;
|
|
493
|
+
if (t.field.type === "field" && I(e, t.operator, this.options.fieldTypes) === "unsupported") {
|
|
494
|
+
n = !0;
|
|
495
|
+
const s = t.operator.replace(/_cs$/, ""), a = this.options.fieldTypes?.[e], l = a === "text" ? `'${e}' is an analyzed text field with no case-preserving subfield in the supplied schema, so the analyzer lowercased every token it indexed and the case '${t.operator}' asks about is not in the index` : `'${e}' is type '${a}' and has no un-analyzed string form, which is what '${t.operator}' matches against`;
|
|
507
496
|
this.addWarning(
|
|
508
497
|
// "The query engine", singular and unqualified, and kept that way deliberately.
|
|
509
498
|
// It was written this way because "both engines" was FALSE in twelve cells —
|
|
@@ -512,34 +501,34 @@ class A {
|
|
|
512
501
|
// user does not choose the engine, the sentence is about what will go wrong
|
|
513
502
|
// rather than about who refuses, and a message that counts engines is a message
|
|
514
503
|
// that goes stale the next time one of them changes.
|
|
515
|
-
`${
|
|
504
|
+
`${l}. The query engine refuses this at execution.`,
|
|
516
505
|
t.start,
|
|
517
506
|
t.end,
|
|
518
507
|
1,
|
|
519
508
|
1,
|
|
520
509
|
"UNANSWERABLE_MAPPING",
|
|
521
|
-
|
|
510
|
+
a === "text" ? `Use the case-insensitive '${s}', or query a keyword subfield (\`${e}.keyword\`) if the index has one this schema does not list.` : `Use the case-insensitive '${s}', or compare '${e}' with an operator suited to '${a}'.`
|
|
522
511
|
);
|
|
523
512
|
}
|
|
524
513
|
if (this.options.fieldTypes && t.field.type === "field") {
|
|
525
|
-
const
|
|
526
|
-
if (
|
|
527
|
-
const
|
|
528
|
-
!i && !
|
|
529
|
-
`Operator '${t.operator}' may not work well with field type '${
|
|
514
|
+
const s = u(e, this.options.fieldTypes), a = s.join(" or ");
|
|
515
|
+
if (s.length > 0) {
|
|
516
|
+
const l = T[t.operator], c = f[t.operator];
|
|
517
|
+
!n && !i && !h(t.operator) && !c && l && !s.some((p) => l.includes(p)) && this.addWarning(
|
|
518
|
+
`Operator '${t.operator}' may not work well with field type '${a}'`,
|
|
530
519
|
t.start,
|
|
531
520
|
t.end,
|
|
532
521
|
1,
|
|
533
522
|
1,
|
|
534
523
|
"TYPE_MISMATCH",
|
|
535
|
-
`Consider using a different operator for ${
|
|
524
|
+
`Consider using a different operator for ${a} fields`
|
|
536
525
|
);
|
|
537
526
|
}
|
|
538
527
|
}
|
|
539
528
|
if (!Array.isArray(t.value) && t.value.type === "literal") {
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
`Operator '${t.operator}' expects ${
|
|
529
|
+
const s = S[t.operator];
|
|
530
|
+
s && !s.includes(t.value.valueType) && this.addWarning(
|
|
531
|
+
`Operator '${t.operator}' expects ${s.join(" or ")} value`,
|
|
543
532
|
t.value.start,
|
|
544
533
|
t.value.end,
|
|
545
534
|
1,
|
|
@@ -548,10 +537,10 @@ class A {
|
|
|
548
537
|
);
|
|
549
538
|
}
|
|
550
539
|
if ((t.operator === "regexp" || t.operator === "regex" || t.operator === "not_regexp" || t.operator === "not_regex" || t.operator === "matches" || t.operator === "not_matches") && !Array.isArray(t.value) && t.value.valueType === "string" && typeof t.value.value == "string") {
|
|
551
|
-
const
|
|
552
|
-
if (
|
|
540
|
+
const s = Array.from(t.value.value).length;
|
|
541
|
+
if (s > _)
|
|
553
542
|
this.addError(
|
|
554
|
-
`Regex pattern is ${
|
|
543
|
+
`Regex pattern is ${s} characters, which exceeds the maximum supported length of ${_}. The query cannot run as written.`,
|
|
555
544
|
t.value.start,
|
|
556
545
|
t.value.end,
|
|
557
546
|
1,
|
|
@@ -578,6 +567,36 @@ class A {
|
|
|
578
567
|
/**
|
|
579
568
|
* Suggest a similar field name using Levenshtein distance
|
|
580
569
|
*/
|
|
570
|
+
/**
|
|
571
|
+
* Report an ordering comparator with no meaningful order as `UNORDERABLE_FIELD`. Returns
|
|
572
|
+
* whether it did. A field with mutators (`f | length gt 5`) is judged by its literal, as the
|
|
573
|
+
* engines judge it.
|
|
574
|
+
*/
|
|
575
|
+
validateOrdering(t) {
|
|
576
|
+
if (!h(t.operator)) return !1;
|
|
577
|
+
let e = t.field, i = !1;
|
|
578
|
+
for (; e.type === "mutator"; )
|
|
579
|
+
i = !0, e = e.field;
|
|
580
|
+
((e.mutators?.length ?? 0) > 0 || (e.mutatorCalls?.length ?? 0) > 0) && (i = !0);
|
|
581
|
+
const n = b({
|
|
582
|
+
field: e.name,
|
|
583
|
+
operator: t.operator,
|
|
584
|
+
value: t.value,
|
|
585
|
+
verdict: m(e.name, this.options.fieldTypes),
|
|
586
|
+
typeHint: e.typeHint,
|
|
587
|
+
hasFieldMutators: i
|
|
588
|
+
});
|
|
589
|
+
return n === null ? !1 : (this.addError(
|
|
590
|
+
v(n),
|
|
591
|
+
t.start,
|
|
592
|
+
t.end,
|
|
593
|
+
1,
|
|
594
|
+
1,
|
|
595
|
+
"UNORDERABLE_FIELD",
|
|
596
|
+
n.literal === void 0 ? `Compare '${n.field}' with eq/ne/in, or order on a numeric, date or ip field (a version has numeric parts such as os.version_build).` : "Use a number, a date or an ip address, or compare with eq/ne/in.",
|
|
597
|
+
n
|
|
598
|
+
), !0);
|
|
599
|
+
}
|
|
581
600
|
suggestField(t) {
|
|
582
601
|
if (!this.options.availableFields || this.options.availableFields.length === 0)
|
|
583
602
|
return "check available fields";
|
|
@@ -606,7 +625,7 @@ class A {
|
|
|
606
625
|
);
|
|
607
626
|
return i[e.length][t.length];
|
|
608
627
|
}
|
|
609
|
-
addError(t, e, i, n, s, a,
|
|
628
|
+
addError(t, e, i, n, s, a, l, c) {
|
|
610
629
|
this.errors.push({
|
|
611
630
|
message: t,
|
|
612
631
|
start: e,
|
|
@@ -615,10 +634,11 @@ class A {
|
|
|
615
634
|
column: s,
|
|
616
635
|
severity: "error",
|
|
617
636
|
code: a,
|
|
618
|
-
suggestion:
|
|
637
|
+
suggestion: l,
|
|
638
|
+
...c ? { ordering: c } : {}
|
|
619
639
|
});
|
|
620
640
|
}
|
|
621
|
-
addWarning(t, e, i, n, s, a,
|
|
641
|
+
addWarning(t, e, i, n, s, a, l) {
|
|
622
642
|
this.warnings.push({
|
|
623
643
|
message: t,
|
|
624
644
|
start: e,
|
|
@@ -627,21 +647,21 @@ class A {
|
|
|
627
647
|
column: s,
|
|
628
648
|
severity: "warning",
|
|
629
649
|
code: a,
|
|
630
|
-
suggestion:
|
|
650
|
+
suggestion: l
|
|
631
651
|
});
|
|
632
652
|
}
|
|
633
653
|
}
|
|
634
|
-
function
|
|
635
|
-
return new
|
|
654
|
+
function y(o, t) {
|
|
655
|
+
return new O(t).validate(o);
|
|
636
656
|
}
|
|
637
|
-
function
|
|
638
|
-
return
|
|
657
|
+
function x(o) {
|
|
658
|
+
return y(o).valid;
|
|
639
659
|
}
|
|
640
|
-
function
|
|
641
|
-
const e =
|
|
660
|
+
function C(o, t) {
|
|
661
|
+
const e = y(o, t);
|
|
642
662
|
return [...e.errors, ...e.warnings];
|
|
643
663
|
}
|
|
644
|
-
function
|
|
664
|
+
function M(o) {
|
|
645
665
|
const t = [];
|
|
646
666
|
o.valid ? t.push("Query is valid") : t.push("Query has errors:");
|
|
647
667
|
for (const e of o.errors)
|
|
@@ -653,18 +673,18 @@ function R(o) {
|
|
|
653
673
|
}
|
|
654
674
|
export {
|
|
655
675
|
r as ALL_FIELD_TYPES,
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
676
|
+
g as BETWEEN_FIELD_TYPES,
|
|
677
|
+
w as CASE_SENSITIVE_MEMBERSHIP_OPERATORS,
|
|
678
|
+
$ as CASE_SENSITIVE_OPERATORS,
|
|
679
|
+
A as CASE_SENSITIVE_WHOLE_VALUE_OPERATORS,
|
|
680
|
+
_ as MAX_REGEX_PATTERN_LENGTH,
|
|
681
|
+
k as NUMERIC_FIELD_TYPES,
|
|
682
|
+
d as ORDERED_FIELD_TYPES,
|
|
683
|
+
O as TqlValidator,
|
|
684
|
+
R as casePreservingForm,
|
|
685
|
+
I as caseSensitiveSupport,
|
|
686
|
+
M as formatValidationResult,
|
|
687
|
+
C as getTqlIssues,
|
|
688
|
+
x as isValidTqlSyntax,
|
|
689
|
+
y as validateTql
|
|
670
690
|
};
|