@webda/ql 4.0.0-beta.2 → 4.0.0-beta.3
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/README.md +135 -2
- package/lib/WebdaQLLexer.d.ts +19 -13
- package/lib/WebdaQLLexer.d.ts.map +1 -1
- package/lib/WebdaQLLexer.js +305 -252
- package/lib/WebdaQLLexer.js.map +1 -1
- package/lib/WebdaQLParserLexer.d.ts +19 -13
- package/lib/WebdaQLParserLexer.d.ts.map +1 -1
- package/lib/WebdaQLParserLexer.js +305 -252
- package/lib/WebdaQLParserLexer.js.map +1 -1
- package/lib/WebdaQLParserListener.d.ts +89 -3
- package/lib/WebdaQLParserListener.d.ts.map +1 -1
- package/lib/WebdaQLParserListener.js +1 -1
- package/lib/WebdaQLParserListener.js.map +1 -1
- package/lib/WebdaQLParserParser.d.ts +83 -22
- package/lib/WebdaQLParserParser.d.ts.map +1 -1
- package/lib/WebdaQLParserParser.js +790 -290
- package/lib/WebdaQLParserParser.js.map +1 -1
- package/lib/WebdaQLParserVisitor.d.ts +65 -2
- package/lib/WebdaQLParserVisitor.d.ts.map +1 -1
- package/lib/WebdaQLParserVisitor.js +1 -1
- package/lib/WebdaQLParserVisitor.js.map +1 -1
- package/lib/bind.d.ts +29 -0
- package/lib/bind.d.ts.map +1 -0
- package/lib/bind.js +139 -0
- package/lib/bind.js.map +1 -0
- package/lib/bind.spec.d.ts +2 -0
- package/lib/bind.spec.d.ts.map +1 -0
- package/lib/bind.spec.js +206 -0
- package/lib/bind.spec.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -0
- package/lib/query.d.ts +395 -76
- package/lib/query.d.ts.map +1 -1
- package/lib/query.js +562 -91
- package/lib/query.js.map +1 -1
- package/lib/query.spec.js +593 -195
- package/lib/query.spec.js.map +1 -1
- package/lib/webdaql-string.d.ts +59 -0
- package/lib/webdaql-string.d.ts.map +1 -0
- package/lib/webdaql-string.js +112 -0
- package/lib/webdaql-string.js.map +1 -0
- package/lib/webdaql-string.spec.d.ts +2 -0
- package/lib/webdaql-string.spec.d.ts.map +1 -0
- package/lib/webdaql-string.spec.js +282 -0
- package/lib/webdaql-string.spec.js.map +1 -0
- package/package.json +30 -42
package/lib/query.spec.js
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
2
|
+
var useValue = arguments.length > 2;
|
|
3
|
+
for (var i = 0; i < initializers.length; i++) {
|
|
4
|
+
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
5
|
+
}
|
|
6
|
+
return useValue ? value : void 0;
|
|
7
|
+
};
|
|
8
|
+
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
9
|
+
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
10
|
+
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
11
|
+
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
12
|
+
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
13
|
+
var _, done = false;
|
|
14
|
+
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
15
|
+
var context = {};
|
|
16
|
+
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
17
|
+
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
18
|
+
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
19
|
+
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
20
|
+
if (kind === "accessor") {
|
|
21
|
+
if (result === void 0) continue;
|
|
22
|
+
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
23
|
+
if (_ = accept(result.get)) descriptor.get = _;
|
|
24
|
+
if (_ = accept(result.set)) descriptor.set = _;
|
|
25
|
+
if (_ = accept(result.init)) initializers.unshift(_);
|
|
26
|
+
}
|
|
27
|
+
else if (_ = accept(result)) {
|
|
28
|
+
if (kind === "field") initializers.unshift(_);
|
|
29
|
+
else descriptor[key] = _;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
33
|
+
done = true;
|
|
6
34
|
};
|
|
7
|
-
import { suite, test } from "@
|
|
35
|
+
import { suite, test } from "@webda/test";
|
|
8
36
|
import * as assert from "assert";
|
|
9
37
|
import * as WebdaQL from "./query.js";
|
|
38
|
+
import { CharStreams, CommonTokenStream } from "antlr4ts";
|
|
39
|
+
import { ParseTreeWalker } from "antlr4ts/tree/index.js";
|
|
40
|
+
import { WebdaQLLexer } from "./WebdaQLLexer.js";
|
|
41
|
+
import { WebdaQLParserParser } from "./WebdaQLParserParser.js";
|
|
10
42
|
const targets = [
|
|
11
43
|
{
|
|
12
44
|
test: {
|
|
@@ -18,197 +50,563 @@ const targets = [
|
|
|
18
50
|
attr5: ["test", "plip"]
|
|
19
51
|
}
|
|
20
52
|
];
|
|
21
|
-
let QueryTest =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
53
|
+
let QueryTest = (() => {
|
|
54
|
+
let _classDecorators = [suite];
|
|
55
|
+
let _classDescriptor;
|
|
56
|
+
let _classExtraInitializers = [];
|
|
57
|
+
let _classThis;
|
|
58
|
+
let _instanceExtraInitializers = [];
|
|
59
|
+
let _dev_decorators;
|
|
60
|
+
let _prependQuery_decorators;
|
|
61
|
+
let _likeRegexp_decorators;
|
|
62
|
+
let _simple_decorators;
|
|
63
|
+
let _contains_decorators;
|
|
64
|
+
let _andQuery_decorators;
|
|
65
|
+
let _orQuery_decorators;
|
|
66
|
+
let _multipleQuery_decorators;
|
|
67
|
+
let _unsanitize_decorators;
|
|
68
|
+
let _limitOffset_decorators;
|
|
69
|
+
let _badQuery_decorators;
|
|
70
|
+
let _setters_decorators;
|
|
71
|
+
let _parse_decorators;
|
|
72
|
+
let _partialValidator_decorators;
|
|
73
|
+
let _mergeTypeMismatch_decorators;
|
|
74
|
+
let _getOffsetFallback_decorators;
|
|
75
|
+
let _expressionToString_decorators;
|
|
76
|
+
let _hasCondition_decorators;
|
|
77
|
+
let _queryValidatorToString_decorators;
|
|
78
|
+
let _complexQueries_decorators;
|
|
79
|
+
let _containsNonArray_decorators;
|
|
80
|
+
let _likeOnNonString_decorators;
|
|
81
|
+
let _likeOnMissingAttribute_decorators;
|
|
82
|
+
let _quotedLiterals_decorators;
|
|
83
|
+
let _lexerIntrospection_decorators;
|
|
84
|
+
let _parserIntrospection_decorators;
|
|
85
|
+
let _listenerWalk_decorators;
|
|
86
|
+
let _contextAccessors_decorators;
|
|
87
|
+
let _setterAssignment_decorators;
|
|
88
|
+
let _mergePreservesExistingMeta_decorators;
|
|
89
|
+
let _booleanLiterals_decorators;
|
|
90
|
+
let _booleanLiteralsFold_decorators;
|
|
91
|
+
let _bareAtomsAreSyntaxErrors_decorators;
|
|
92
|
+
let _partialValidatorWithBooleans_decorators;
|
|
93
|
+
let _isNull_decorators;
|
|
94
|
+
let _isNullToString_decorators;
|
|
95
|
+
let _isNullPartial_decorators;
|
|
96
|
+
var QueryTest = class {
|
|
97
|
+
static { _classThis = this; }
|
|
98
|
+
static {
|
|
99
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
100
|
+
_dev_decorators = [test];
|
|
101
|
+
_prependQuery_decorators = [test];
|
|
102
|
+
_likeRegexp_decorators = [test];
|
|
103
|
+
_simple_decorators = [test];
|
|
104
|
+
_contains_decorators = [test];
|
|
105
|
+
_andQuery_decorators = [test];
|
|
106
|
+
_orQuery_decorators = [test];
|
|
107
|
+
_multipleQuery_decorators = [test];
|
|
108
|
+
_unsanitize_decorators = [test];
|
|
109
|
+
_limitOffset_decorators = [test];
|
|
110
|
+
_badQuery_decorators = [test];
|
|
111
|
+
_setters_decorators = [test];
|
|
112
|
+
_parse_decorators = [test];
|
|
113
|
+
_partialValidator_decorators = [test];
|
|
114
|
+
_mergeTypeMismatch_decorators = [test];
|
|
115
|
+
_getOffsetFallback_decorators = [test];
|
|
116
|
+
_expressionToString_decorators = [test];
|
|
117
|
+
_hasCondition_decorators = [test];
|
|
118
|
+
_queryValidatorToString_decorators = [test];
|
|
119
|
+
_complexQueries_decorators = [test];
|
|
120
|
+
_containsNonArray_decorators = [test];
|
|
121
|
+
_likeOnNonString_decorators = [test];
|
|
122
|
+
_likeOnMissingAttribute_decorators = [test];
|
|
123
|
+
_quotedLiterals_decorators = [test];
|
|
124
|
+
_lexerIntrospection_decorators = [test];
|
|
125
|
+
_parserIntrospection_decorators = [test];
|
|
126
|
+
_listenerWalk_decorators = [test];
|
|
127
|
+
_contextAccessors_decorators = [test];
|
|
128
|
+
_setterAssignment_decorators = [test];
|
|
129
|
+
_mergePreservesExistingMeta_decorators = [test];
|
|
130
|
+
_booleanLiterals_decorators = [test];
|
|
131
|
+
_booleanLiteralsFold_decorators = [test];
|
|
132
|
+
_bareAtomsAreSyntaxErrors_decorators = [test];
|
|
133
|
+
_partialValidatorWithBooleans_decorators = [test];
|
|
134
|
+
_isNull_decorators = [test];
|
|
135
|
+
_isNullToString_decorators = [test];
|
|
136
|
+
_isNullPartial_decorators = [test];
|
|
137
|
+
__esDecorate(this, null, _dev_decorators, { kind: "method", name: "dev", static: false, private: false, access: { has: obj => "dev" in obj, get: obj => obj.dev }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
138
|
+
__esDecorate(this, null, _prependQuery_decorators, { kind: "method", name: "prependQuery", static: false, private: false, access: { has: obj => "prependQuery" in obj, get: obj => obj.prependQuery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
139
|
+
__esDecorate(this, null, _likeRegexp_decorators, { kind: "method", name: "likeRegexp", static: false, private: false, access: { has: obj => "likeRegexp" in obj, get: obj => obj.likeRegexp }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
140
|
+
__esDecorate(this, null, _simple_decorators, { kind: "method", name: "simple", static: false, private: false, access: { has: obj => "simple" in obj, get: obj => obj.simple }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
141
|
+
__esDecorate(this, null, _contains_decorators, { kind: "method", name: "contains", static: false, private: false, access: { has: obj => "contains" in obj, get: obj => obj.contains }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
142
|
+
__esDecorate(this, null, _andQuery_decorators, { kind: "method", name: "andQuery", static: false, private: false, access: { has: obj => "andQuery" in obj, get: obj => obj.andQuery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
143
|
+
__esDecorate(this, null, _orQuery_decorators, { kind: "method", name: "orQuery", static: false, private: false, access: { has: obj => "orQuery" in obj, get: obj => obj.orQuery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
144
|
+
__esDecorate(this, null, _multipleQuery_decorators, { kind: "method", name: "multipleQuery", static: false, private: false, access: { has: obj => "multipleQuery" in obj, get: obj => obj.multipleQuery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
145
|
+
__esDecorate(this, null, _unsanitize_decorators, { kind: "method", name: "unsanitize", static: false, private: false, access: { has: obj => "unsanitize" in obj, get: obj => obj.unsanitize }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
146
|
+
__esDecorate(this, null, _limitOffset_decorators, { kind: "method", name: "limitOffset", static: false, private: false, access: { has: obj => "limitOffset" in obj, get: obj => obj.limitOffset }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
147
|
+
__esDecorate(this, null, _badQuery_decorators, { kind: "method", name: "badQuery", static: false, private: false, access: { has: obj => "badQuery" in obj, get: obj => obj.badQuery }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
148
|
+
__esDecorate(this, null, _setters_decorators, { kind: "method", name: "setters", static: false, private: false, access: { has: obj => "setters" in obj, get: obj => obj.setters }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
149
|
+
__esDecorate(this, null, _parse_decorators, { kind: "method", name: "parse", static: false, private: false, access: { has: obj => "parse" in obj, get: obj => obj.parse }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
150
|
+
__esDecorate(this, null, _partialValidator_decorators, { kind: "method", name: "partialValidator", static: false, private: false, access: { has: obj => "partialValidator" in obj, get: obj => obj.partialValidator }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
151
|
+
__esDecorate(this, null, _mergeTypeMismatch_decorators, { kind: "method", name: "mergeTypeMismatch", static: false, private: false, access: { has: obj => "mergeTypeMismatch" in obj, get: obj => obj.mergeTypeMismatch }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
152
|
+
__esDecorate(this, null, _getOffsetFallback_decorators, { kind: "method", name: "getOffsetFallback", static: false, private: false, access: { has: obj => "getOffsetFallback" in obj, get: obj => obj.getOffsetFallback }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
153
|
+
__esDecorate(this, null, _expressionToString_decorators, { kind: "method", name: "expressionToString", static: false, private: false, access: { has: obj => "expressionToString" in obj, get: obj => obj.expressionToString }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
154
|
+
__esDecorate(this, null, _hasCondition_decorators, { kind: "method", name: "hasCondition", static: false, private: false, access: { has: obj => "hasCondition" in obj, get: obj => obj.hasCondition }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
155
|
+
__esDecorate(this, null, _queryValidatorToString_decorators, { kind: "method", name: "queryValidatorToString", static: false, private: false, access: { has: obj => "queryValidatorToString" in obj, get: obj => obj.queryValidatorToString }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
156
|
+
__esDecorate(this, null, _complexQueries_decorators, { kind: "method", name: "complexQueries", static: false, private: false, access: { has: obj => "complexQueries" in obj, get: obj => obj.complexQueries }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
157
|
+
__esDecorate(this, null, _containsNonArray_decorators, { kind: "method", name: "containsNonArray", static: false, private: false, access: { has: obj => "containsNonArray" in obj, get: obj => obj.containsNonArray }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
158
|
+
__esDecorate(this, null, _likeOnNonString_decorators, { kind: "method", name: "likeOnNonString", static: false, private: false, access: { has: obj => "likeOnNonString" in obj, get: obj => obj.likeOnNonString }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
159
|
+
__esDecorate(this, null, _likeOnMissingAttribute_decorators, { kind: "method", name: "likeOnMissingAttribute", static: false, private: false, access: { has: obj => "likeOnMissingAttribute" in obj, get: obj => obj.likeOnMissingAttribute }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
160
|
+
__esDecorate(this, null, _quotedLiterals_decorators, { kind: "method", name: "quotedLiterals", static: false, private: false, access: { has: obj => "quotedLiterals" in obj, get: obj => obj.quotedLiterals }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
161
|
+
__esDecorate(this, null, _lexerIntrospection_decorators, { kind: "method", name: "lexerIntrospection", static: false, private: false, access: { has: obj => "lexerIntrospection" in obj, get: obj => obj.lexerIntrospection }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
162
|
+
__esDecorate(this, null, _parserIntrospection_decorators, { kind: "method", name: "parserIntrospection", static: false, private: false, access: { has: obj => "parserIntrospection" in obj, get: obj => obj.parserIntrospection }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
163
|
+
__esDecorate(this, null, _listenerWalk_decorators, { kind: "method", name: "listenerWalk", static: false, private: false, access: { has: obj => "listenerWalk" in obj, get: obj => obj.listenerWalk }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
164
|
+
__esDecorate(this, null, _contextAccessors_decorators, { kind: "method", name: "contextAccessors", static: false, private: false, access: { has: obj => "contextAccessors" in obj, get: obj => obj.contextAccessors }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
165
|
+
__esDecorate(this, null, _setterAssignment_decorators, { kind: "method", name: "setterAssignment", static: false, private: false, access: { has: obj => "setterAssignment" in obj, get: obj => obj.setterAssignment }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
166
|
+
__esDecorate(this, null, _mergePreservesExistingMeta_decorators, { kind: "method", name: "mergePreservesExistingMeta", static: false, private: false, access: { has: obj => "mergePreservesExistingMeta" in obj, get: obj => obj.mergePreservesExistingMeta }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
167
|
+
__esDecorate(this, null, _booleanLiterals_decorators, { kind: "method", name: "booleanLiterals", static: false, private: false, access: { has: obj => "booleanLiterals" in obj, get: obj => obj.booleanLiterals }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
168
|
+
__esDecorate(this, null, _booleanLiteralsFold_decorators, { kind: "method", name: "booleanLiteralsFold", static: false, private: false, access: { has: obj => "booleanLiteralsFold" in obj, get: obj => obj.booleanLiteralsFold }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
169
|
+
__esDecorate(this, null, _bareAtomsAreSyntaxErrors_decorators, { kind: "method", name: "bareAtomsAreSyntaxErrors", static: false, private: false, access: { has: obj => "bareAtomsAreSyntaxErrors" in obj, get: obj => obj.bareAtomsAreSyntaxErrors }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
170
|
+
__esDecorate(this, null, _partialValidatorWithBooleans_decorators, { kind: "method", name: "partialValidatorWithBooleans", static: false, private: false, access: { has: obj => "partialValidatorWithBooleans" in obj, get: obj => obj.partialValidatorWithBooleans }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
171
|
+
__esDecorate(this, null, _isNull_decorators, { kind: "method", name: "isNull", static: false, private: false, access: { has: obj => "isNull" in obj, get: obj => obj.isNull }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
172
|
+
__esDecorate(this, null, _isNullToString_decorators, { kind: "method", name: "isNullToString", static: false, private: false, access: { has: obj => "isNullToString" in obj, get: obj => obj.isNullToString }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
173
|
+
__esDecorate(this, null, _isNullPartial_decorators, { kind: "method", name: "isNullPartial", static: false, private: false, access: { has: obj => "isNullPartial" in obj, get: obj => obj.isNullPartial }, metadata: _metadata }, null, _instanceExtraInitializers);
|
|
174
|
+
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
175
|
+
QueryTest = _classThis = _classDescriptor.value;
|
|
176
|
+
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
177
|
+
__runInitializers(_classThis, _classExtraInitializers);
|
|
178
|
+
}
|
|
179
|
+
dev() {
|
|
180
|
+
const queryMap = {
|
|
181
|
+
"a = 1 AND b = 2 AND c = 3 AND d = 4": "a = 1 AND b = 2 AND c = 3 AND d = 4",
|
|
182
|
+
"a = 1 AND (b = 2 AND c = 3) AND d = 4": "a = 1 AND b = 2 AND c = 3 AND d = 4",
|
|
183
|
+
"a = 1 AND ((b = 2 AND c = 3) AND d = 4)": "a = 1 AND b = 2 AND c = 3 AND d = 4",
|
|
184
|
+
"a = 1 AND ((b = 2 OR c = 3) AND d = 4)": "a = 1 AND ( b = 2 OR c = 3 ) AND d = 4",
|
|
185
|
+
"a = 1 AND (b = 2) AND c = 3 AND d = 4": "a = 1 AND b = 2 AND c = 3 AND d = 4",
|
|
186
|
+
"a = 1 OR b = 2 OR c = 3 OR d = 4": "a = 1 OR b = 2 OR c = 3 OR d = 4",
|
|
187
|
+
'a = 1 AND (b = 2 OR c = 3) AND d = "plop"': 'a = 1 AND ( b = 2 OR c = 3 ) AND d = "plop"',
|
|
188
|
+
"a = 1 OR b = TRUE AND c = FALSE OR d = 'plop'": 'a = 1 OR ( b = TRUE AND c = FALSE ) OR d = "plop"',
|
|
189
|
+
"test.attr1 = 'plop'": true,
|
|
190
|
+
"test.attr1 = 'plop2'": false,
|
|
191
|
+
"test.attr1 = 'plop' AND attr2 IN ['TEST', TRUE, 3]": 'test.attr1 = "plop" AND attr2 IN ["TEST", TRUE, 3]',
|
|
192
|
+
"(test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK']) OR attr3 <= 12": null,
|
|
193
|
+
"test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK'] OR attr3 <= 12 AND attr4 = 'ok'": null,
|
|
194
|
+
"test.attr1 = 'plop' AND (attr2 IN ['TEST', 'OK'] OR attr3 <= 12) AND attr4 = 'ok'": null,
|
|
195
|
+
"test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK'] AND attr3 <= 12 AND attr4 = 'ok'": null,
|
|
196
|
+
"a = 1 OR b = 2": null,
|
|
197
|
+
"a = 1 AND b = 2 OR c = 3 AND d = 4": null,
|
|
198
|
+
"a = 1 AND b = 2 OR c = 3 AND d = 4 OR e = 5 AND f = 6": null,
|
|
199
|
+
"a = 1 AND (b = 2 OR (c = 3 AND (d = 4 OR e = 5))) AND f = 6": null,
|
|
200
|
+
"": true,
|
|
201
|
+
'test.attr1 LIKE "pl_p"': true,
|
|
202
|
+
'test.attr1 LIKE "pl__p"': false,
|
|
203
|
+
'attr3 LIKE "1_"': true,
|
|
204
|
+
"attr3 >= 12": true,
|
|
205
|
+
"attr3 <= 12": false,
|
|
206
|
+
"attr3 != 12": true,
|
|
207
|
+
"attr3 > 12": true,
|
|
208
|
+
"attr3 < 13": false,
|
|
209
|
+
"attr5 CONTAINS 'test'": true,
|
|
210
|
+
"attr5 CONTAINS 'test2'": false,
|
|
211
|
+
'test.attr1 LIKE "pl%"': true,
|
|
212
|
+
"a = 1 AND b=2 OR a=1 AND b=3": "( a = 1 AND b = 2 ) OR ( a = 1 AND b = 3 )",
|
|
213
|
+
"a = 1 ORDER BY a": null,
|
|
214
|
+
"a = 1 ORDER BY a DESC, b ASC": null,
|
|
215
|
+
"(attr3 >= 12)": true
|
|
216
|
+
};
|
|
217
|
+
for (const query in queryMap) {
|
|
218
|
+
const validator = new WebdaQL.QueryValidator(query);
|
|
219
|
+
assert.strictEqual(validator.displayTree().replace(/\s/g, ""), query.replace(/\s/g, ""));
|
|
220
|
+
if (typeof queryMap[query] === "string") {
|
|
221
|
+
assert.strictEqual(validator.getExpression().toString(), queryMap[query], `Failed optimization of query: ${query} => ${validator.getExpression().toString()}`);
|
|
222
|
+
}
|
|
223
|
+
else if (typeof queryMap[query] === "boolean") {
|
|
224
|
+
assert.strictEqual(validator.eval(targets[0]), queryMap[query], `Failed query: ${query}`);
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
console.log("QUERY", query);
|
|
228
|
+
console.log("OPTIMIZED QUERY", validator.getExpression().toString(), "=>", validator.eval(targets[0]));
|
|
229
|
+
}
|
|
65
230
|
}
|
|
66
|
-
|
|
67
|
-
|
|
231
|
+
}
|
|
232
|
+
prependQuery() {
|
|
233
|
+
// merge method is tested through the prependQuery helper
|
|
234
|
+
const strictEqual = (arg1, arg2) => {
|
|
235
|
+
// Ensure it is parsable
|
|
236
|
+
new WebdaQL.QueryValidator(arg1);
|
|
237
|
+
assert.deepStrictEqual(arg1, arg2);
|
|
238
|
+
};
|
|
239
|
+
strictEqual(WebdaQL.PrependCondition("", "test='plop'"), 'test = "plop"');
|
|
240
|
+
strictEqual(WebdaQL.PrependCondition("test='plop'", ""), 'test = "plop"');
|
|
241
|
+
strictEqual(WebdaQL.PrependCondition("test='plip'", "test='plop'"), 'test = "plip" AND test = "plop"');
|
|
242
|
+
strictEqual(WebdaQL.PrependCondition("ORDER BY test", "test='plop'"), 'test = "plop" ORDER BY test ASC');
|
|
243
|
+
strictEqual(WebdaQL.PrependCondition("ORDER BY test LIMIT 100", "test='plop'"), 'test = "plop" ORDER BY test ASC LIMIT 100');
|
|
244
|
+
strictEqual(WebdaQL.PrependCondition("ORDER BY test DESC LIMIT 100", "test='plop'"), 'test = "plop" ORDER BY test DESC LIMIT 100');
|
|
245
|
+
strictEqual(WebdaQL.PrependCondition("test='plip' ORDER BY test ASC LIMIT 100", "test='plop'"), 'test = "plip" AND test = "plop" ORDER BY test ASC LIMIT 100');
|
|
246
|
+
strictEqual(WebdaQL.PrependCondition("test='plip' LIMIT 100", "test='plop'"), 'test = "plip" AND test = "plop" LIMIT 100');
|
|
247
|
+
strictEqual(WebdaQL.PrependCondition("test='plip' OFFSET 'test'", "test='plop'"), 'test = "plip" AND test = "plop" OFFSET "test"');
|
|
248
|
+
strictEqual(WebdaQL.PrependCondition("test='ORDER BY plop' OFFSET 'test'", "test='plop'"), 'test = "ORDER BY plop" AND test = "plop" OFFSET "test"');
|
|
249
|
+
strictEqual(WebdaQL.PrependCondition('test="ORDER BY plop" LIMIT 100', "test='plop'"), 'test = "ORDER BY plop" AND test = "plop" LIMIT 100');
|
|
250
|
+
// Composed ORDER BY
|
|
251
|
+
strictEqual(WebdaQL.PrependCondition('test="plop" ORDER BY ab ASC LIMIT 100', "ORDER BY forced DESC"), 'test = "plop" ORDER BY forced DESC, ab ASC LIMIT 100');
|
|
252
|
+
// Opposite ORDER BY
|
|
253
|
+
strictEqual(WebdaQL.PrependCondition('test="plop" ORDER BY forced ASC LIMIT 100', "ORDER BY forced DESC"), 'test = "plop" ORDER BY forced DESC LIMIT 100');
|
|
254
|
+
// Overwrite LIMIT
|
|
255
|
+
strictEqual(WebdaQL.PrependCondition('test="plop" ORDER BY forced ASC LIMIT 100', "LIMIT 5"), 'test = "plop" ORDER BY forced ASC LIMIT 5');
|
|
256
|
+
// Overwrite OFFSET
|
|
257
|
+
strictEqual(WebdaQL.PrependCondition('OFFSET "test"', "OFFSET 'plop'"), 'OFFSET "plop"');
|
|
258
|
+
strictEqual(WebdaQL.PrependCondition('plop = "ok"', "OFFSET 'plop'"), 'plop = "ok" OFFSET "plop"');
|
|
259
|
+
}
|
|
260
|
+
likeRegexp() {
|
|
261
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("test"), /test/);
|
|
262
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t_est"), /t.{1}est/);
|
|
263
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("_test"), /.{1}test/);
|
|
264
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t\\_est"), /t_est/);
|
|
265
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t%est"), /t.*est/);
|
|
266
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("%te?st"), /.*te\?st/);
|
|
267
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t\\%est"), /t%est/);
|
|
268
|
+
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t\\eest"), /t\\est/);
|
|
269
|
+
}
|
|
270
|
+
simple() {
|
|
271
|
+
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 = 'plop'").eval(targets[0]), true);
|
|
272
|
+
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 = 'plop2'").eval(targets[0]), false);
|
|
273
|
+
}
|
|
274
|
+
contains() {
|
|
275
|
+
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 CONTAINS 'plop2'").eval(targets[0]), false);
|
|
276
|
+
}
|
|
277
|
+
andQuery() {
|
|
278
|
+
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK']").eval(targets[0]), true);
|
|
279
|
+
}
|
|
280
|
+
orQuery() {
|
|
281
|
+
new WebdaQL.QueryValidator("(test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK']) OR attr3 <= 12").eval(targets[0]);
|
|
282
|
+
}
|
|
283
|
+
multipleQuery() {
|
|
284
|
+
new WebdaQL.QueryValidator("test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK'] OR attr3 <= 12 AND attr4 = 'ok'").eval(targets[0]);
|
|
285
|
+
new WebdaQL.QueryValidator("test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK'] AND attr3 <= 12 AND attr4 = 'ok'").eval(targets[0]);
|
|
286
|
+
}
|
|
287
|
+
unsanitize() {
|
|
288
|
+
assert.strictEqual(WebdaQL.unsanitize("test.attr1 < 12 AND attr2 > 13"), "test.attr1 < 12 AND attr2 > 13");
|
|
289
|
+
}
|
|
290
|
+
limitOffset() {
|
|
291
|
+
let val = new WebdaQL.QueryValidator('LIMIT 10 OFFSET "pl"');
|
|
292
|
+
// getQuery
|
|
293
|
+
val.getQuery();
|
|
294
|
+
assert.strictEqual(val.getLimit(), 10);
|
|
295
|
+
assert.strictEqual(val.getOffset(), "pl");
|
|
296
|
+
val = new WebdaQL.QueryValidator('OFFSET "pl2"');
|
|
297
|
+
assert.strictEqual(val.getLimit(), 1000);
|
|
298
|
+
assert.strictEqual(val.getOffset(), "pl2");
|
|
299
|
+
}
|
|
300
|
+
badQuery() {
|
|
301
|
+
assert.throws(() => new WebdaQL.QueryValidator("test lo 'plop'").eval(targets[0]));
|
|
302
|
+
}
|
|
303
|
+
setters() {
|
|
304
|
+
let target = {};
|
|
305
|
+
new WebdaQL.SetterValidator('i = 10 AND j = "12"').eval(target);
|
|
306
|
+
assert.strictEqual(target.i, 10);
|
|
307
|
+
assert.strictEqual(target.j, "12");
|
|
308
|
+
target = {};
|
|
309
|
+
new WebdaQL.SetterValidator("").eval(target);
|
|
310
|
+
assert.strictEqual(Object.keys(target).length, 0);
|
|
311
|
+
new WebdaQL.SetterValidator('test.i = 10 AND j.k.l = "12"').eval(target);
|
|
312
|
+
assert.strictEqual(target.test.i, 10);
|
|
313
|
+
assert.strictEqual(target.j.k.l, "12");
|
|
314
|
+
target = {};
|
|
315
|
+
new WebdaQL.SetterValidator("test.__proto__.test = 10").eval(target);
|
|
316
|
+
assert.strictEqual(target.__proto__.test, undefined);
|
|
317
|
+
assert.throws(() => new WebdaQL.SetterValidator('i = 10 OR j = "12"').eval(target), SyntaxError);
|
|
318
|
+
assert.throws(() => new WebdaQL.SetterValidator('i > 10 AND j = "12"').eval(target), SyntaxError);
|
|
319
|
+
}
|
|
320
|
+
parse() {
|
|
321
|
+
// Basic query with filter, order, limit, offset
|
|
322
|
+
const query = WebdaQL.parse("status = 'active' AND age > 18 ORDER BY name DESC LIMIT 50 OFFSET 'token123'");
|
|
323
|
+
assert.ok(query.filter instanceof WebdaQL.AndExpression);
|
|
324
|
+
assert.strictEqual(query.limit, 50);
|
|
325
|
+
assert.strictEqual(query.continuationToken, "token123");
|
|
326
|
+
assert.deepStrictEqual(query.orderBy, [{ field: "name", direction: "DESC" }]);
|
|
327
|
+
// toString returns the original parse tree reconstruction
|
|
328
|
+
assert.ok(query.toString().includes("status"));
|
|
329
|
+
// Empty query
|
|
330
|
+
const empty = WebdaQL.parse("");
|
|
331
|
+
assert.ok(empty.filter instanceof WebdaQL.AndExpression);
|
|
332
|
+
assert.strictEqual(empty.filter.children.length, 0);
|
|
333
|
+
// Filter-only query
|
|
334
|
+
const simple = WebdaQL.parse("x = 1");
|
|
335
|
+
assert.ok(simple.filter.eval({ x: 1 }));
|
|
336
|
+
assert.ok(!simple.filter.eval({ x: 2 }));
|
|
337
|
+
}
|
|
338
|
+
partialValidator() {
|
|
339
|
+
const validator = new WebdaQL.PartialValidator("attr1 = 'plop' AND attr2 = 'ok'");
|
|
340
|
+
assert.ok(validator.eval({ attr1: "plop" }));
|
|
341
|
+
assert.ok(validator.wasPartialMatch());
|
|
342
|
+
assert.ok(!validator.eval({ attr1: "plop" }, false));
|
|
343
|
+
assert.ok(!validator.eval({ attr1: "plop2" }));
|
|
344
|
+
assert.ok(new WebdaQL.PartialValidator("attr1 = 'plop' AND attr2 LIKE '?ok' AND attr3 IN ['test'] AND attr4 CONTAINS 'plop'").eval({ attr1: "plop" }));
|
|
345
|
+
}
|
|
346
|
+
mergeTypeMismatch() {
|
|
347
|
+
// AND filter merged with OR type — should wrap in OrExpression
|
|
348
|
+
const v1 = new WebdaQL.QueryValidator("a = 1 AND b = 2");
|
|
349
|
+
v1.merge("c = 3", "OR");
|
|
350
|
+
const expr1 = v1.getExpression();
|
|
351
|
+
assert.ok(expr1 instanceof WebdaQL.OrExpression);
|
|
352
|
+
// OR filter merged with AND type — should wrap in AndExpression
|
|
353
|
+
const v2 = new WebdaQL.QueryValidator("a = 1 OR b = 2");
|
|
354
|
+
v2.merge("c = 3", "AND");
|
|
355
|
+
const expr2 = v2.getExpression();
|
|
356
|
+
assert.ok(expr2 instanceof WebdaQL.AndExpression);
|
|
357
|
+
}
|
|
358
|
+
getOffsetFallback() {
|
|
359
|
+
// Query without OFFSET should return ""
|
|
360
|
+
const v = new WebdaQL.QueryValidator("a = 1");
|
|
361
|
+
assert.strictEqual(v.getOffset(), "");
|
|
362
|
+
// Query with OFFSET
|
|
363
|
+
const v2 = new WebdaQL.QueryValidator('OFFSET "tok"');
|
|
364
|
+
assert.strictEqual(v2.getOffset(), "tok");
|
|
365
|
+
}
|
|
366
|
+
expressionToString() {
|
|
367
|
+
// Test toString at different depths
|
|
368
|
+
const v = new WebdaQL.QueryValidator("a = 1 AND (b = 2 OR c = 3)");
|
|
369
|
+
const str = v.getExpression().toString();
|
|
370
|
+
assert.ok(str.includes("a = 1"));
|
|
371
|
+
// Empty AND/OR toString
|
|
372
|
+
const emptyAnd = new WebdaQL.AndExpression([]);
|
|
373
|
+
assert.strictEqual(emptyAnd.toString(), "");
|
|
374
|
+
assert.strictEqual(emptyAnd.eval({}), true);
|
|
375
|
+
const emptyOr = new WebdaQL.OrExpression([]);
|
|
376
|
+
assert.strictEqual(emptyOr.toString(), "");
|
|
377
|
+
assert.strictEqual(emptyOr.eval({}), true);
|
|
378
|
+
// Test ComparisonExpression toString with various operators
|
|
379
|
+
const comp = new WebdaQL.ComparisonExpression("!=", "field", "test");
|
|
380
|
+
assert.strictEqual(comp.toString(), 'field != "test"');
|
|
381
|
+
// Boolean values in toString
|
|
382
|
+
const boolComp = new WebdaQL.ComparisonExpression("=", "field", true);
|
|
383
|
+
assert.strictEqual(boolComp.toString(), "field = TRUE");
|
|
384
|
+
// Array values in toString
|
|
385
|
+
const arrComp = new WebdaQL.ComparisonExpression("IN", "field", ["a", 1, true]);
|
|
386
|
+
assert.ok(arrComp.toString().includes("IN"));
|
|
387
|
+
}
|
|
388
|
+
hasCondition() {
|
|
389
|
+
const v1 = new WebdaQL.QueryValidator("a = 1");
|
|
390
|
+
assert.ok(v1.hasCondition());
|
|
391
|
+
const v2 = new WebdaQL.QueryValidator("");
|
|
392
|
+
assert.ok(!v2.hasCondition());
|
|
393
|
+
const v3 = new WebdaQL.QueryValidator("ORDER BY a");
|
|
394
|
+
assert.ok(!v3.hasCondition());
|
|
395
|
+
}
|
|
396
|
+
queryValidatorToString() {
|
|
397
|
+
const v = new WebdaQL.QueryValidator("a = 1 ORDER BY b LIMIT 10");
|
|
398
|
+
const str = v.toString();
|
|
399
|
+
assert.ok(str.includes("a = 1"));
|
|
400
|
+
assert.ok(str.includes("ORDER BY"));
|
|
401
|
+
assert.ok(str.includes("LIMIT 10"));
|
|
402
|
+
}
|
|
403
|
+
complexQueries() {
|
|
404
|
+
// Nested parentheses
|
|
405
|
+
new WebdaQL.QueryValidator("(a = 1 OR b = 2) AND (c = 3 OR d = 4)").eval({ a: 1, c: 3 });
|
|
406
|
+
// Multiple IN values
|
|
407
|
+
const v = new WebdaQL.QueryValidator("field IN ['a', 'b', 'c', 'd']");
|
|
408
|
+
assert.ok(v.eval({ field: "b" }));
|
|
409
|
+
assert.ok(!v.eval({ field: "e" }));
|
|
410
|
+
// Multiple ORDER BY
|
|
411
|
+
const v2 = new WebdaQL.QueryValidator("a = 1 ORDER BY x DESC, y ASC, z DESC");
|
|
412
|
+
assert.strictEqual(v2.toString().includes("ORDER BY"), true);
|
|
413
|
+
// LIMIT + OFFSET + ORDER BY together
|
|
414
|
+
const v3 = new WebdaQL.QueryValidator('a = 1 ORDER BY b LIMIT 5 OFFSET "page2"');
|
|
415
|
+
assert.strictEqual(v3.getOffset(), "page2");
|
|
416
|
+
// Numeric comparisons
|
|
417
|
+
assert.ok(new WebdaQL.QueryValidator("x > 5").eval({ x: 10 }));
|
|
418
|
+
assert.ok(new WebdaQL.QueryValidator("x >= 10").eval({ x: 10 }));
|
|
419
|
+
assert.ok(new WebdaQL.QueryValidator("x < 10").eval({ x: 5 }));
|
|
420
|
+
assert.ok(new WebdaQL.QueryValidator("x <= 10").eval({ x: 10 }));
|
|
421
|
+
// FALSE boolean
|
|
422
|
+
assert.ok(new WebdaQL.QueryValidator("x = FALSE").eval({ x: false }));
|
|
423
|
+
}
|
|
424
|
+
containsNonArray() {
|
|
425
|
+
// CONTAINS on non-array should return false
|
|
426
|
+
assert.ok(!new WebdaQL.QueryValidator("x CONTAINS 'a'").eval({ x: "hello" }));
|
|
427
|
+
assert.ok(!new WebdaQL.QueryValidator("x CONTAINS 'a'").eval({ x: 42 }));
|
|
428
|
+
}
|
|
429
|
+
likeOnNonString() {
|
|
430
|
+
// LIKE on numeric value should toString and match
|
|
431
|
+
assert.ok(new WebdaQL.QueryValidator("x LIKE '1%'").eval({ x: 123 }));
|
|
432
|
+
}
|
|
433
|
+
likeOnMissingAttribute() {
|
|
434
|
+
// A missing or null attribute never matches instead of throwing
|
|
435
|
+
assert.ok(!new WebdaQL.QueryValidator("x LIKE '%a%'").eval({}));
|
|
436
|
+
assert.ok(!new WebdaQL.QueryValidator("x LIKE '%a%'").eval({ x: null }));
|
|
437
|
+
assert.ok(new WebdaQL.QueryValidator("x LIKE '%a%' OR y LIKE '%a%'").eval({ y: "abc" }));
|
|
438
|
+
}
|
|
439
|
+
quotedLiterals() {
|
|
440
|
+
// Doubled quotes (what escapeValue produces) and backslash-escaped quotes are unescaped
|
|
441
|
+
assert.ok(new WebdaQL.QueryValidator("k = 'it''s'").eval({ k: "it's" }));
|
|
442
|
+
assert.ok(new WebdaQL.QueryValidator('k = "say ""hi"""').eval({ k: 'say "hi"' }));
|
|
443
|
+
assert.ok(new WebdaQL.QueryValidator("k = 'it\\'s'").eval({ k: "it's" }));
|
|
444
|
+
assert.strictEqual(WebdaQL.unescapeStringLiteral("'a''b'"), "a'b");
|
|
445
|
+
// Backslash handling
|
|
446
|
+
assert.ok(new WebdaQL.QueryValidator("k = 'a\\\\b'").eval({ k: "a\\b" }));
|
|
447
|
+
assert.strictEqual(WebdaQL.unescapeStringLiteral("'a\\\\''b'"), "a\\'b");
|
|
448
|
+
// LIKE escapes are not touched
|
|
449
|
+
assert.ok(new WebdaQL.QueryValidator("k LIKE '100\\%'").eval({ k: "100%" }));
|
|
450
|
+
assert.ok(!new WebdaQL.QueryValidator("k LIKE '100\\%'").eval({ k: "1000" }));
|
|
451
|
+
}
|
|
452
|
+
lexerIntrospection() {
|
|
453
|
+
const lexer = new WebdaQLLexer(CharStreams.fromString("a = 1"));
|
|
454
|
+
assert.ok(lexer.grammarFileName);
|
|
455
|
+
assert.ok(Array.isArray(lexer.ruleNames));
|
|
456
|
+
assert.ok(typeof lexer.serializedATN === "string");
|
|
457
|
+
assert.ok(Array.isArray(lexer.channelNames));
|
|
458
|
+
assert.ok(Array.isArray(lexer.modeNames));
|
|
459
|
+
}
|
|
460
|
+
parserIntrospection() {
|
|
461
|
+
const lexer = new WebdaQLLexer(CharStreams.fromString("a = 1"));
|
|
462
|
+
const tokenStream = new CommonTokenStream(lexer);
|
|
463
|
+
const parser = new WebdaQLParserParser(tokenStream);
|
|
464
|
+
assert.ok(parser.vocabulary);
|
|
465
|
+
assert.strictEqual(parser.grammarFileName, "WebdaQLParser.g4");
|
|
466
|
+
assert.ok(Array.isArray(parser.ruleNames));
|
|
467
|
+
assert.ok(typeof parser.serializedATN === "string");
|
|
468
|
+
}
|
|
469
|
+
listenerWalk() {
|
|
470
|
+
const lexer = new WebdaQLLexer(CharStreams.fromString('a = 1 AND b LIKE "test%" AND c IN [1, "x", TRUE] AND d CONTAINS "v" AND (e = 2 OR f = 3) ORDER BY g DESC LIMIT 10 OFFSET "tok"'));
|
|
471
|
+
const tokenStream = new CommonTokenStream(lexer);
|
|
472
|
+
const parser = new WebdaQLParserParser(tokenStream);
|
|
473
|
+
const tree = parser.webdaql();
|
|
474
|
+
const visited = [];
|
|
475
|
+
const listener = {};
|
|
476
|
+
// Dynamically add all enter/exit methods to track visits
|
|
477
|
+
for (const rule of parser.ruleNames) {
|
|
478
|
+
const capitalized = rule.charAt(0).toUpperCase() + rule.slice(1);
|
|
479
|
+
listener[`enter${capitalized}`] = () => visited.push(`enter${capitalized}`);
|
|
480
|
+
listener[`exit${capitalized}`] = () => visited.push(`exit${capitalized}`);
|
|
68
481
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
482
|
+
ParseTreeWalker.DEFAULT.walk(listener, tree);
|
|
483
|
+
assert.ok(visited.includes("enterWebdaql"));
|
|
484
|
+
assert.ok(visited.includes("exitWebdaql"));
|
|
485
|
+
assert.ok(visited.length > 20);
|
|
486
|
+
}
|
|
487
|
+
contextAccessors() {
|
|
488
|
+
// Exercise parser context accessor methods
|
|
489
|
+
const lexer = new WebdaQLLexer(CharStreams.fromString("a = 1 AND b IN [1, 2] ORDER BY c DESC"));
|
|
490
|
+
const tokenStream = new CommonTokenStream(lexer);
|
|
491
|
+
const parser = new WebdaQLParserParser(tokenStream);
|
|
492
|
+
const tree = parser.webdaql();
|
|
493
|
+
// Access children of the parse tree
|
|
494
|
+
assert.ok(tree.expression());
|
|
495
|
+
const orderExpr = tree.orderExpression();
|
|
496
|
+
assert.ok(orderExpr);
|
|
497
|
+
assert.strictEqual(tree.limitExpression(), undefined);
|
|
498
|
+
// Exercise ruleIndex
|
|
499
|
+
assert.strictEqual(typeof tree.ruleIndex, "number");
|
|
500
|
+
}
|
|
501
|
+
setterAssignment() {
|
|
502
|
+
// Test SetterValidator assignments
|
|
503
|
+
const setter = new WebdaQL.SetterValidator("a = 1 AND b = 'hello' AND c = TRUE");
|
|
504
|
+
const target = { a: 0, b: "", c: false };
|
|
505
|
+
setter.eval(target);
|
|
506
|
+
assert.strictEqual(target.a, 1);
|
|
507
|
+
assert.strictEqual(target.b, "hello");
|
|
508
|
+
assert.strictEqual(target.c, true);
|
|
509
|
+
}
|
|
510
|
+
mergePreservesExistingMeta() {
|
|
511
|
+
// Same-type merge (AND + AND) should push into existing children
|
|
512
|
+
const v = new WebdaQL.QueryValidator("a = 1 AND b = 2");
|
|
513
|
+
v.merge("c = 3", "AND");
|
|
514
|
+
const expr = v.getExpression();
|
|
515
|
+
assert.ok(expr instanceof WebdaQL.AndExpression);
|
|
516
|
+
assert.strictEqual(expr.children.length, 3);
|
|
517
|
+
}
|
|
518
|
+
booleanLiterals() {
|
|
519
|
+
const check = (query, target = {}) => new WebdaQL.QueryValidator(query).eval(target);
|
|
520
|
+
assert.strictEqual(check("TRUE"), true);
|
|
521
|
+
assert.strictEqual(check("FALSE"), false);
|
|
522
|
+
assert.strictEqual(check("(TRUE)"), true);
|
|
523
|
+
assert.strictEqual(check("TRUE AND x = 1", { x: 1 }), true);
|
|
524
|
+
assert.strictEqual(check("TRUE AND x = 1", { x: 2 }), false);
|
|
525
|
+
assert.strictEqual(check("FALSE OR x = 1", { x: 1 }), true);
|
|
526
|
+
assert.strictEqual(check("FALSE AND x = 1", { x: 1 }), false);
|
|
527
|
+
assert.strictEqual(check("TRUE OR x = 1", { x: 2 }), true);
|
|
528
|
+
assert.strictEqual(check("x = 1 OR (y = 2 AND FALSE)", { y: 2 }), false);
|
|
529
|
+
}
|
|
530
|
+
booleanLiteralsFold() {
|
|
531
|
+
// Store query translators only ever see the existing expression classes
|
|
532
|
+
const all = WebdaQL.parse("TRUE").filter;
|
|
533
|
+
assert.ok(all instanceof WebdaQL.AndExpression);
|
|
534
|
+
assert.strictEqual(all.children.length, 0);
|
|
535
|
+
assert.strictEqual(WebdaQL.parse("TRUE AND x = 1").filter.toString(), "x = 1");
|
|
536
|
+
assert.ok(WebdaQL.parse("TRUE OR x = 1").filter instanceof WebdaQL.AndExpression);
|
|
537
|
+
const none = WebdaQL.parse("FALSE").filter;
|
|
538
|
+
assert.ok(none instanceof WebdaQL.BooleanExpression);
|
|
539
|
+
assert.strictEqual(none.toString(), "FALSE");
|
|
540
|
+
assert.strictEqual(WebdaQL.parse("x = 1 AND FALSE").filter.toString(), "FALSE");
|
|
541
|
+
}
|
|
542
|
+
bareAtomsAreSyntaxErrors() {
|
|
543
|
+
assert.throws(() => new WebdaQL.QueryValidator("active"), SyntaxError);
|
|
544
|
+
assert.throws(() => new WebdaQL.QueryValidator("42"), SyntaxError);
|
|
545
|
+
assert.throws(() => new WebdaQL.QueryValidator("x = 1 AND 'a'"), SyntaxError);
|
|
546
|
+
}
|
|
547
|
+
partialValidatorWithBooleans() {
|
|
548
|
+
// A missing attribute is a partial match, TRUE is folded away
|
|
549
|
+
assert.ok(new WebdaQL.PartialValidator("TRUE AND x = 1").eval({}));
|
|
550
|
+
assert.ok(!new WebdaQL.PartialValidator("FALSE").eval({}));
|
|
551
|
+
}
|
|
552
|
+
isNull() {
|
|
553
|
+
const target = { a: null, b: "x", c: 0, d: false, e: "", nested: { f: null, g: 1 } };
|
|
554
|
+
const cases = {
|
|
555
|
+
"a IS NULL": true,
|
|
556
|
+
"a IS NOT NULL": false,
|
|
557
|
+
"missing IS NULL": true,
|
|
558
|
+
"missing IS NOT NULL": false,
|
|
559
|
+
"b IS NULL": false,
|
|
560
|
+
"b IS NOT NULL": true,
|
|
561
|
+
// Falsy values are not null
|
|
562
|
+
"c IS NOT NULL": true,
|
|
563
|
+
"d IS NOT NULL": true,
|
|
564
|
+
"e IS NOT NULL": true,
|
|
565
|
+
"nested.f IS NULL": true,
|
|
566
|
+
"nested.g IS NOT NULL": true,
|
|
567
|
+
"nested.missing.deep IS NULL": true,
|
|
568
|
+
"a IS NULL AND b IS NOT NULL": true,
|
|
569
|
+
"a IS NOT NULL OR b = 'x'": true
|
|
570
|
+
};
|
|
571
|
+
for (const [query, expected] of Object.entries(cases)) {
|
|
572
|
+
assert.strictEqual(new WebdaQL.QueryValidator(query).eval(target), expected, query);
|
|
72
573
|
}
|
|
574
|
+
// Keywords only win on an exact match: identifiers starting with them still parse
|
|
575
|
+
assert.ok(new WebdaQL.QueryValidator("notes IS NOT NULL AND isActive = TRUE AND nullable IS NULL").eval({
|
|
576
|
+
notes: "n",
|
|
577
|
+
isActive: true
|
|
578
|
+
}));
|
|
579
|
+
// NULL is not a value
|
|
580
|
+
assert.throws(() => new WebdaQL.QueryValidator("a = NULL"), SyntaxError);
|
|
581
|
+
assert.throws(() => new WebdaQL.QueryValidator("a IS 'x'"), SyntaxError);
|
|
73
582
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
likeRegexp() {
|
|
104
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("test"), /test/);
|
|
105
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t_est"), /t.{1}est/);
|
|
106
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("_test"), /.{1}test/);
|
|
107
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t\\_est"), /t_est/);
|
|
108
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t%est"), /t.*est/);
|
|
109
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("%te?st"), /.*te\?st/);
|
|
110
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t\\%est"), /t%est/);
|
|
111
|
-
assert.deepStrictEqual(WebdaQL.ComparisonExpression.likeToRegex("t\\eest"), /t\\est/);
|
|
112
|
-
}
|
|
113
|
-
simple() {
|
|
114
|
-
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 = 'plop'").eval(targets[0]), true);
|
|
115
|
-
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 = 'plop2'").eval(targets[0]), false);
|
|
116
|
-
}
|
|
117
|
-
contains() {
|
|
118
|
-
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 CONTAINS 'plop2'").eval(targets[0]), false);
|
|
119
|
-
}
|
|
120
|
-
andQuery() {
|
|
121
|
-
assert.strictEqual(new WebdaQL.QueryValidator("test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK']").eval(targets[0]), true);
|
|
122
|
-
}
|
|
123
|
-
orQuery() {
|
|
124
|
-
new WebdaQL.QueryValidator("(test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK']) OR attr3 <= 12").eval(targets[0]);
|
|
125
|
-
}
|
|
126
|
-
multipleQuery() {
|
|
127
|
-
new WebdaQL.QueryValidator("test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK'] OR attr3 <= 12 AND attr4 = 'ok'").eval(targets[0]);
|
|
128
|
-
new WebdaQL.QueryValidator("test.attr1 = 'plop' AND attr2 IN ['TEST', 'OK'] AND attr3 <= 12 AND attr4 = 'ok'").eval(targets[0]);
|
|
129
|
-
}
|
|
130
|
-
unsanitize() {
|
|
131
|
-
assert.strictEqual(WebdaQL.unsanitize("test.attr1 < 12 AND attr2 > 13"), "test.attr1 < 12 AND attr2 > 13");
|
|
132
|
-
}
|
|
133
|
-
limitOffset() {
|
|
134
|
-
let val = new WebdaQL.QueryValidator('LIMIT 10 OFFSET "pl"');
|
|
135
|
-
// getQuery
|
|
136
|
-
val.getQuery();
|
|
137
|
-
assert.strictEqual(val.getLimit(), 10);
|
|
138
|
-
assert.strictEqual(val.getOffset(), "pl");
|
|
139
|
-
val = new WebdaQL.QueryValidator('OFFSET "pl2"');
|
|
140
|
-
assert.strictEqual(val.getLimit(), 1000);
|
|
141
|
-
assert.strictEqual(val.getOffset(), "pl2");
|
|
142
|
-
}
|
|
143
|
-
badQuery() {
|
|
144
|
-
assert.throws(() => new WebdaQL.QueryValidator("test lo 'plop'").eval(targets[0]));
|
|
145
|
-
}
|
|
146
|
-
setters() {
|
|
147
|
-
let target = {};
|
|
148
|
-
new WebdaQL.SetterValidator('i = 10 AND j = "12"').eval(target);
|
|
149
|
-
assert.strictEqual(target.i, 10);
|
|
150
|
-
assert.strictEqual(target.j, "12");
|
|
151
|
-
target = {};
|
|
152
|
-
new WebdaQL.SetterValidator("").eval(target);
|
|
153
|
-
assert.strictEqual(Object.keys(target).length, 0);
|
|
154
|
-
new WebdaQL.SetterValidator('test.i = 10 AND j.k.l = "12"').eval(target);
|
|
155
|
-
assert.strictEqual(target.test.i, 10);
|
|
156
|
-
assert.strictEqual(target.j.k.l, "12");
|
|
157
|
-
target = {};
|
|
158
|
-
new WebdaQL.SetterValidator("test.__proto__.test = 10").eval(target);
|
|
159
|
-
assert.strictEqual(target.__proto__.test, undefined);
|
|
160
|
-
assert.throws(() => new WebdaQL.SetterValidator('i = 10 OR j = "12"').eval(target), SyntaxError);
|
|
161
|
-
assert.throws(() => new WebdaQL.SetterValidator('i > 10 AND j = "12"').eval(target), SyntaxError);
|
|
162
|
-
}
|
|
163
|
-
partialValidator() {
|
|
164
|
-
const validator = new WebdaQL.PartialValidator("attr1 = 'plop' AND attr2 = 'ok'");
|
|
165
|
-
assert.ok(validator.eval({ attr1: "plop" }));
|
|
166
|
-
assert.ok(validator.wasPartialMatch());
|
|
167
|
-
assert.ok(!validator.eval({ attr1: "plop" }, false));
|
|
168
|
-
assert.ok(!validator.eval({ attr1: "plop2" }));
|
|
169
|
-
assert.ok(new WebdaQL.PartialValidator("attr1 = 'plop' AND attr2 LIKE '?ok' AND attr3 IN ['test'] AND attr4 CONTAINS 'plop'").eval({ attr1: "plop" }));
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
__decorate([
|
|
173
|
-
test
|
|
174
|
-
], QueryTest.prototype, "dev", null);
|
|
175
|
-
__decorate([
|
|
176
|
-
test
|
|
177
|
-
], QueryTest.prototype, "prependQuery", null);
|
|
178
|
-
__decorate([
|
|
179
|
-
test
|
|
180
|
-
], QueryTest.prototype, "likeRegexp", null);
|
|
181
|
-
__decorate([
|
|
182
|
-
test
|
|
183
|
-
], QueryTest.prototype, "simple", null);
|
|
184
|
-
__decorate([
|
|
185
|
-
test
|
|
186
|
-
], QueryTest.prototype, "contains", null);
|
|
187
|
-
__decorate([
|
|
188
|
-
test
|
|
189
|
-
], QueryTest.prototype, "andQuery", null);
|
|
190
|
-
__decorate([
|
|
191
|
-
test
|
|
192
|
-
], QueryTest.prototype, "orQuery", null);
|
|
193
|
-
__decorate([
|
|
194
|
-
test
|
|
195
|
-
], QueryTest.prototype, "multipleQuery", null);
|
|
196
|
-
__decorate([
|
|
197
|
-
test
|
|
198
|
-
], QueryTest.prototype, "unsanitize", null);
|
|
199
|
-
__decorate([
|
|
200
|
-
test
|
|
201
|
-
], QueryTest.prototype, "limitOffset", null);
|
|
202
|
-
__decorate([
|
|
203
|
-
test
|
|
204
|
-
], QueryTest.prototype, "badQuery", null);
|
|
205
|
-
__decorate([
|
|
206
|
-
test
|
|
207
|
-
], QueryTest.prototype, "setters", null);
|
|
208
|
-
__decorate([
|
|
209
|
-
test
|
|
210
|
-
], QueryTest.prototype, "partialValidator", null);
|
|
211
|
-
QueryTest = __decorate([
|
|
212
|
-
suite
|
|
213
|
-
], QueryTest);
|
|
583
|
+
isNullToString() {
|
|
584
|
+
const expression = new WebdaQL.QueryValidator("a IS NULL AND b.c IS NOT NULL").getExpression();
|
|
585
|
+
assert.strictEqual(expression.toString(), "a IS NULL AND b.c IS NOT NULL");
|
|
586
|
+
const comparison = expression.children[0];
|
|
587
|
+
assert.strictEqual(comparison.operator, "IS NULL");
|
|
588
|
+
assert.deepStrictEqual(comparison.attribute, ["a"]);
|
|
589
|
+
// The printed query parses back to the same expression
|
|
590
|
+
assert.strictEqual(new WebdaQL.QueryValidator(expression.toString()).getExpression().toString(), expression.toString());
|
|
591
|
+
// Merging keeps the operators printable and parsable
|
|
592
|
+
assert.strictEqual(WebdaQL.PrependCondition("a IS NULL ORDER BY a", "b IS NOT NULL"), "a IS NULL AND b IS NOT NULL ORDER BY a ASC");
|
|
593
|
+
const merged = new WebdaQL.QueryValidator("a IS NULL").merge("b IS NOT NULL", "OR").toString();
|
|
594
|
+
assert.strictEqual(merged, "a IS NULL OR b IS NOT NULL");
|
|
595
|
+
assert.ok(new WebdaQL.QueryValidator(merged).eval({ a: null }));
|
|
596
|
+
}
|
|
597
|
+
isNullPartial() {
|
|
598
|
+
// A missing attribute is a partial match
|
|
599
|
+
const validator = new WebdaQL.PartialValidator("a IS NOT NULL AND b IS NULL");
|
|
600
|
+
assert.ok(validator.eval({}));
|
|
601
|
+
assert.ok(validator.wasPartialMatch());
|
|
602
|
+
assert.ok(!validator.eval({ a: null, b: null }));
|
|
603
|
+
assert.ok(validator.eval({ a: 1, b: null }));
|
|
604
|
+
assert.ok(!validator.eval({ a: 1, b: 2 }));
|
|
605
|
+
}
|
|
606
|
+
constructor() {
|
|
607
|
+
__runInitializers(this, _instanceExtraInitializers);
|
|
608
|
+
}
|
|
609
|
+
};
|
|
610
|
+
return QueryTest = _classThis;
|
|
611
|
+
})();
|
|
214
612
|
//# sourceMappingURL=query.spec.js.map
|