@itwin/ecsql-common 4.2.0-dev.10
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/LICENSE.md +9 -0
- package/README.md +11 -0
- package/lib/cjs/ECSqlAst.d.ts +1039 -0
- package/lib/cjs/ECSqlAst.d.ts.map +1 -0
- package/lib/cjs/ECSqlAst.js +2393 -0
- package/lib/cjs/ECSqlAst.js.map +1 -0
- package/lib/cjs/ecsql-common.d.ts +2 -0
- package/lib/cjs/ecsql-common.d.ts.map +1 -0
- package/lib/cjs/ecsql-common.js +22 -0
- package/lib/cjs/ecsql-common.js.map +1 -0
- package/lib/esm/ECSqlAst.d.ts +1039 -0
- package/lib/esm/ECSqlAst.d.ts.map +1 -0
- package/lib/esm/ECSqlAst.js +2384 -0
- package/lib/esm/ECSqlAst.js.map +1 -0
- package/lib/esm/ecsql-common.d.ts +2 -0
- package/lib/esm/ecsql-common.d.ts.map +1 -0
- package/lib/esm/ecsql-common.js +6 -0
- package/lib/esm/ecsql-common.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,2384 @@
|
|
|
1
|
+
import { asInstanceOf, isInstanceOf } from "@itwin/core-bentley";
|
|
2
|
+
/**
|
|
3
|
+
* Id returned by native code
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
var NativeExpIds;
|
|
7
|
+
(function (NativeExpIds) {
|
|
8
|
+
NativeExpIds["AllOrAny"] = "AllOrAnyExp";
|
|
9
|
+
NativeExpIds["Assignment"] = "AssignmentExp";
|
|
10
|
+
NativeExpIds["BetweenRangeValue"] = "BetweenRangeValueExp";
|
|
11
|
+
NativeExpIds["BinaryBoolean"] = "BinaryBooleanExp";
|
|
12
|
+
NativeExpIds["BinaryValue"] = "BinaryValueExp";
|
|
13
|
+
NativeExpIds["BooleanFactor"] = "BooleanFactorExp";
|
|
14
|
+
NativeExpIds["Cast"] = "CastExp";
|
|
15
|
+
NativeExpIds["ClassName"] = "ClassNameExp";
|
|
16
|
+
NativeExpIds["CommonTable"] = "CommonTableExp";
|
|
17
|
+
NativeExpIds["CommonTableBlock"] = "CommonTableBlockExp";
|
|
18
|
+
NativeExpIds["CommonTableBlockName"] = "CommonTableBlockNameExp";
|
|
19
|
+
NativeExpIds["CrossJoin"] = "CrossJoinExp";
|
|
20
|
+
NativeExpIds["DeleteStatement"] = "DeleteStatementExp";
|
|
21
|
+
NativeExpIds["DerivedProperty"] = "DerivedPropertyExp";
|
|
22
|
+
NativeExpIds["FunctionCall"] = "FunctionCallExp";
|
|
23
|
+
NativeExpIds["IIF"] = "IIFExp";
|
|
24
|
+
NativeExpIds["InsertStatement"] = "InsertStatementExp";
|
|
25
|
+
NativeExpIds["LikeRhsValue"] = "LikeRhsValueExp";
|
|
26
|
+
NativeExpIds["LimitOffset"] = "LimitOffsetExp";
|
|
27
|
+
NativeExpIds["LiteralValue"] = "LiteralValueExp";
|
|
28
|
+
NativeExpIds["MemberFunctionCall"] = "MemberFunctionCallExp";
|
|
29
|
+
NativeExpIds["NaturalJoin"] = "NaturalJoinExp";
|
|
30
|
+
NativeExpIds["Options"] = "OptionsExp";
|
|
31
|
+
NativeExpIds["OrderBySpec"] = "OrderBySpecExp";
|
|
32
|
+
NativeExpIds["Parameter"] = "ParameterExp";
|
|
33
|
+
NativeExpIds["PropertyName"] = "PropertyNameExp";
|
|
34
|
+
NativeExpIds["QualifiedJoin"] = "QualifiedJoinExp";
|
|
35
|
+
NativeExpIds["RowConstructor"] = "RowConstructor";
|
|
36
|
+
NativeExpIds["SearchCaseValue"] = "SearchCaseValueExp";
|
|
37
|
+
NativeExpIds["SelectStatement"] = "SelectStatementExp";
|
|
38
|
+
NativeExpIds["SingleSelectStatement"] = "SingleSelectStatementExp";
|
|
39
|
+
NativeExpIds["Subquery"] = "SubqueryExp";
|
|
40
|
+
NativeExpIds["SubqueryRef"] = "SubqueryRefExp";
|
|
41
|
+
NativeExpIds["SubqueryTest"] = "SubqueryTestExp";
|
|
42
|
+
NativeExpIds["TableValuedFunction"] = "TableValuedFunctionExp";
|
|
43
|
+
NativeExpIds["UnaryValue"] = "UnaryValueExp";
|
|
44
|
+
NativeExpIds["UpdateStatement"] = "UpdateStatementExp";
|
|
45
|
+
NativeExpIds["UsingRelationshipJoinExp"] = "UsingRelationshipJoinExp";
|
|
46
|
+
})(NativeExpIds || (NativeExpIds = {}));
|
|
47
|
+
/**
|
|
48
|
+
* Type of literal value.
|
|
49
|
+
* @alpha
|
|
50
|
+
*/
|
|
51
|
+
export var LiteralValueType;
|
|
52
|
+
(function (LiteralValueType) {
|
|
53
|
+
LiteralValueType["Null"] = "NULL";
|
|
54
|
+
LiteralValueType["String"] = "STRING";
|
|
55
|
+
LiteralValueType["Date"] = "DATE";
|
|
56
|
+
LiteralValueType["Time"] = "TIME";
|
|
57
|
+
LiteralValueType["Timestamp"] = "TIMESTAMP";
|
|
58
|
+
LiteralValueType["Raw"] = "RAW";
|
|
59
|
+
})(LiteralValueType || (LiteralValueType = {}));
|
|
60
|
+
/**
|
|
61
|
+
* Qualified JOIN type @see [[QualifiedJoinExpr]]
|
|
62
|
+
* @alpha
|
|
63
|
+
*/
|
|
64
|
+
export var JoinType;
|
|
65
|
+
(function (JoinType) {
|
|
66
|
+
JoinType["LeftOuter"] = "LEFT OUTER JOIN";
|
|
67
|
+
JoinType["RightOuter"] = "RIGHT OUTER JOIN";
|
|
68
|
+
JoinType["FullOuter"] = "FULL OUTER JOIN";
|
|
69
|
+
JoinType["Inner"] = "INNER JOIN";
|
|
70
|
+
})(JoinType || (JoinType = {}));
|
|
71
|
+
/**
|
|
72
|
+
* ECSql expr type supported @see [[Expr]]
|
|
73
|
+
* @alpha
|
|
74
|
+
*/
|
|
75
|
+
export var ExprType;
|
|
76
|
+
(function (ExprType) {
|
|
77
|
+
ExprType["Literal"] = "Literal";
|
|
78
|
+
ExprType["Unary"] = "Unary";
|
|
79
|
+
ExprType["Parameter"] = "Parameter";
|
|
80
|
+
ExprType["Cast"] = "Cast";
|
|
81
|
+
ExprType["BinaryValue"] = "BinaryValue";
|
|
82
|
+
ExprType["SearchCase"] = "SearchCase";
|
|
83
|
+
ExprType["IIF"] = "IIF";
|
|
84
|
+
ExprType["FuncCall"] = "FuncCall";
|
|
85
|
+
ExprType["PropertyName"] = "PropertyName";
|
|
86
|
+
ExprType["Subquery"] = "Subquery";
|
|
87
|
+
ExprType["Between"] = "Between";
|
|
88
|
+
// Match = "Match",
|
|
89
|
+
ExprType["Like"] = "Like";
|
|
90
|
+
ExprType["In"] = "In";
|
|
91
|
+
ExprType["Not"] = "Not";
|
|
92
|
+
ExprType["IsOfType"] = "IsOfType";
|
|
93
|
+
ExprType["IsNull"] = "IsNull";
|
|
94
|
+
ExprType["BinaryBoolean"] = "BinaryBoolean";
|
|
95
|
+
ExprType["SubqueryTest"] = "SubqueryTest";
|
|
96
|
+
ExprType["UsingRelationshipJoin"] = "UsingRelationshipJoin";
|
|
97
|
+
ExprType["QualifiedJoin"] = "QualifiedJoin";
|
|
98
|
+
ExprType["SubqueryRef"] = "SubqueryRef";
|
|
99
|
+
ExprType["CteBlockRef"] = "CteBlockRef";
|
|
100
|
+
ExprType["ClassName"] = "ClassName";
|
|
101
|
+
ExprType["TableValuedFunc"] = "TableValuedFunc";
|
|
102
|
+
ExprType["DerivedProperty"] = "DerivedProperty";
|
|
103
|
+
ExprType["SetClause"] = "SetClause";
|
|
104
|
+
ExprType["Select"] = "Select";
|
|
105
|
+
ExprType["ECSqlOptionsClause"] = "ECSqlOptions";
|
|
106
|
+
ExprType["CteBlock"] = "CteBlock";
|
|
107
|
+
ExprType["MemberFuncCall"] = "MemberFuncCall";
|
|
108
|
+
ExprType["Cte"] = "Cte";
|
|
109
|
+
ExprType["UpdateStatement"] = "UpdateStatement";
|
|
110
|
+
ExprType["InsertStatement"] = "InsertStatement";
|
|
111
|
+
ExprType["DeleteStatement"] = "DeleteStatement";
|
|
112
|
+
ExprType["SelectStatement"] = "SelectStatement";
|
|
113
|
+
ExprType["SelectionClause"] = "SelectionClause";
|
|
114
|
+
ExprType["WhereClause"] = "WhereClause";
|
|
115
|
+
ExprType["GroupByClause"] = "GroupByClause";
|
|
116
|
+
ExprType["HavingClause"] = "HavingCluase";
|
|
117
|
+
ExprType["FromClause"] = "FromClause";
|
|
118
|
+
ExprType["OrderByClause"] = "OrderByClause";
|
|
119
|
+
ExprType["OrderBySpec"] = "OrderBySpec";
|
|
120
|
+
ExprType["LimitClause"] = "LimitClause";
|
|
121
|
+
ExprType["Assignment"] = "Assignment";
|
|
122
|
+
})(ExprType || (ExprType = {}));
|
|
123
|
+
/**
|
|
124
|
+
* Allow to create statement expression tree from a ecsql
|
|
125
|
+
* @alpha
|
|
126
|
+
*/
|
|
127
|
+
export class ExprFactory {
|
|
128
|
+
constructor(provider) {
|
|
129
|
+
this.provider = provider;
|
|
130
|
+
}
|
|
131
|
+
async parseStatement(ecsql) {
|
|
132
|
+
return StatementExpr.deserialize(this.provider.parseECSql(ecsql));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Base class for all ECSql expressions.
|
|
137
|
+
* @alpha
|
|
138
|
+
*/
|
|
139
|
+
export class Expr {
|
|
140
|
+
constructor(expType) {
|
|
141
|
+
this.expType = expType;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Find instances of expressions matching the type in sub tree.
|
|
145
|
+
* @param type a subclass of Expr
|
|
146
|
+
* @returns
|
|
147
|
+
*/
|
|
148
|
+
findInstancesOf(type) {
|
|
149
|
+
const listOfT = [];
|
|
150
|
+
this.traverse((expr) => {
|
|
151
|
+
const inst = expr.asInstanceOf(type);
|
|
152
|
+
if (inst)
|
|
153
|
+
listOfT.push(inst);
|
|
154
|
+
});
|
|
155
|
+
return listOfT;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Allow to traverse the expression tree depth first
|
|
159
|
+
* @param callback this will be called for each expression traverse from first to last.
|
|
160
|
+
*/
|
|
161
|
+
traverse(callback) {
|
|
162
|
+
const list = [this];
|
|
163
|
+
let parent;
|
|
164
|
+
while (list.length > 0) {
|
|
165
|
+
const current = list.pop();
|
|
166
|
+
if (current) {
|
|
167
|
+
const rc = callback(current, parent);
|
|
168
|
+
if (typeof rc === "boolean") {
|
|
169
|
+
if (!rc)
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
parent = current;
|
|
173
|
+
list.push(...current.children.reverse());
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Test if class instance is of certain type
|
|
179
|
+
* @param type A class that extends from Expr
|
|
180
|
+
* @returns true if instances matches the type else return false.
|
|
181
|
+
*/
|
|
182
|
+
isInstanceOf(type) { return isInstanceOf(this, type); }
|
|
183
|
+
asInstanceOf(type) { return asInstanceOf(this, type); }
|
|
184
|
+
/**
|
|
185
|
+
* Convert expression tree to ECSQL.
|
|
186
|
+
* @param args args to ecsql writer.
|
|
187
|
+
* @returns ECSQL string
|
|
188
|
+
*/
|
|
189
|
+
toECSql(args) {
|
|
190
|
+
if (args) {
|
|
191
|
+
const customWriter = new ECSqlWriter(args);
|
|
192
|
+
this.writeTo(customWriter);
|
|
193
|
+
return customWriter.toString();
|
|
194
|
+
}
|
|
195
|
+
const defaultWriter = new ECSqlWriter();
|
|
196
|
+
this.writeTo(defaultWriter);
|
|
197
|
+
return defaultWriter.toString();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Base class for all ECSQL Statements. Here are list of subclasses @see [[CteExpr]], @see [[SelectStatement]], @see [[InsertStatement]], @see [UpdateStatement]] and @see [[DeleteStatement]]
|
|
202
|
+
* @alpha
|
|
203
|
+
*/
|
|
204
|
+
export class StatementExpr extends Expr {
|
|
205
|
+
static deserialize(node) {
|
|
206
|
+
if (node.id === NativeExpIds.CommonTable)
|
|
207
|
+
return CteExpr.deserialize(node);
|
|
208
|
+
if (node.id === NativeExpIds.InsertStatement)
|
|
209
|
+
return InsertStatementExpr.deserialize(node);
|
|
210
|
+
if (node.id === NativeExpIds.UpdateStatement)
|
|
211
|
+
return UpdateStatementExpr.deserialize(node);
|
|
212
|
+
if (node.id === NativeExpIds.DeleteStatement)
|
|
213
|
+
return DeleteStatementExpr.deserialize(node);
|
|
214
|
+
if (node.id === NativeExpIds.SelectStatement)
|
|
215
|
+
return SelectStatementExpr.deserialize(node);
|
|
216
|
+
throw new Error(`unknow node.id = ${node.id}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Base class for all computed expression like Value and Boolean.
|
|
221
|
+
* @alpha
|
|
222
|
+
*/
|
|
223
|
+
export class ComputedExpr extends Expr {
|
|
224
|
+
static deserialize(node) {
|
|
225
|
+
if (BooleanExpr.deserializableIds.includes(node.id)) {
|
|
226
|
+
return BooleanExpr.deserialize(node);
|
|
227
|
+
}
|
|
228
|
+
if (ValueExpr.deserializableIds.includes(node.id)) {
|
|
229
|
+
return ValueExpr.deserialize(node);
|
|
230
|
+
}
|
|
231
|
+
throw new Error(`unknow node.id = ${node.id}`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Base class for a boolean expressions. It has following subclasses
|
|
236
|
+
* @see [[BooleanExpr]]
|
|
237
|
+
* @see [[ubqueryTestExpr]]
|
|
238
|
+
* @see [[BetweenExpr]]
|
|
239
|
+
* @see [[LikeExpr]]
|
|
240
|
+
* @see [[InExpr]]
|
|
241
|
+
* @see [[IsNullExpr]]
|
|
242
|
+
* @see [[IsOfTypeExpr]]
|
|
243
|
+
* @see [[NotExpr]]
|
|
244
|
+
* @see [[BinaryBooleanExpr]]
|
|
245
|
+
* @alpha
|
|
246
|
+
*/
|
|
247
|
+
class BooleanExpr extends ComputedExpr {
|
|
248
|
+
static deserialize(node) {
|
|
249
|
+
if (node.id === NativeExpIds.BinaryBoolean) {
|
|
250
|
+
const op = node.op;
|
|
251
|
+
// if (MatchExpr.parseOp(op)[0]) {
|
|
252
|
+
// return MatchExpr.deserialize(node);
|
|
253
|
+
// }
|
|
254
|
+
if (BetweenExpr.parseOp(op)[0]) {
|
|
255
|
+
return BetweenExpr.deserialize(node);
|
|
256
|
+
}
|
|
257
|
+
if (LikeExpr.parseOp(op)[0]) {
|
|
258
|
+
return LikeExpr.deserialize(node);
|
|
259
|
+
}
|
|
260
|
+
if (InExpr.parseOp(op)[0]) {
|
|
261
|
+
return InExpr.deserialize(node);
|
|
262
|
+
}
|
|
263
|
+
if (IsNullExpr.parseOp(node)[0]) {
|
|
264
|
+
return IsNullExpr.deserialize(node);
|
|
265
|
+
}
|
|
266
|
+
if (IsOfTypeExpr.parseOp(node)[0]) {
|
|
267
|
+
return IsOfTypeExpr.deserialize(node);
|
|
268
|
+
}
|
|
269
|
+
return BinaryBooleanExpr.deserialize(node);
|
|
270
|
+
}
|
|
271
|
+
if (node.id === NativeExpIds.BooleanFactor) {
|
|
272
|
+
return NotExpr.deserialize(node);
|
|
273
|
+
}
|
|
274
|
+
if (node.id === NativeExpIds.SubqueryTest) {
|
|
275
|
+
return SubqueryTestExpr.deserialize(node);
|
|
276
|
+
}
|
|
277
|
+
if (node.id === NativeExpIds.BooleanFactor) {
|
|
278
|
+
return NotExpr.deserialize(node);
|
|
279
|
+
}
|
|
280
|
+
throw new Error(`Unknown type of native value exp ${node.id}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
BooleanExpr.deserializableIds = [NativeExpIds.BinaryBoolean, NativeExpIds.BooleanFactor, NativeExpIds.SubqueryTest, NativeExpIds.AllOrAny, NativeExpIds.BooleanFactor];
|
|
284
|
+
export { BooleanExpr };
|
|
285
|
+
/**
|
|
286
|
+
* Base class for all value expressions. Following is list of subclasses.
|
|
287
|
+
* @see [[SubqueryExpr]]
|
|
288
|
+
* @see [[ValueExpr]]
|
|
289
|
+
* @see [[UnaryValueExpr]]
|
|
290
|
+
* @see [[FuncCallExpr]]
|
|
291
|
+
* @see [[CastExpr]]
|
|
292
|
+
* @see [[BinaryValueExpr]]
|
|
293
|
+
* @see [[SearchCaseExpr]]
|
|
294
|
+
* @see [[IIFExpr]]
|
|
295
|
+
* @see [[LiteralExpr]]
|
|
296
|
+
* @see [[PropertyNameExpr]]
|
|
297
|
+
* @alpha
|
|
298
|
+
*/
|
|
299
|
+
class ValueExpr extends ComputedExpr {
|
|
300
|
+
static deserialize(node) {
|
|
301
|
+
if (node.id === NativeExpIds.UnaryValue) {
|
|
302
|
+
return UnaryValueExpr.deserialize(node);
|
|
303
|
+
}
|
|
304
|
+
if (node.id === NativeExpIds.PropertyName) {
|
|
305
|
+
return PropertyNameExpr.deserialize(node);
|
|
306
|
+
}
|
|
307
|
+
if (node.id === NativeExpIds.Parameter) {
|
|
308
|
+
return ParameterExpr.deserialize(node);
|
|
309
|
+
}
|
|
310
|
+
if (node.id === NativeExpIds.FunctionCall) {
|
|
311
|
+
return FuncCallExpr.deserialize(node);
|
|
312
|
+
}
|
|
313
|
+
if (node.id === NativeExpIds.Cast) {
|
|
314
|
+
return CastExpr.deserialize(node);
|
|
315
|
+
}
|
|
316
|
+
if (node.id === NativeExpIds.Subquery) {
|
|
317
|
+
return SubqueryExpr.deserialize(node);
|
|
318
|
+
}
|
|
319
|
+
if (node.id === NativeExpIds.BinaryValue) {
|
|
320
|
+
return BinaryValueExpr.deserialize(node);
|
|
321
|
+
}
|
|
322
|
+
if (node.id === NativeExpIds.SearchCaseValue) {
|
|
323
|
+
return SearchCaseExpr.deserialize(node);
|
|
324
|
+
}
|
|
325
|
+
if (node.id === NativeExpIds.IIF) {
|
|
326
|
+
return IIFExpr.deserialize(node);
|
|
327
|
+
}
|
|
328
|
+
if (node.id === NativeExpIds.LiteralValue) {
|
|
329
|
+
return LiteralExpr.deserialize(node);
|
|
330
|
+
}
|
|
331
|
+
throw new Error(`Unknown type of native value exp ${node.id}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
ValueExpr.deserializableIds = [
|
|
335
|
+
NativeExpIds.LiteralValue,
|
|
336
|
+
NativeExpIds.Parameter,
|
|
337
|
+
NativeExpIds.FunctionCall,
|
|
338
|
+
NativeExpIds.Cast,
|
|
339
|
+
NativeExpIds.BinaryValue,
|
|
340
|
+
NativeExpIds.SearchCaseValue,
|
|
341
|
+
NativeExpIds.IIF,
|
|
342
|
+
NativeExpIds.UnaryValue,
|
|
343
|
+
NativeExpIds.PropertyName,
|
|
344
|
+
NativeExpIds.Subquery,
|
|
345
|
+
];
|
|
346
|
+
export { ValueExpr };
|
|
347
|
+
/**
|
|
348
|
+
* Base class for expressions that can be used in FROM clause of a SELECT. Following list of this subclasses.
|
|
349
|
+
* @see [[ClassRefExpr]]
|
|
350
|
+
* @see [[ClassNameExpr]]
|
|
351
|
+
* @see [[SubqueryRefExpr]]
|
|
352
|
+
* @see [[UsingRelationshipJoinExpr]]
|
|
353
|
+
* @see [[QualifiedJoinExpr]]
|
|
354
|
+
* @see [[CteBlockRefExpr]]
|
|
355
|
+
* @see [[TableValuedFuncExpr]]
|
|
356
|
+
* @alpha
|
|
357
|
+
*/
|
|
358
|
+
class ClassRefExpr extends Expr {
|
|
359
|
+
static deserialize(node) {
|
|
360
|
+
if (node.id === NativeExpIds.ClassName) {
|
|
361
|
+
return ClassNameExpr.deserialize(node);
|
|
362
|
+
}
|
|
363
|
+
if (node.id === NativeExpIds.SubqueryRef) {
|
|
364
|
+
return SubqueryRefExpr.deserialize(node);
|
|
365
|
+
}
|
|
366
|
+
if (node.id === NativeExpIds.UsingRelationshipJoinExp) {
|
|
367
|
+
return UsingRelationshipJoinExpr.deserialize(node);
|
|
368
|
+
}
|
|
369
|
+
if (node.id === NativeExpIds.QualifiedJoin) {
|
|
370
|
+
return QualifiedJoinExpr.deserialize(node);
|
|
371
|
+
}
|
|
372
|
+
if (node.id === NativeExpIds.CommonTableBlockName) {
|
|
373
|
+
return CteBlockRefExpr.deserialize(node);
|
|
374
|
+
}
|
|
375
|
+
if (node.id === NativeExpIds.TableValuedFunction) {
|
|
376
|
+
return TableValuedFuncExpr.deserialize(node);
|
|
377
|
+
}
|
|
378
|
+
throw new Error(`Unknown type of native value exp ${node.id}`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
ClassRefExpr.deserializableIds = [
|
|
382
|
+
NativeExpIds.ClassName,
|
|
383
|
+
NativeExpIds.SubqueryRef,
|
|
384
|
+
NativeExpIds.UsingRelationshipJoinExp,
|
|
385
|
+
NativeExpIds.QualifiedJoin,
|
|
386
|
+
NativeExpIds.CommonTableBlockName,
|
|
387
|
+
];
|
|
388
|
+
export { ClassRefExpr };
|
|
389
|
+
/**
|
|
390
|
+
* Write expression tree to string
|
|
391
|
+
* @alpha
|
|
392
|
+
*/
|
|
393
|
+
export class ECSqlWriter {
|
|
394
|
+
constructor(options = {
|
|
395
|
+
multiline: false,
|
|
396
|
+
spaceAfterComma: true,
|
|
397
|
+
spaceAroundBinOp: true,
|
|
398
|
+
eol: "\r\n",
|
|
399
|
+
keywordCasing: "UPPER",
|
|
400
|
+
indent: { size: 3, char: " " },
|
|
401
|
+
}) {
|
|
402
|
+
this.options = options;
|
|
403
|
+
this._tokens = [];
|
|
404
|
+
this._currentIndent = 0;
|
|
405
|
+
this._isNewLine = false;
|
|
406
|
+
}
|
|
407
|
+
indent() {
|
|
408
|
+
this._currentIndent++;
|
|
409
|
+
}
|
|
410
|
+
unindent() {
|
|
411
|
+
if (this._currentIndent > 0)
|
|
412
|
+
this._currentIndent--;
|
|
413
|
+
}
|
|
414
|
+
appendBinaryOp(val) {
|
|
415
|
+
if (this.options.spaceAroundBinOp)
|
|
416
|
+
return this.append(` ${val} `);
|
|
417
|
+
return this.append(val);
|
|
418
|
+
}
|
|
419
|
+
appendKeyword(val) {
|
|
420
|
+
if (this.options.keywordCasing === "UPPER")
|
|
421
|
+
return this.append(val);
|
|
422
|
+
return this.append(val.toLowerCase());
|
|
423
|
+
}
|
|
424
|
+
appendComma() {
|
|
425
|
+
this.append(",");
|
|
426
|
+
if (this.options.spaceAfterComma)
|
|
427
|
+
this.appendSpace();
|
|
428
|
+
}
|
|
429
|
+
appendQuoted(val) {
|
|
430
|
+
return this.append(`[${val}]`);
|
|
431
|
+
}
|
|
432
|
+
append(val) {
|
|
433
|
+
if (this._isNewLine) {
|
|
434
|
+
if (this._currentIndent > 0 && this.options.indent.size > 0 && this.options.indent.char.length === 1) {
|
|
435
|
+
this._tokens.push("".padEnd(this._currentIndent * this.options.indent.size, this.options.indent.char));
|
|
436
|
+
}
|
|
437
|
+
this._isNewLine = false;
|
|
438
|
+
}
|
|
439
|
+
this._tokens.push(val);
|
|
440
|
+
return this;
|
|
441
|
+
}
|
|
442
|
+
appendStringLiteral(val) {
|
|
443
|
+
return this.append(`'${val}'`);
|
|
444
|
+
}
|
|
445
|
+
appendLineOrSpace() {
|
|
446
|
+
if (this.options.multiline)
|
|
447
|
+
return this.appendLine();
|
|
448
|
+
return this.appendSpace();
|
|
449
|
+
}
|
|
450
|
+
appendSpace() {
|
|
451
|
+
return this.append(" ");
|
|
452
|
+
}
|
|
453
|
+
appendLine() {
|
|
454
|
+
if (this.options.multiline) {
|
|
455
|
+
this._isNewLine = true;
|
|
456
|
+
if (this._tokens.length > 0) {
|
|
457
|
+
this._tokens[this._tokens.length - 1] = this._tokens[this._tokens.length - 1].trimEnd();
|
|
458
|
+
}
|
|
459
|
+
this._tokens.push(this.options.eol);
|
|
460
|
+
}
|
|
461
|
+
return this;
|
|
462
|
+
}
|
|
463
|
+
clear() {
|
|
464
|
+
this._tokens = [];
|
|
465
|
+
return this;
|
|
466
|
+
}
|
|
467
|
+
squash() {
|
|
468
|
+
if (this._tokens.length > 1) {
|
|
469
|
+
this._tokens = [this.toString()];
|
|
470
|
+
}
|
|
471
|
+
return this;
|
|
472
|
+
}
|
|
473
|
+
toString() {
|
|
474
|
+
return this._tokens.join("");
|
|
475
|
+
}
|
|
476
|
+
appendExp(exp) {
|
|
477
|
+
exp.writeTo(this);
|
|
478
|
+
return this;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Use to describe selection clause terms in a SELECT statements @see [[SelectionClauseExpr]] @see [[SelectExpr]]
|
|
483
|
+
* @alpha
|
|
484
|
+
*/
|
|
485
|
+
class DerivedPropertyExpr extends Expr {
|
|
486
|
+
constructor(computedExpr, alias) {
|
|
487
|
+
super(DerivedPropertyExpr.type);
|
|
488
|
+
this.computedExpr = computedExpr;
|
|
489
|
+
this.alias = alias;
|
|
490
|
+
}
|
|
491
|
+
get children() {
|
|
492
|
+
return [this.computedExpr];
|
|
493
|
+
}
|
|
494
|
+
static deserialize(node) {
|
|
495
|
+
if (node.id !== NativeExpIds.DerivedProperty) {
|
|
496
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.DerivedProperty'. ${JSON.stringify(node)}`);
|
|
497
|
+
}
|
|
498
|
+
return new DerivedPropertyExpr(ComputedExpr.deserialize(node.exp), node.alias ? node.alias : undefined);
|
|
499
|
+
}
|
|
500
|
+
writeTo(writer) {
|
|
501
|
+
writer.appendExp(this.computedExpr);
|
|
502
|
+
if (this.alias) {
|
|
503
|
+
writer.appendSpace();
|
|
504
|
+
writer.appendQuoted(this.alias);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
DerivedPropertyExpr.type = ExprType.DerivedProperty;
|
|
509
|
+
export { DerivedPropertyExpr };
|
|
510
|
+
/**
|
|
511
|
+
* Describes a ECSQL delete statement.
|
|
512
|
+
* @alpha
|
|
513
|
+
*/
|
|
514
|
+
class DeleteStatementExpr extends StatementExpr {
|
|
515
|
+
constructor(className, where, options) {
|
|
516
|
+
super(DeleteStatementExpr.type);
|
|
517
|
+
this.className = className;
|
|
518
|
+
this.where = where;
|
|
519
|
+
this.options = options;
|
|
520
|
+
}
|
|
521
|
+
get children() {
|
|
522
|
+
const exprs = [this.className];
|
|
523
|
+
if (this.where)
|
|
524
|
+
exprs.push(this.where);
|
|
525
|
+
if (this.options)
|
|
526
|
+
exprs.push(this.options);
|
|
527
|
+
return exprs;
|
|
528
|
+
}
|
|
529
|
+
static deserialize(node) {
|
|
530
|
+
if (node.id !== NativeExpIds.DeleteStatement) {
|
|
531
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.DeleteStatement'. ${JSON.stringify(node)}`);
|
|
532
|
+
}
|
|
533
|
+
const className = ClassNameExpr.deserialize(node.class);
|
|
534
|
+
const where = node.where ? WhereClauseExp.deserialize(node.where) : undefined;
|
|
535
|
+
const options = node.options ? ECSqlOptionsClauseExpr.deserialize(node.options) : undefined;
|
|
536
|
+
return new DeleteStatementExpr(className, where, options);
|
|
537
|
+
}
|
|
538
|
+
writeTo(writer) {
|
|
539
|
+
writer.appendKeyword("DELETE");
|
|
540
|
+
writer.appendSpace();
|
|
541
|
+
writer.appendKeyword("FROM");
|
|
542
|
+
writer.appendSpace();
|
|
543
|
+
writer.appendExp(this.className);
|
|
544
|
+
if (this.where) {
|
|
545
|
+
writer.appendSpace();
|
|
546
|
+
writer.appendExp(this.where);
|
|
547
|
+
}
|
|
548
|
+
if (this.options) {
|
|
549
|
+
writer.appendSpace();
|
|
550
|
+
writer.appendExp(this.options);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
DeleteStatementExpr.type = ExprType.DeleteStatement;
|
|
555
|
+
export { DeleteStatementExpr };
|
|
556
|
+
/**
|
|
557
|
+
* Describe a ECSQL Insert statement.
|
|
558
|
+
* @alpha
|
|
559
|
+
*/
|
|
560
|
+
class InsertStatementExpr extends StatementExpr {
|
|
561
|
+
constructor(className, values, propertyNames) {
|
|
562
|
+
super(InsertStatementExpr.type);
|
|
563
|
+
this.className = className;
|
|
564
|
+
this.values = values;
|
|
565
|
+
this.propertyNames = propertyNames;
|
|
566
|
+
}
|
|
567
|
+
get children() {
|
|
568
|
+
const exprs = [this.className];
|
|
569
|
+
exprs.push(...this.values);
|
|
570
|
+
if (this.propertyNames)
|
|
571
|
+
exprs.push(...this.propertyNames);
|
|
572
|
+
return exprs;
|
|
573
|
+
}
|
|
574
|
+
static deserialize(node) {
|
|
575
|
+
if (node.id !== NativeExpIds.InsertStatement) {
|
|
576
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.InsertStatement'. ${JSON.stringify(node)}`);
|
|
577
|
+
}
|
|
578
|
+
const className = ClassNameExpr.deserialize(node.class);
|
|
579
|
+
if (className.polymorphicInfo) {
|
|
580
|
+
// Patch as INSERT are always ONLY but parser have issue accepting ONLY.
|
|
581
|
+
if (className.polymorphicInfo.allOrAny === "ONLY") {
|
|
582
|
+
className.polymorphicInfo = undefined;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
const values = Array.from(node.values.map((v) => ValueExpr.deserialize(v)));
|
|
586
|
+
const properties = node.properties ? Array.from(node.properties.map((v) => PropertyNameExpr.deserialize(v))) : undefined;
|
|
587
|
+
return new InsertStatementExpr(className, values, properties);
|
|
588
|
+
}
|
|
589
|
+
writeTo(writer) {
|
|
590
|
+
writer.appendKeyword("INSERT");
|
|
591
|
+
writer.appendSpace();
|
|
592
|
+
writer.appendKeyword("INTO");
|
|
593
|
+
writer.appendSpace();
|
|
594
|
+
writer.appendExp(this.className);
|
|
595
|
+
writer.appendSpace();
|
|
596
|
+
if (this.propertyNames) {
|
|
597
|
+
writer.append("(");
|
|
598
|
+
this.propertyNames.forEach((v, i) => {
|
|
599
|
+
if (i > 0) {
|
|
600
|
+
writer.appendComma();
|
|
601
|
+
}
|
|
602
|
+
writer.appendExp(v);
|
|
603
|
+
});
|
|
604
|
+
writer.append(")");
|
|
605
|
+
}
|
|
606
|
+
writer.appendSpace();
|
|
607
|
+
writer.appendKeyword("VALUES");
|
|
608
|
+
writer.append("(");
|
|
609
|
+
this.values.forEach((v, i) => {
|
|
610
|
+
if (i > 0) {
|
|
611
|
+
writer.appendComma();
|
|
612
|
+
}
|
|
613
|
+
writer.appendExp(v);
|
|
614
|
+
});
|
|
615
|
+
writer.append(")");
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
InsertStatementExpr.type = ExprType.InsertStatement;
|
|
619
|
+
export { InsertStatementExpr };
|
|
620
|
+
/**
|
|
621
|
+
* Describes a JOIN clause e.g. <classNameExpr> JOIN <classNameExpr> ON <joinspec>
|
|
622
|
+
* @alpha
|
|
623
|
+
*/
|
|
624
|
+
class QualifiedJoinExpr extends ClassRefExpr {
|
|
625
|
+
constructor(joinType, from, to, spec) {
|
|
626
|
+
super(QualifiedJoinExpr.type);
|
|
627
|
+
this.joinType = joinType;
|
|
628
|
+
this.from = from;
|
|
629
|
+
this.to = to;
|
|
630
|
+
this.spec = spec;
|
|
631
|
+
}
|
|
632
|
+
get children() {
|
|
633
|
+
const exprs = [this.from, this.to];
|
|
634
|
+
if (this.spec instanceof BooleanExpr)
|
|
635
|
+
exprs.push(this.spec);
|
|
636
|
+
return exprs;
|
|
637
|
+
}
|
|
638
|
+
static deserialize(node) {
|
|
639
|
+
if (node.id !== NativeExpIds.QualifiedJoin) {
|
|
640
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.QualifiedJoin'. ${JSON.stringify(node)}`);
|
|
641
|
+
}
|
|
642
|
+
const type = node.type;
|
|
643
|
+
const from = ClassRefExpr.deserialize(node.from);
|
|
644
|
+
const to = ClassRefExpr.deserialize(node.to);
|
|
645
|
+
let spec;
|
|
646
|
+
if (Array.isArray(node.spec))
|
|
647
|
+
spec = node.spec;
|
|
648
|
+
else
|
|
649
|
+
spec = BooleanExpr.deserialize(node.spec);
|
|
650
|
+
return new QualifiedJoinExpr(type, from, to, spec);
|
|
651
|
+
}
|
|
652
|
+
writeTo(writer) {
|
|
653
|
+
writer.appendExp(this.from);
|
|
654
|
+
writer.appendSpace();
|
|
655
|
+
if (this.joinType === JoinType.LeftOuter) {
|
|
656
|
+
writer.appendKeyword("LEFT").appendSpace();
|
|
657
|
+
writer.appendKeyword("OUTER").appendSpace();
|
|
658
|
+
writer.appendKeyword("JOIN").appendSpace();
|
|
659
|
+
}
|
|
660
|
+
else if (this.joinType === JoinType.RightOuter) {
|
|
661
|
+
writer.appendKeyword("RIGHT").appendSpace();
|
|
662
|
+
writer.appendKeyword("OUTER").appendSpace();
|
|
663
|
+
writer.appendKeyword("JOIN").appendSpace();
|
|
664
|
+
}
|
|
665
|
+
else if (this.joinType === JoinType.FullOuter) {
|
|
666
|
+
writer.appendKeyword("FULL").appendSpace();
|
|
667
|
+
writer.appendKeyword("OUTER").appendSpace();
|
|
668
|
+
writer.appendKeyword("JOIN").appendSpace();
|
|
669
|
+
}
|
|
670
|
+
else if (this.joinType === JoinType.Inner) {
|
|
671
|
+
writer.appendKeyword("INNER").appendSpace();
|
|
672
|
+
writer.appendKeyword("JOIN").appendSpace();
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
throw new Error(`not supported join type ${this.joinType}`);
|
|
676
|
+
}
|
|
677
|
+
writer.appendExp(this.to);
|
|
678
|
+
if (this.spec) {
|
|
679
|
+
writer.appendSpace();
|
|
680
|
+
if (this.spec instanceof BooleanExpr) {
|
|
681
|
+
writer.appendKeyword("ON");
|
|
682
|
+
writer.appendSpace();
|
|
683
|
+
writer.appendExp(this.spec);
|
|
684
|
+
}
|
|
685
|
+
else if (this.spec instanceof Array) {
|
|
686
|
+
writer.appendKeyword("USING");
|
|
687
|
+
this.spec.forEach((v, i) => {
|
|
688
|
+
if (i > 0) {
|
|
689
|
+
writer.appendComma();
|
|
690
|
+
writer.append(v);
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
else {
|
|
695
|
+
throw new Error("unknow join spec");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
QualifiedJoinExpr.type = ExprType.QualifiedJoin;
|
|
701
|
+
export { QualifiedJoinExpr };
|
|
702
|
+
/**
|
|
703
|
+
* Describe a JOIN USING clause.
|
|
704
|
+
* @alpha
|
|
705
|
+
*/
|
|
706
|
+
class UsingRelationshipJoinExpr extends ClassRefExpr {
|
|
707
|
+
constructor(fromClassName, toClassName, toRelClassName, direction) {
|
|
708
|
+
super(UsingRelationshipJoinExpr.type);
|
|
709
|
+
this.fromClassName = fromClassName;
|
|
710
|
+
this.toClassName = toClassName;
|
|
711
|
+
this.toRelClassName = toRelClassName;
|
|
712
|
+
this.direction = direction;
|
|
713
|
+
}
|
|
714
|
+
get children() {
|
|
715
|
+
return [this.fromClassName, this.toClassName, this.toRelClassName];
|
|
716
|
+
}
|
|
717
|
+
static deserialize(node) {
|
|
718
|
+
if (node.id !== NativeExpIds.UsingRelationshipJoinExp) {
|
|
719
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.UsingRelationshipJoinExp'. ${JSON.stringify(node)}`);
|
|
720
|
+
}
|
|
721
|
+
const from = ClassRefExpr.deserialize(node.from);
|
|
722
|
+
const to = ClassNameExpr.deserialize(node.to);
|
|
723
|
+
const usingRel = ClassNameExpr.deserialize(node.using);
|
|
724
|
+
const direction = node.direction ? node.direction : undefined;
|
|
725
|
+
return new UsingRelationshipJoinExpr(from, to, usingRel, direction);
|
|
726
|
+
}
|
|
727
|
+
writeTo(writer) {
|
|
728
|
+
writer.appendExp(this.fromClassName);
|
|
729
|
+
writer.appendSpace();
|
|
730
|
+
writer.appendKeyword("JOIN");
|
|
731
|
+
writer.appendSpace();
|
|
732
|
+
writer.appendExp(this.toClassName);
|
|
733
|
+
writer.appendSpace();
|
|
734
|
+
writer.appendKeyword("USING");
|
|
735
|
+
writer.appendSpace();
|
|
736
|
+
writer.appendExp(this.toRelClassName);
|
|
737
|
+
if (this.direction) {
|
|
738
|
+
writer.appendSpace();
|
|
739
|
+
writer.appendKeyword(this.direction);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
UsingRelationshipJoinExpr.type = ExprType.UsingRelationshipJoin;
|
|
744
|
+
export { UsingRelationshipJoinExpr };
|
|
745
|
+
/**
|
|
746
|
+
* Describe subquery result test e.g. EXISTS(<subquery>)
|
|
747
|
+
* @alpha
|
|
748
|
+
*/
|
|
749
|
+
class SubqueryTestExpr extends BooleanExpr {
|
|
750
|
+
constructor(op, query) {
|
|
751
|
+
super(SubqueryTestExpr.type);
|
|
752
|
+
this.op = op;
|
|
753
|
+
this.query = query;
|
|
754
|
+
}
|
|
755
|
+
get children() {
|
|
756
|
+
return [this.query];
|
|
757
|
+
}
|
|
758
|
+
static deserialize(node) {
|
|
759
|
+
if (node.id !== NativeExpIds.SubqueryTest) {
|
|
760
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.SubqueryTest'. ${JSON.stringify(node)}`);
|
|
761
|
+
}
|
|
762
|
+
const query = SubqueryExpr.deserialize(node.query);
|
|
763
|
+
const op = node.op;
|
|
764
|
+
return new SubqueryTestExpr(op, query);
|
|
765
|
+
}
|
|
766
|
+
writeTo(writer) {
|
|
767
|
+
writer.appendKeyword(this.op);
|
|
768
|
+
writer.appendExp(this.query);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
SubqueryTestExpr.type = ExprType.SubqueryTest;
|
|
772
|
+
export { SubqueryTestExpr };
|
|
773
|
+
/**
|
|
774
|
+
* Describe a subquery when used in FROM clause.
|
|
775
|
+
* @alpha
|
|
776
|
+
*/
|
|
777
|
+
class SubqueryRefExpr extends ClassRefExpr {
|
|
778
|
+
constructor(query, polymorphicInfo, alias) {
|
|
779
|
+
super(SubqueryRefExpr.type);
|
|
780
|
+
this.query = query;
|
|
781
|
+
this.polymorphicInfo = polymorphicInfo;
|
|
782
|
+
this.alias = alias;
|
|
783
|
+
}
|
|
784
|
+
get children() {
|
|
785
|
+
return [this.query];
|
|
786
|
+
}
|
|
787
|
+
static deserialize(node) {
|
|
788
|
+
if (node.id !== NativeExpIds.SubqueryRef) {
|
|
789
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.SubqueryRef'. ${JSON.stringify(node)}`);
|
|
790
|
+
}
|
|
791
|
+
const query = SubqueryExpr.deserialize(node.query);
|
|
792
|
+
const polymorphicInfo = node.polymorphicInfo ? node.polymorphicInfo : undefined;
|
|
793
|
+
const alias = node.alias ? node.alias : undefined;
|
|
794
|
+
return new SubqueryRefExpr(query, polymorphicInfo, alias);
|
|
795
|
+
}
|
|
796
|
+
writeTo(writer) {
|
|
797
|
+
if (this.polymorphicInfo) {
|
|
798
|
+
if (this.polymorphicInfo.disqualify) {
|
|
799
|
+
writer.append(this.polymorphicInfo.disqualify);
|
|
800
|
+
}
|
|
801
|
+
writer.appendKeyword(this.polymorphicInfo.allOrAny);
|
|
802
|
+
writer.appendSpace();
|
|
803
|
+
}
|
|
804
|
+
writer.appendExp(this.query);
|
|
805
|
+
if (this.alias) {
|
|
806
|
+
writer.appendSpace();
|
|
807
|
+
writer.appendQuoted(this.alias);
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
SubqueryRefExpr.type = ExprType.SubqueryRef;
|
|
812
|
+
export { SubqueryRefExpr };
|
|
813
|
+
/**
|
|
814
|
+
* Describe a optionally compound SELECT statement.
|
|
815
|
+
* @alpha
|
|
816
|
+
*/
|
|
817
|
+
class SelectStatementExpr extends StatementExpr {
|
|
818
|
+
constructor(singleSelect, nextSelect) {
|
|
819
|
+
super(SelectStatementExpr.type);
|
|
820
|
+
this.singleSelect = singleSelect;
|
|
821
|
+
this.nextSelect = nextSelect;
|
|
822
|
+
}
|
|
823
|
+
get children() {
|
|
824
|
+
const exprs = [this.singleSelect];
|
|
825
|
+
if (this.nextSelect)
|
|
826
|
+
exprs.push(this.nextSelect.select);
|
|
827
|
+
return exprs;
|
|
828
|
+
}
|
|
829
|
+
static deserialize(node) {
|
|
830
|
+
if (node.id !== NativeExpIds.SelectStatement) {
|
|
831
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.SelectStatement'. ${JSON.stringify(node)}`);
|
|
832
|
+
}
|
|
833
|
+
const singleSelect = SelectExpr.deserialize(node.select);
|
|
834
|
+
let nextSelect;
|
|
835
|
+
if (node.nextBlock) {
|
|
836
|
+
nextSelect = {
|
|
837
|
+
op: node.nextBlock.combineOp,
|
|
838
|
+
select: SelectStatementExpr.deserialize(node.nextBlock.select),
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
return new SelectStatementExpr(singleSelect, nextSelect);
|
|
842
|
+
}
|
|
843
|
+
writeTo(writer) {
|
|
844
|
+
writer.appendExp(this.singleSelect);
|
|
845
|
+
if (this.nextSelect) {
|
|
846
|
+
writer.appendSpace();
|
|
847
|
+
if (this.nextSelect.op === "UNION ALL") {
|
|
848
|
+
writer.appendKeyword("UNION");
|
|
849
|
+
writer.appendSpace();
|
|
850
|
+
writer.appendKeyword("ALL");
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
writer.append(this.nextSelect.op);
|
|
854
|
+
}
|
|
855
|
+
writer.appendSpace();
|
|
856
|
+
writer.appendExp(this.nextSelect.select);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
SelectStatementExpr.type = ExprType.SelectStatement;
|
|
861
|
+
export { SelectStatementExpr };
|
|
862
|
+
/**
|
|
863
|
+
* Describe selection in a SELECT query
|
|
864
|
+
* @alpha
|
|
865
|
+
*/
|
|
866
|
+
class SelectionClauseExpr extends Expr {
|
|
867
|
+
constructor(derivedPropertyList) {
|
|
868
|
+
super(SelectionClauseExpr.type);
|
|
869
|
+
this.derivedPropertyList = derivedPropertyList;
|
|
870
|
+
}
|
|
871
|
+
get children() {
|
|
872
|
+
return [...this.derivedPropertyList];
|
|
873
|
+
}
|
|
874
|
+
static deserialize(node) {
|
|
875
|
+
if (!Array.isArray(node)) {
|
|
876
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode[] ${JSON.stringify(node)}`);
|
|
877
|
+
}
|
|
878
|
+
return new SelectionClauseExpr(Array.from(node.map((v) => DerivedPropertyExpr.deserialize(v))));
|
|
879
|
+
}
|
|
880
|
+
writeTo(writer) {
|
|
881
|
+
this.derivedPropertyList.forEach((v, i) => {
|
|
882
|
+
if (i > 0) {
|
|
883
|
+
writer.appendComma();
|
|
884
|
+
}
|
|
885
|
+
writer.appendExp(v);
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
SelectionClauseExpr.type = ExprType.SelectionClause;
|
|
890
|
+
export { SelectionClauseExpr };
|
|
891
|
+
/**
|
|
892
|
+
* Describe a GROUP BY clause in a SELECT statement.
|
|
893
|
+
* @alpha
|
|
894
|
+
*/
|
|
895
|
+
class GroupByClauseExpr extends Expr {
|
|
896
|
+
constructor(exprList) {
|
|
897
|
+
super(GroupByClauseExpr.type);
|
|
898
|
+
this.exprList = exprList;
|
|
899
|
+
}
|
|
900
|
+
get children() {
|
|
901
|
+
return [...this.exprList];
|
|
902
|
+
}
|
|
903
|
+
static deserialize(node) {
|
|
904
|
+
if (!Array.isArray(node)) {
|
|
905
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode[] ${JSON.stringify(node)}`);
|
|
906
|
+
}
|
|
907
|
+
return new GroupByClauseExpr(Array.from(node.map((v) => ValueExpr.deserialize(v))));
|
|
908
|
+
}
|
|
909
|
+
writeTo(writer) {
|
|
910
|
+
writer.appendKeyword("GROUP");
|
|
911
|
+
writer.appendSpace();
|
|
912
|
+
writer.appendKeyword("BY");
|
|
913
|
+
writer.appendSpace();
|
|
914
|
+
this.exprList.forEach((v, i) => {
|
|
915
|
+
if (i > 0) {
|
|
916
|
+
writer.appendComma();
|
|
917
|
+
}
|
|
918
|
+
writer.appendExp(v);
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
GroupByClauseExpr.type = ExprType.GroupByClause;
|
|
923
|
+
export { GroupByClauseExpr };
|
|
924
|
+
/**
|
|
925
|
+
* Describe a HAVING clause in a SELECT statement.
|
|
926
|
+
* @alpha
|
|
927
|
+
*/
|
|
928
|
+
class HavingClauseExpr extends Expr {
|
|
929
|
+
constructor(filterExpr) {
|
|
930
|
+
super(HavingClauseExpr.type);
|
|
931
|
+
this.filterExpr = filterExpr;
|
|
932
|
+
}
|
|
933
|
+
get children() {
|
|
934
|
+
return [this.filterExpr];
|
|
935
|
+
}
|
|
936
|
+
static deserialize(node) {
|
|
937
|
+
if (typeof node !== "object") {
|
|
938
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode ${JSON.stringify(node)}`);
|
|
939
|
+
}
|
|
940
|
+
return new HavingClauseExpr(BooleanExpr.deserialize(node));
|
|
941
|
+
}
|
|
942
|
+
writeTo(writer) {
|
|
943
|
+
writer.appendKeyword("HAVING");
|
|
944
|
+
writer.appendSpace();
|
|
945
|
+
writer.appendExp(this.filterExpr);
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
HavingClauseExpr.type = ExprType.HavingClause;
|
|
949
|
+
export { HavingClauseExpr };
|
|
950
|
+
/**
|
|
951
|
+
* Describe a FROM clause in a SELECT statement.
|
|
952
|
+
* @alpha
|
|
953
|
+
*/
|
|
954
|
+
class FromClauseExpr extends Expr {
|
|
955
|
+
constructor(classRefs) {
|
|
956
|
+
super(FromClauseExpr.type);
|
|
957
|
+
this.classRefs = classRefs;
|
|
958
|
+
}
|
|
959
|
+
get children() {
|
|
960
|
+
return [...this.classRefs];
|
|
961
|
+
}
|
|
962
|
+
static deserialize(node) {
|
|
963
|
+
if (!Array.isArray(node)) {
|
|
964
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode[] ${JSON.stringify(node)}`);
|
|
965
|
+
}
|
|
966
|
+
return new FromClauseExpr(Array.from(node.map((v) => ClassRefExpr.deserialize(v))));
|
|
967
|
+
}
|
|
968
|
+
writeTo(writer) {
|
|
969
|
+
writer.appendKeyword("FROM");
|
|
970
|
+
writer.appendSpace();
|
|
971
|
+
this.classRefs.forEach((v, i) => {
|
|
972
|
+
if (i > 0) {
|
|
973
|
+
writer.appendComma();
|
|
974
|
+
}
|
|
975
|
+
writer.appendExp(v);
|
|
976
|
+
});
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
FromClauseExpr.type = ExprType.FromClause;
|
|
980
|
+
export { FromClauseExpr };
|
|
981
|
+
/**
|
|
982
|
+
* Describe a WHERE clause in a SELECT, UPDATE and DELETE statement.
|
|
983
|
+
* @alpha
|
|
984
|
+
*/
|
|
985
|
+
class WhereClauseExp extends Expr {
|
|
986
|
+
constructor(filterExpr) {
|
|
987
|
+
super(WhereClauseExp.type);
|
|
988
|
+
this.filterExpr = filterExpr;
|
|
989
|
+
}
|
|
990
|
+
get children() {
|
|
991
|
+
return [this.filterExpr];
|
|
992
|
+
}
|
|
993
|
+
static deserialize(node) {
|
|
994
|
+
if (typeof node !== "object") {
|
|
995
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode ${JSON.stringify(node)}`);
|
|
996
|
+
}
|
|
997
|
+
return new WhereClauseExp(BooleanExpr.deserialize(node));
|
|
998
|
+
}
|
|
999
|
+
writeTo(writer) {
|
|
1000
|
+
writer.appendKeyword("WHERE");
|
|
1001
|
+
writer.appendSpace();
|
|
1002
|
+
writer.appendExp(this.filterExpr);
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
WhereClauseExp.type = ExprType.WhereClause;
|
|
1006
|
+
export { WhereClauseExp };
|
|
1007
|
+
/**
|
|
1008
|
+
* Describe a single sorted term in a ORDER BY clause of a SELECT statement.
|
|
1009
|
+
* @alpha
|
|
1010
|
+
*/
|
|
1011
|
+
class OrderBySpecExpr extends Expr {
|
|
1012
|
+
constructor(term, sortDirection, nulls) {
|
|
1013
|
+
super(OrderBySpecExpr.type);
|
|
1014
|
+
this.term = term;
|
|
1015
|
+
this.sortDirection = sortDirection;
|
|
1016
|
+
this.nulls = nulls;
|
|
1017
|
+
}
|
|
1018
|
+
get children() {
|
|
1019
|
+
return [this.term];
|
|
1020
|
+
}
|
|
1021
|
+
static deserialize(node) {
|
|
1022
|
+
if (typeof node !== "object") {
|
|
1023
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode ${JSON.stringify(node)}`);
|
|
1024
|
+
}
|
|
1025
|
+
return new OrderBySpecExpr(ValueExpr.deserialize(node.exp), node.direction ? node.direction : undefined);
|
|
1026
|
+
}
|
|
1027
|
+
writeTo(writer) {
|
|
1028
|
+
writer.appendExp(this.term);
|
|
1029
|
+
if (this.sortDirection) {
|
|
1030
|
+
writer.appendSpace();
|
|
1031
|
+
writer.appendKeyword(this.sortDirection);
|
|
1032
|
+
}
|
|
1033
|
+
if (this.nulls) {
|
|
1034
|
+
writer.appendSpace();
|
|
1035
|
+
writer.appendKeyword("NULLS");
|
|
1036
|
+
writer.appendSpace();
|
|
1037
|
+
writer.appendKeyword(this.nulls);
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
OrderBySpecExpr.type = ExprType.OrderBySpec;
|
|
1042
|
+
export { OrderBySpecExpr };
|
|
1043
|
+
/**
|
|
1044
|
+
* Describe a ORDER BY clause in a SELECT statement.
|
|
1045
|
+
* @alpha
|
|
1046
|
+
*/
|
|
1047
|
+
class OrderByClauseExpr extends Expr {
|
|
1048
|
+
constructor(terms) {
|
|
1049
|
+
super(OrderByClauseExpr.type);
|
|
1050
|
+
this.terms = terms;
|
|
1051
|
+
}
|
|
1052
|
+
get children() {
|
|
1053
|
+
return [...this.terms.map((v) => v.term)];
|
|
1054
|
+
}
|
|
1055
|
+
static deserialize(node) {
|
|
1056
|
+
if (!Array.isArray(node)) {
|
|
1057
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode[] ${JSON.stringify(node)}`);
|
|
1058
|
+
}
|
|
1059
|
+
return new OrderByClauseExpr(Array.from(node.map((v) => OrderBySpecExpr.deserialize(v))));
|
|
1060
|
+
}
|
|
1061
|
+
writeTo(writer) {
|
|
1062
|
+
writer.appendKeyword("ORDER");
|
|
1063
|
+
writer.appendSpace();
|
|
1064
|
+
writer.appendKeyword("BY");
|
|
1065
|
+
writer.appendSpace();
|
|
1066
|
+
this.terms.forEach((v, i) => {
|
|
1067
|
+
if (i > 0) {
|
|
1068
|
+
writer.appendComma();
|
|
1069
|
+
}
|
|
1070
|
+
writer.appendExp(v);
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
OrderByClauseExpr.type = ExprType.OrderByClause;
|
|
1075
|
+
export { OrderByClauseExpr };
|
|
1076
|
+
/**
|
|
1077
|
+
* Describe a LIMIT clause in a SELECT statement.
|
|
1078
|
+
* @alpha
|
|
1079
|
+
*/
|
|
1080
|
+
class LimitClauseExpr extends Expr {
|
|
1081
|
+
constructor(limit, offset) {
|
|
1082
|
+
super(LimitClauseExpr.type);
|
|
1083
|
+
this.limit = limit;
|
|
1084
|
+
this.offset = offset;
|
|
1085
|
+
}
|
|
1086
|
+
get children() {
|
|
1087
|
+
const exprs = [this.limit];
|
|
1088
|
+
if (this.offset)
|
|
1089
|
+
exprs.push(this.offset);
|
|
1090
|
+
return exprs;
|
|
1091
|
+
}
|
|
1092
|
+
static deserialize(node) {
|
|
1093
|
+
if (typeof node !== "object") {
|
|
1094
|
+
throw new Error(`Expect node to be array of NativeECSqlParseNode ${JSON.stringify(node)}`);
|
|
1095
|
+
}
|
|
1096
|
+
return new LimitClauseExpr(ValueExpr.deserialize(node.exp), node.offset ? ValueExpr.deserialize(node.offset) : undefined);
|
|
1097
|
+
}
|
|
1098
|
+
writeTo(writer) {
|
|
1099
|
+
writer.appendKeyword("LIMIT");
|
|
1100
|
+
writer.appendSpace();
|
|
1101
|
+
writer.appendExp(this.limit);
|
|
1102
|
+
if (this.offset) {
|
|
1103
|
+
writer.appendSpace();
|
|
1104
|
+
writer.appendKeyword("OFFSET");
|
|
1105
|
+
writer.appendSpace();
|
|
1106
|
+
writer.appendExp(this.offset);
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
LimitClauseExpr.type = ExprType.LimitClause;
|
|
1111
|
+
export { LimitClauseExpr };
|
|
1112
|
+
/**
|
|
1113
|
+
* Describe a single select statement.
|
|
1114
|
+
* @alpha
|
|
1115
|
+
*/
|
|
1116
|
+
class SelectExpr extends Expr {
|
|
1117
|
+
constructor(selection, rowQuantifier, from, where, groupBy, having, orderBy, limit, options) {
|
|
1118
|
+
super(SelectExpr.type);
|
|
1119
|
+
this.selection = selection;
|
|
1120
|
+
this.rowQuantifier = rowQuantifier;
|
|
1121
|
+
this.from = from;
|
|
1122
|
+
this.where = where;
|
|
1123
|
+
this.groupBy = groupBy;
|
|
1124
|
+
this.having = having;
|
|
1125
|
+
this.orderBy = orderBy;
|
|
1126
|
+
this.limit = limit;
|
|
1127
|
+
this.options = options;
|
|
1128
|
+
}
|
|
1129
|
+
get children() {
|
|
1130
|
+
const exprs = [this.selection];
|
|
1131
|
+
if (this.from)
|
|
1132
|
+
exprs.push(this.from);
|
|
1133
|
+
if (this.where)
|
|
1134
|
+
exprs.push(this.where);
|
|
1135
|
+
if (this.groupBy)
|
|
1136
|
+
exprs.push(this.groupBy);
|
|
1137
|
+
if (this.having)
|
|
1138
|
+
exprs.push(this.having);
|
|
1139
|
+
if (this.orderBy)
|
|
1140
|
+
exprs.push(this.orderBy);
|
|
1141
|
+
if (this.limit)
|
|
1142
|
+
exprs.push(this.limit);
|
|
1143
|
+
if (this.options)
|
|
1144
|
+
exprs.push(this.options);
|
|
1145
|
+
return exprs;
|
|
1146
|
+
}
|
|
1147
|
+
static deserialize(node) {
|
|
1148
|
+
if (node.id !== NativeExpIds.SingleSelectStatement && node.id !== NativeExpIds.RowConstructor) {
|
|
1149
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.SingleSelectStatement/RowConstructor'. ${JSON.stringify(node)}`);
|
|
1150
|
+
}
|
|
1151
|
+
if (node.id === NativeExpIds.RowConstructor) {
|
|
1152
|
+
const values = SelectionClauseExpr.deserialize(node.values);
|
|
1153
|
+
return new SelectExpr(values);
|
|
1154
|
+
}
|
|
1155
|
+
const selection = SelectionClauseExpr.deserialize(node.selection);
|
|
1156
|
+
const from = node.from ? FromClauseExpr.deserialize(node.from) : undefined;
|
|
1157
|
+
const where = node.where ? WhereClauseExp.deserialize(node.where) : undefined;
|
|
1158
|
+
const groupBy = node.groupBy ? GroupByClauseExpr.deserialize(node.groupBy) : undefined;
|
|
1159
|
+
const having = node.having ? HavingClauseExpr.deserialize(node.having) : undefined;
|
|
1160
|
+
const orderBy = node.orderBy ? OrderByClauseExpr.deserialize(node.orderBy) : undefined;
|
|
1161
|
+
const options = node.options ? ECSqlOptionsClauseExpr.deserialize(node.options) : undefined;
|
|
1162
|
+
const limitSpec = node.limit ? LimitClauseExpr.deserialize(node.limit) : undefined;
|
|
1163
|
+
const rowQuantifier = node.selectionType ? node.selectionType : undefined;
|
|
1164
|
+
return new SelectExpr(selection, rowQuantifier, from, where, groupBy, having, orderBy, limitSpec, options);
|
|
1165
|
+
}
|
|
1166
|
+
writeTo(writer) {
|
|
1167
|
+
writer.appendKeyword("SELECT");
|
|
1168
|
+
writer.appendSpace();
|
|
1169
|
+
if (this.rowQuantifier) {
|
|
1170
|
+
writer.appendKeyword(this.rowQuantifier);
|
|
1171
|
+
writer.appendSpace();
|
|
1172
|
+
}
|
|
1173
|
+
writer.appendExp(this.selection);
|
|
1174
|
+
if (this.from) {
|
|
1175
|
+
writer.appendSpace();
|
|
1176
|
+
writer.appendExp(this.from);
|
|
1177
|
+
}
|
|
1178
|
+
if (this.where) {
|
|
1179
|
+
writer.appendSpace();
|
|
1180
|
+
writer.appendExp(this.where);
|
|
1181
|
+
}
|
|
1182
|
+
if (this.groupBy) {
|
|
1183
|
+
writer.appendSpace();
|
|
1184
|
+
writer.appendExp(this.groupBy);
|
|
1185
|
+
}
|
|
1186
|
+
if (this.having) {
|
|
1187
|
+
writer.appendSpace();
|
|
1188
|
+
writer.appendExp(this.having);
|
|
1189
|
+
}
|
|
1190
|
+
if (this.orderBy) {
|
|
1191
|
+
writer.appendSpace();
|
|
1192
|
+
writer.appendExp(this.orderBy);
|
|
1193
|
+
}
|
|
1194
|
+
if (this.limit) {
|
|
1195
|
+
writer.appendSpace();
|
|
1196
|
+
writer.appendExp(this.limit);
|
|
1197
|
+
}
|
|
1198
|
+
if (this.options) {
|
|
1199
|
+
writer.appendSpace();
|
|
1200
|
+
writer.appendExp(this.options);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
SelectExpr.type = ExprType.Select;
|
|
1205
|
+
export { SelectExpr };
|
|
1206
|
+
/**
|
|
1207
|
+
* Describe a subquery when used as value. This kind of query expect to return one column and one one value.
|
|
1208
|
+
* @alpha
|
|
1209
|
+
*/
|
|
1210
|
+
class SubqueryExpr extends ValueExpr {
|
|
1211
|
+
constructor(query) {
|
|
1212
|
+
super(SubqueryExpr.type);
|
|
1213
|
+
this.query = query;
|
|
1214
|
+
}
|
|
1215
|
+
get children() {
|
|
1216
|
+
return [this.query];
|
|
1217
|
+
}
|
|
1218
|
+
static deserialize(node) {
|
|
1219
|
+
if (node.id !== NativeExpIds.Subquery) {
|
|
1220
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.Subquery'. ${JSON.stringify(node)}`);
|
|
1221
|
+
}
|
|
1222
|
+
return new SubqueryExpr(SelectStatementExpr.deserialize(node.query));
|
|
1223
|
+
}
|
|
1224
|
+
writeTo(writer) {
|
|
1225
|
+
writer.append("(");
|
|
1226
|
+
writer.appendExp(this.query);
|
|
1227
|
+
writer.append(")");
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
SubqueryExpr.type = ExprType.Subquery;
|
|
1231
|
+
export { SubqueryExpr };
|
|
1232
|
+
/**
|
|
1233
|
+
* Describe a binary boolean expression in ECSQL.
|
|
1234
|
+
* @alpha
|
|
1235
|
+
*/
|
|
1236
|
+
class BinaryBooleanExpr extends BooleanExpr {
|
|
1237
|
+
constructor(op, lhsExpr, rhsExpr, not) {
|
|
1238
|
+
super(BinaryBooleanExpr.type);
|
|
1239
|
+
this.op = op;
|
|
1240
|
+
this.lhsExpr = lhsExpr;
|
|
1241
|
+
this.rhsExpr = rhsExpr;
|
|
1242
|
+
this.not = not;
|
|
1243
|
+
}
|
|
1244
|
+
get children() {
|
|
1245
|
+
return [this.lhsExpr, this.rhsExpr];
|
|
1246
|
+
}
|
|
1247
|
+
static deserialize(node) {
|
|
1248
|
+
if (node.id !== NativeExpIds.BinaryBoolean) {
|
|
1249
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryBoolean'. ${JSON.stringify(node)}`);
|
|
1250
|
+
}
|
|
1251
|
+
const op = node.op;
|
|
1252
|
+
return new BinaryBooleanExpr(op, ComputedExpr.deserialize(node.lhs), ComputedExpr.deserialize(node.rhs));
|
|
1253
|
+
}
|
|
1254
|
+
writeTo(writer) {
|
|
1255
|
+
writer.append("(");
|
|
1256
|
+
writer.appendExp(this.lhsExpr);
|
|
1257
|
+
writer.appendBinaryOp(this.op);
|
|
1258
|
+
writer.appendExp(this.rhsExpr);
|
|
1259
|
+
writer.append(")");
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
BinaryBooleanExpr.type = ExprType.BinaryBoolean;
|
|
1263
|
+
export { BinaryBooleanExpr };
|
|
1264
|
+
/**
|
|
1265
|
+
* Describe a <expr> IS NULL boolean expression
|
|
1266
|
+
* @alpha
|
|
1267
|
+
*/
|
|
1268
|
+
class IsNullExpr extends BooleanExpr {
|
|
1269
|
+
constructor(operandExpr, not) {
|
|
1270
|
+
super(IsNullExpr.type);
|
|
1271
|
+
this.operandExpr = operandExpr;
|
|
1272
|
+
this.not = not;
|
|
1273
|
+
}
|
|
1274
|
+
get children() {
|
|
1275
|
+
return [this.operandExpr];
|
|
1276
|
+
}
|
|
1277
|
+
static parseOp(node) {
|
|
1278
|
+
const op = node.op;
|
|
1279
|
+
const isLiteral = node.rhs.op === NativeExpIds.LiteralValue;
|
|
1280
|
+
if (!isLiteral) {
|
|
1281
|
+
return [false, false];
|
|
1282
|
+
}
|
|
1283
|
+
const isNull = LiteralExpr.deserialize(node.rhs).rawValue === "NULL";
|
|
1284
|
+
return [op.startsWith("IS"), isNull];
|
|
1285
|
+
}
|
|
1286
|
+
static deserialize(node) {
|
|
1287
|
+
if (node.id !== NativeExpIds.BinaryBoolean) {
|
|
1288
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryBoolean'. ${JSON.stringify(node)}`);
|
|
1289
|
+
}
|
|
1290
|
+
const [isNullExp, isNull] = this.parseOp(node);
|
|
1291
|
+
if (!isNullExp) {
|
|
1292
|
+
throw new Error(`Parse node has 'node.op !== IS NULL'. ${JSON.stringify(node)}`);
|
|
1293
|
+
}
|
|
1294
|
+
const exp = ValueExpr.deserialize(node.lhs);
|
|
1295
|
+
return new IsNullExpr(exp, isNull ? "NOT" : undefined);
|
|
1296
|
+
}
|
|
1297
|
+
writeTo(writer) {
|
|
1298
|
+
writer.appendExp(this.operandExpr);
|
|
1299
|
+
writer.appendSpace();
|
|
1300
|
+
writer.appendKeyword("IS");
|
|
1301
|
+
writer.appendSpace();
|
|
1302
|
+
if (this.not) {
|
|
1303
|
+
writer.appendKeyword("NOT");
|
|
1304
|
+
writer.appendSpace();
|
|
1305
|
+
}
|
|
1306
|
+
writer.appendKeyword("NULL");
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
IsNullExpr.type = ExprType.IsNull;
|
|
1310
|
+
export { IsNullExpr };
|
|
1311
|
+
/**
|
|
1312
|
+
* Describe a <expr> IS (type1[, type2]) in ECSQL.
|
|
1313
|
+
* @alpha
|
|
1314
|
+
*/
|
|
1315
|
+
class IsOfTypeExpr extends BooleanExpr {
|
|
1316
|
+
constructor(lhsExpr, typeNames, not) {
|
|
1317
|
+
super(IsOfTypeExpr.type);
|
|
1318
|
+
this.lhsExpr = lhsExpr;
|
|
1319
|
+
this.typeNames = typeNames;
|
|
1320
|
+
this.not = not;
|
|
1321
|
+
}
|
|
1322
|
+
get children() {
|
|
1323
|
+
return [this.lhsExpr, ...this.typeNames];
|
|
1324
|
+
}
|
|
1325
|
+
static parseOp(node) {
|
|
1326
|
+
const op = node.op;
|
|
1327
|
+
return [op.startsWith("IS") && Array.isArray(node.rhs), op.endsWith("NOT")];
|
|
1328
|
+
}
|
|
1329
|
+
static deserialize(node) {
|
|
1330
|
+
if (node.id !== NativeExpIds.BinaryBoolean) {
|
|
1331
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryBoolean'. ${JSON.stringify(node)}`);
|
|
1332
|
+
}
|
|
1333
|
+
const [isTypeOf, isNull] = this.parseOp(node);
|
|
1334
|
+
if (!isTypeOf) {
|
|
1335
|
+
throw new Error(`Parse node has 'node.op !== IS (type....)'. ${JSON.stringify(node)}`);
|
|
1336
|
+
}
|
|
1337
|
+
const exp = ValueExpr.deserialize(node.lhs);
|
|
1338
|
+
const classNames = Array.from(node.rhs.map((v) => ClassNameExpr.deserialize(v)));
|
|
1339
|
+
return new IsOfTypeExpr(exp, classNames, isNull ? "NOT" : undefined);
|
|
1340
|
+
}
|
|
1341
|
+
writeTo(writer) {
|
|
1342
|
+
writer.appendExp(this.lhsExpr);
|
|
1343
|
+
writer.appendSpace();
|
|
1344
|
+
writer.appendKeyword("IS");
|
|
1345
|
+
writer.appendSpace();
|
|
1346
|
+
if (this.not) {
|
|
1347
|
+
writer.appendKeyword("NOT");
|
|
1348
|
+
writer.appendSpace();
|
|
1349
|
+
}
|
|
1350
|
+
writer.append("(");
|
|
1351
|
+
this.typeNames.forEach((v, i) => {
|
|
1352
|
+
if (i > 0) {
|
|
1353
|
+
writer.appendComma();
|
|
1354
|
+
}
|
|
1355
|
+
writer.appendExp(v);
|
|
1356
|
+
});
|
|
1357
|
+
writer.append(")");
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
IsOfTypeExpr.type = ExprType.IsOfType;
|
|
1361
|
+
export { IsOfTypeExpr };
|
|
1362
|
+
/**
|
|
1363
|
+
* Describe a NOT <expr> boolean expression
|
|
1364
|
+
* @alpha
|
|
1365
|
+
*/
|
|
1366
|
+
class NotExpr extends BooleanExpr {
|
|
1367
|
+
constructor(operandExpr) {
|
|
1368
|
+
super(NotExpr.type);
|
|
1369
|
+
this.operandExpr = operandExpr;
|
|
1370
|
+
}
|
|
1371
|
+
get children() {
|
|
1372
|
+
return [this.operandExpr];
|
|
1373
|
+
}
|
|
1374
|
+
static deserialize(node) {
|
|
1375
|
+
if (node.id !== NativeExpIds.BooleanFactor) {
|
|
1376
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BooleanFactor'. ${JSON.stringify(node)}`);
|
|
1377
|
+
}
|
|
1378
|
+
const exp = ComputedExpr.deserialize(node.exp);
|
|
1379
|
+
return new NotExpr(exp);
|
|
1380
|
+
}
|
|
1381
|
+
writeTo(writer) {
|
|
1382
|
+
writer.append("(");
|
|
1383
|
+
writer.appendKeyword("NOT");
|
|
1384
|
+
writer.appendSpace();
|
|
1385
|
+
writer.appendExp(this.operandExpr);
|
|
1386
|
+
writer.append(")");
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
NotExpr.type = ExprType.Not;
|
|
1390
|
+
export { NotExpr };
|
|
1391
|
+
/**
|
|
1392
|
+
* Describe a <expr> IN subquery|(val1[,val2...]) boolean expression
|
|
1393
|
+
* @alpha
|
|
1394
|
+
*/
|
|
1395
|
+
class InExpr extends BooleanExpr {
|
|
1396
|
+
constructor(lhsExpr, rhsExpr, not) {
|
|
1397
|
+
super(InExpr.type);
|
|
1398
|
+
this.lhsExpr = lhsExpr;
|
|
1399
|
+
this.rhsExpr = rhsExpr;
|
|
1400
|
+
this.not = not;
|
|
1401
|
+
}
|
|
1402
|
+
get children() {
|
|
1403
|
+
const exprs = [this.lhsExpr];
|
|
1404
|
+
if (this.rhsExpr instanceof SubqueryExpr)
|
|
1405
|
+
exprs.push(this.rhsExpr);
|
|
1406
|
+
else {
|
|
1407
|
+
exprs.push(...this.rhsExpr);
|
|
1408
|
+
}
|
|
1409
|
+
return exprs;
|
|
1410
|
+
}
|
|
1411
|
+
static parseOp(op) {
|
|
1412
|
+
return [op.endsWith("IN"), op.startsWith("NOT ")];
|
|
1413
|
+
}
|
|
1414
|
+
static deserialize(node) {
|
|
1415
|
+
if (node.id !== NativeExpIds.BinaryBoolean) {
|
|
1416
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryBoolean'. ${JSON.stringify(node)}`);
|
|
1417
|
+
}
|
|
1418
|
+
const [isIn, isNull] = this.parseOp(node.op);
|
|
1419
|
+
if (!isIn) {
|
|
1420
|
+
throw new Error(`Parse node has 'node.op !== IN'. ${JSON.stringify(node)}`);
|
|
1421
|
+
}
|
|
1422
|
+
const lhs = ValueExpr.deserialize(node.lhs);
|
|
1423
|
+
if (Array.isArray(node.rhs))
|
|
1424
|
+
return new InExpr(lhs, Array.from(node.rhs.map((v) => ValueExpr.deserialize(v))), isNull ? "NOT" : undefined);
|
|
1425
|
+
else if (node.rhs.id === NativeExpIds.Subquery)
|
|
1426
|
+
return new InExpr(lhs, SubqueryExpr.deserialize(node.rhs), isNull ? "NOT" : undefined);
|
|
1427
|
+
else
|
|
1428
|
+
throw new Error(`unknown IN rhs ${node.rhs.id}`);
|
|
1429
|
+
}
|
|
1430
|
+
writeTo(writer) {
|
|
1431
|
+
writer.appendExp(this.lhsExpr);
|
|
1432
|
+
writer.appendSpace();
|
|
1433
|
+
if (this.not) {
|
|
1434
|
+
writer.appendKeyword("NOT");
|
|
1435
|
+
writer.appendSpace();
|
|
1436
|
+
}
|
|
1437
|
+
writer.appendKeyword("IN");
|
|
1438
|
+
writer.appendSpace();
|
|
1439
|
+
if (this.rhsExpr instanceof SubqueryExpr) {
|
|
1440
|
+
writer.appendExp(this.rhsExpr);
|
|
1441
|
+
}
|
|
1442
|
+
else if (Array.isArray(this.rhsExpr)) {
|
|
1443
|
+
writer.append("(");
|
|
1444
|
+
this.rhsExpr.forEach((v, i) => {
|
|
1445
|
+
if (i > 0) {
|
|
1446
|
+
writer.appendComma();
|
|
1447
|
+
}
|
|
1448
|
+
writer.appendExp(v);
|
|
1449
|
+
});
|
|
1450
|
+
writer.append(")");
|
|
1451
|
+
}
|
|
1452
|
+
else {
|
|
1453
|
+
throw new Error("unknown expression on rhs of IN expr.");
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
InExpr.type = ExprType.In;
|
|
1458
|
+
export { InExpr };
|
|
1459
|
+
/**
|
|
1460
|
+
* Describe a <expr> LIKE <expr> [ESCAPE <expr>] boolean expression
|
|
1461
|
+
* @alpha
|
|
1462
|
+
*/
|
|
1463
|
+
class LikeExpr extends BooleanExpr {
|
|
1464
|
+
constructor(lhsExpr, patternExpr, escapeExpr, not) {
|
|
1465
|
+
super(LikeExpr.type);
|
|
1466
|
+
this.lhsExpr = lhsExpr;
|
|
1467
|
+
this.patternExpr = patternExpr;
|
|
1468
|
+
this.escapeExpr = escapeExpr;
|
|
1469
|
+
this.not = not;
|
|
1470
|
+
}
|
|
1471
|
+
get children() {
|
|
1472
|
+
const exprs = [this.lhsExpr, this.patternExpr];
|
|
1473
|
+
if (this.escapeExpr)
|
|
1474
|
+
exprs.push(this.escapeExpr);
|
|
1475
|
+
return exprs;
|
|
1476
|
+
}
|
|
1477
|
+
static parseOp(op) {
|
|
1478
|
+
return [op.endsWith("LIKE"), op.startsWith("NOT ")];
|
|
1479
|
+
}
|
|
1480
|
+
static deserialize(node) {
|
|
1481
|
+
if (node.id !== NativeExpIds.BinaryBoolean) {
|
|
1482
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryBoolean'. ${JSON.stringify(node)}`);
|
|
1483
|
+
}
|
|
1484
|
+
const [isLike, isNull] = this.parseOp(node.op);
|
|
1485
|
+
if (!isLike) {
|
|
1486
|
+
throw new Error(`Parse node has 'node.op !== LIKE'. ${JSON.stringify(node)}`);
|
|
1487
|
+
}
|
|
1488
|
+
const lhs = ValueExpr.deserialize(node.lhs);
|
|
1489
|
+
const pattren = ValueExpr.deserialize(node.rhs.pattren);
|
|
1490
|
+
const escape = node.rhs.escape ? ValueExpr.deserialize(node.rhs.escape) : undefined;
|
|
1491
|
+
return new LikeExpr(lhs, pattren, escape, isNull ? "NOT" : undefined);
|
|
1492
|
+
}
|
|
1493
|
+
writeTo(writer) {
|
|
1494
|
+
writer.appendExp(this.lhsExpr);
|
|
1495
|
+
writer.appendSpace();
|
|
1496
|
+
if (this.not) {
|
|
1497
|
+
writer.appendKeyword("NOT");
|
|
1498
|
+
writer.appendSpace();
|
|
1499
|
+
}
|
|
1500
|
+
writer.appendKeyword("LIKE");
|
|
1501
|
+
writer.appendSpace();
|
|
1502
|
+
writer.appendExp(this.patternExpr);
|
|
1503
|
+
if (this.escapeExpr) {
|
|
1504
|
+
writer.appendSpace();
|
|
1505
|
+
writer.appendKeyword("ESCAPE");
|
|
1506
|
+
writer.appendSpace();
|
|
1507
|
+
writer.appendExp(this.escapeExpr);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
LikeExpr.type = ExprType.Like;
|
|
1512
|
+
export { LikeExpr };
|
|
1513
|
+
/**
|
|
1514
|
+
* Describe a <expr> BETWEEN <expr> AND <expr> boolean expression
|
|
1515
|
+
* @alpha
|
|
1516
|
+
*/
|
|
1517
|
+
class BetweenExpr extends BooleanExpr {
|
|
1518
|
+
constructor(lhsExpr, lowerBoundExpr, upperBoundExpr, not) {
|
|
1519
|
+
super(BetweenExpr.type);
|
|
1520
|
+
this.lhsExpr = lhsExpr;
|
|
1521
|
+
this.lowerBoundExpr = lowerBoundExpr;
|
|
1522
|
+
this.upperBoundExpr = upperBoundExpr;
|
|
1523
|
+
this.not = not;
|
|
1524
|
+
}
|
|
1525
|
+
get children() {
|
|
1526
|
+
return [this.lhsExpr, this.lowerBoundExpr, this.upperBoundExpr];
|
|
1527
|
+
}
|
|
1528
|
+
static parseOp(op) {
|
|
1529
|
+
return [op.endsWith(" BETWEEN"), op.startsWith("NOT ")];
|
|
1530
|
+
}
|
|
1531
|
+
static deserialize(node) {
|
|
1532
|
+
if (node.id !== NativeExpIds.BinaryBoolean) {
|
|
1533
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryBoolean'. ${JSON.stringify(node)}`);
|
|
1534
|
+
}
|
|
1535
|
+
const [isBetween, isNull] = this.parseOp(node.op);
|
|
1536
|
+
if (!isBetween) {
|
|
1537
|
+
throw new Error(`Parse node has 'node.op !== BETWEEN'. ${JSON.stringify(node)}`);
|
|
1538
|
+
}
|
|
1539
|
+
const rhs = node.rhs;
|
|
1540
|
+
return new BetweenExpr(ValueExpr.deserialize(node.lhs), ValueExpr.deserialize(rhs.lbound), ValueExpr.deserialize(rhs.ubound), isNull ? "NOT" : undefined);
|
|
1541
|
+
}
|
|
1542
|
+
writeTo(writer) {
|
|
1543
|
+
writer.appendExp(this.lhsExpr);
|
|
1544
|
+
writer.appendSpace();
|
|
1545
|
+
if (this.not) {
|
|
1546
|
+
writer.appendKeyword("NOT");
|
|
1547
|
+
writer.appendSpace();
|
|
1548
|
+
}
|
|
1549
|
+
writer.appendKeyword("BETWEEN");
|
|
1550
|
+
writer.appendSpace();
|
|
1551
|
+
writer.appendExp(this.lowerBoundExpr);
|
|
1552
|
+
writer.appendSpace();
|
|
1553
|
+
writer.appendKeyword("AND");
|
|
1554
|
+
writer.appendSpace();
|
|
1555
|
+
writer.appendExp(this.upperBoundExpr);
|
|
1556
|
+
}
|
|
1557
|
+
}
|
|
1558
|
+
BetweenExpr.type = ExprType.Between;
|
|
1559
|
+
export { BetweenExpr };
|
|
1560
|
+
/**
|
|
1561
|
+
* Describe a common table expression base query statement
|
|
1562
|
+
* @alpha
|
|
1563
|
+
*/
|
|
1564
|
+
class CteExpr extends StatementExpr {
|
|
1565
|
+
constructor(cteBlocks, query, recursive) {
|
|
1566
|
+
super(CteExpr.type);
|
|
1567
|
+
this.cteBlocks = cteBlocks;
|
|
1568
|
+
this.query = query;
|
|
1569
|
+
this.recursive = recursive;
|
|
1570
|
+
}
|
|
1571
|
+
get children() {
|
|
1572
|
+
return [...this.cteBlocks, this.query];
|
|
1573
|
+
}
|
|
1574
|
+
static deserialize(node) {
|
|
1575
|
+
if (node.id !== NativeExpIds.CommonTable) {
|
|
1576
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.CommonTable'. ${JSON.stringify(node)}`);
|
|
1577
|
+
}
|
|
1578
|
+
const blocks = Array.from(node.blocks.map((v) => CteBlockExpr.deserialize(v)));
|
|
1579
|
+
return new CteExpr(blocks, SelectStatementExpr.deserialize(node.select), node.recursive === true ? "RECURSIVE" : undefined);
|
|
1580
|
+
}
|
|
1581
|
+
writeTo(writer) {
|
|
1582
|
+
writer.appendKeyword("WITH");
|
|
1583
|
+
writer.appendSpace();
|
|
1584
|
+
if (this.recursive) {
|
|
1585
|
+
writer.appendKeyword(this.recursive);
|
|
1586
|
+
writer.appendSpace();
|
|
1587
|
+
}
|
|
1588
|
+
this.cteBlocks.forEach((v, i) => {
|
|
1589
|
+
if (i > 0) {
|
|
1590
|
+
writer.appendComma();
|
|
1591
|
+
}
|
|
1592
|
+
writer.appendExp(v);
|
|
1593
|
+
});
|
|
1594
|
+
writer.appendSpace();
|
|
1595
|
+
writer.appendExp(this.query);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
CteExpr.type = ExprType.Cte;
|
|
1599
|
+
export { CteExpr };
|
|
1600
|
+
/**
|
|
1601
|
+
* Describe a single block of CTE that can be reference in FROM clause of a SELECT
|
|
1602
|
+
* @alpha
|
|
1603
|
+
*/
|
|
1604
|
+
class CteBlockExpr extends Expr {
|
|
1605
|
+
constructor(name, query, props) {
|
|
1606
|
+
super(CteBlockExpr.type);
|
|
1607
|
+
this.name = name;
|
|
1608
|
+
this.query = query;
|
|
1609
|
+
this.props = props;
|
|
1610
|
+
}
|
|
1611
|
+
get children() {
|
|
1612
|
+
return [this.query];
|
|
1613
|
+
}
|
|
1614
|
+
static deserialize(node) {
|
|
1615
|
+
if (node.id !== NativeExpIds.CommonTableBlock) {
|
|
1616
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.CommonTableBlock'. ${JSON.stringify(node)}`);
|
|
1617
|
+
}
|
|
1618
|
+
return new CteBlockExpr(node.name, SelectStatementExpr.deserialize(node.asQuery), node.args);
|
|
1619
|
+
}
|
|
1620
|
+
writeTo(writer) {
|
|
1621
|
+
writer.appendQuoted(this.name);
|
|
1622
|
+
writer.append("(");
|
|
1623
|
+
this.props.forEach((v, i) => {
|
|
1624
|
+
if (i > 0) {
|
|
1625
|
+
writer.appendComma();
|
|
1626
|
+
}
|
|
1627
|
+
writer.appendQuoted(v);
|
|
1628
|
+
});
|
|
1629
|
+
writer.append(")");
|
|
1630
|
+
writer.appendSpace();
|
|
1631
|
+
writer.appendKeyword("AS");
|
|
1632
|
+
writer.appendSpace();
|
|
1633
|
+
writer.append("(");
|
|
1634
|
+
writer.appendLine();
|
|
1635
|
+
writer.indent();
|
|
1636
|
+
writer.appendExp(this.query);
|
|
1637
|
+
writer.unindent();
|
|
1638
|
+
writer.appendLine();
|
|
1639
|
+
writer.append(")");
|
|
1640
|
+
}
|
|
1641
|
+
}
|
|
1642
|
+
CteBlockExpr.type = ExprType.CteBlock;
|
|
1643
|
+
export { CteBlockExpr };
|
|
1644
|
+
/**
|
|
1645
|
+
* Describe a name reference to a CTE block.
|
|
1646
|
+
* @alpha
|
|
1647
|
+
*/
|
|
1648
|
+
class CteBlockRefExpr extends ClassRefExpr {
|
|
1649
|
+
constructor(name, alias) {
|
|
1650
|
+
super(CteBlockRefExpr.type);
|
|
1651
|
+
this.name = name;
|
|
1652
|
+
this.alias = alias;
|
|
1653
|
+
}
|
|
1654
|
+
get children() {
|
|
1655
|
+
return [];
|
|
1656
|
+
}
|
|
1657
|
+
static deserialize(node) {
|
|
1658
|
+
if (node.id !== NativeExpIds.CommonTableBlockName) {
|
|
1659
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.CommonTableBlockName'. ${JSON.stringify(node)}`);
|
|
1660
|
+
}
|
|
1661
|
+
return new CteBlockRefExpr(node.name, node.alias ? node.alias : undefined);
|
|
1662
|
+
}
|
|
1663
|
+
writeTo(writer) {
|
|
1664
|
+
writer.appendQuoted(this.name);
|
|
1665
|
+
if (this.alias) {
|
|
1666
|
+
writer.appendQuoted(this.alias);
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
CteBlockRefExpr.type = ExprType.CteBlockRef;
|
|
1671
|
+
export { CteBlockRefExpr };
|
|
1672
|
+
/**
|
|
1673
|
+
* Describe a table value function expression in ECSQL that appear in FROM clause of query.
|
|
1674
|
+
* @alpha
|
|
1675
|
+
*/
|
|
1676
|
+
class TableValuedFuncExpr extends ClassRefExpr {
|
|
1677
|
+
constructor(schemaName, memberFunc, alias) {
|
|
1678
|
+
super(TableValuedFuncExpr.type);
|
|
1679
|
+
this.schemaName = schemaName;
|
|
1680
|
+
this.memberFunc = memberFunc;
|
|
1681
|
+
this.alias = alias;
|
|
1682
|
+
}
|
|
1683
|
+
get children() {
|
|
1684
|
+
return [this.memberFunc];
|
|
1685
|
+
}
|
|
1686
|
+
static deserialize(node) {
|
|
1687
|
+
if (node.id !== NativeExpIds.TableValuedFunction) {
|
|
1688
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.TableValuedFunction'. ${JSON.stringify(node)}`);
|
|
1689
|
+
}
|
|
1690
|
+
return new TableValuedFuncExpr(node.schema, MemberFuncCallExpr.deserialize(node.func), node.alias);
|
|
1691
|
+
}
|
|
1692
|
+
writeTo(writer) {
|
|
1693
|
+
writer.appendQuoted(this.schemaName);
|
|
1694
|
+
writer.append(".");
|
|
1695
|
+
writer.appendExp(this.memberFunc);
|
|
1696
|
+
if (this.alias) {
|
|
1697
|
+
writer.appendSpace();
|
|
1698
|
+
writer.appendQuoted(this.alias);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
TableValuedFuncExpr.type = ExprType.TableValuedFunc;
|
|
1703
|
+
export { TableValuedFuncExpr };
|
|
1704
|
+
/**
|
|
1705
|
+
* Describe a class name reference in ECSQL that appear in FROM clause of a SELECT.
|
|
1706
|
+
* @alpha
|
|
1707
|
+
*/
|
|
1708
|
+
class ClassNameExpr extends ClassRefExpr {
|
|
1709
|
+
constructor(schemaNameOrAlias, className, tablespace, alias, polymorphicInfo, memberFunc) {
|
|
1710
|
+
super(ClassNameExpr.type);
|
|
1711
|
+
this.schemaNameOrAlias = schemaNameOrAlias;
|
|
1712
|
+
this.className = className;
|
|
1713
|
+
this.tablespace = tablespace;
|
|
1714
|
+
this.alias = alias;
|
|
1715
|
+
this.polymorphicInfo = polymorphicInfo;
|
|
1716
|
+
this.memberFunc = memberFunc;
|
|
1717
|
+
}
|
|
1718
|
+
get children() {
|
|
1719
|
+
return [];
|
|
1720
|
+
}
|
|
1721
|
+
static deserialize(node) {
|
|
1722
|
+
if (node.id !== NativeExpIds.ClassName) {
|
|
1723
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.ClassName'. ${JSON.stringify(node)}`);
|
|
1724
|
+
}
|
|
1725
|
+
const className = node.className;
|
|
1726
|
+
const tablespace = node.tableSpace ? node.tableSpace : undefined;
|
|
1727
|
+
const schemaName = node.schemaName;
|
|
1728
|
+
const alias = node.alias ? node.alias : undefined;
|
|
1729
|
+
const polymorphicInfo = node.polymorphicInfo ? { disqualify: node.polymorphicInfo.disqualify, allOrAny: node.polymorphicInfo.scope } : undefined;
|
|
1730
|
+
const memberFunc = node.func ? MemberFuncCallExpr.deserialize(node.func) : undefined;
|
|
1731
|
+
return new ClassNameExpr(schemaName, className, tablespace, alias, polymorphicInfo, memberFunc);
|
|
1732
|
+
}
|
|
1733
|
+
writeTo(writer) {
|
|
1734
|
+
if (this.polymorphicInfo) {
|
|
1735
|
+
if (this.polymorphicInfo.disqualify) {
|
|
1736
|
+
writer.append(this.polymorphicInfo.disqualify);
|
|
1737
|
+
}
|
|
1738
|
+
writer.appendKeyword(this.polymorphicInfo.allOrAny);
|
|
1739
|
+
writer.appendSpace();
|
|
1740
|
+
}
|
|
1741
|
+
if (this.tablespace) {
|
|
1742
|
+
writer.append("[").append(this.tablespace).append("]");
|
|
1743
|
+
writer.append(".");
|
|
1744
|
+
}
|
|
1745
|
+
writer.append("[").append(this.schemaNameOrAlias).append("]");
|
|
1746
|
+
writer.append(".");
|
|
1747
|
+
writer.append("[").append(this.className).append("]");
|
|
1748
|
+
if (this.memberFunc) {
|
|
1749
|
+
writer.append(".");
|
|
1750
|
+
writer.appendExp(this.memberFunc);
|
|
1751
|
+
}
|
|
1752
|
+
if (this.alias) {
|
|
1753
|
+
writer.appendSpace();
|
|
1754
|
+
writer.appendQuoted(this.alias);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
static fromECSql(ecsql) {
|
|
1758
|
+
const regex = /\s*((\+)?\s*(ALL|ONLY)\s+)?(\[?(\w+)\]?[\.:])?\[?(\w+)\]?[\.:]\[?(\w+)\]?(\s+(AS)?(\s+(\w+)))?/i;
|
|
1759
|
+
const match = ecsql.match(regex);
|
|
1760
|
+
if (!match) {
|
|
1761
|
+
throw new Error("ECSQL className must follow syntax: [+][ALL|ONLY] [tablespace.][.|:][schemaOrAlias]][.|:][className] [AS] [alias");
|
|
1762
|
+
}
|
|
1763
|
+
const plus = match.at(2);
|
|
1764
|
+
const allOrOnlyStr = match.at(3);
|
|
1765
|
+
const tablespace = match.at(5);
|
|
1766
|
+
const schemaOrAlias = match.at(6);
|
|
1767
|
+
const className = match.at(7);
|
|
1768
|
+
const alias = match.at(11);
|
|
1769
|
+
if (!schemaOrAlias || !className)
|
|
1770
|
+
throw new Error("ECSQL className must follow syntax: [+][ALL|ONLY] [tablespace.][.|:][schemaOrAlias]][.|:][className] [AS] [alias");
|
|
1771
|
+
let polyInfo;
|
|
1772
|
+
if (allOrOnlyStr) {
|
|
1773
|
+
const allOrAny = allOrOnlyStr.toUpperCase();
|
|
1774
|
+
polyInfo = { disqualify: plus, allOrAny };
|
|
1775
|
+
}
|
|
1776
|
+
return new ClassNameExpr(schemaOrAlias, className, tablespace, alias, polyInfo);
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
ClassNameExpr.type = ExprType.ClassName;
|
|
1780
|
+
export { ClassNameExpr };
|
|
1781
|
+
/**
|
|
1782
|
+
* Describe a UPDATE statement in ECSQL.
|
|
1783
|
+
* @alpha
|
|
1784
|
+
*/
|
|
1785
|
+
class UpdateStatementExpr extends StatementExpr {
|
|
1786
|
+
constructor(className, assignement, where, options) {
|
|
1787
|
+
super(UpdateStatementExpr.type);
|
|
1788
|
+
this.className = className;
|
|
1789
|
+
this.assignement = assignement;
|
|
1790
|
+
this.where = where;
|
|
1791
|
+
this.options = options;
|
|
1792
|
+
}
|
|
1793
|
+
get children() {
|
|
1794
|
+
const exprs = [this.className, this.assignement];
|
|
1795
|
+
if (this.where)
|
|
1796
|
+
exprs.push(this.where);
|
|
1797
|
+
if (this.options)
|
|
1798
|
+
exprs.push(this.options);
|
|
1799
|
+
return exprs;
|
|
1800
|
+
}
|
|
1801
|
+
static deserialize(node) {
|
|
1802
|
+
if (node.id !== NativeExpIds.UpdateStatement) {
|
|
1803
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.UpdateStatement'. ${JSON.stringify(node)}`);
|
|
1804
|
+
}
|
|
1805
|
+
const className = ClassNameExpr.deserialize(node.className);
|
|
1806
|
+
const assignment = SetClauseExpr.deserialize(node.assignment);
|
|
1807
|
+
const where = node.where ? WhereClauseExp.deserialize(node.where) : undefined;
|
|
1808
|
+
const options = node.options ? ECSqlOptionsClauseExpr.deserialize(node.options) : undefined;
|
|
1809
|
+
return new UpdateStatementExpr(className, assignment, where, options);
|
|
1810
|
+
}
|
|
1811
|
+
writeTo(writer) {
|
|
1812
|
+
writer.appendKeyword("UPDATE");
|
|
1813
|
+
writer.appendSpace();
|
|
1814
|
+
writer.appendExp(this.className);
|
|
1815
|
+
writer.appendSpace();
|
|
1816
|
+
writer.appendExp(this.assignement);
|
|
1817
|
+
if (this.where) {
|
|
1818
|
+
writer.appendSpace();
|
|
1819
|
+
writer.appendExp(this.where);
|
|
1820
|
+
}
|
|
1821
|
+
if (this.options) {
|
|
1822
|
+
writer.appendSpace();
|
|
1823
|
+
writer.appendExp(this.options);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
UpdateStatementExpr.type = ExprType.UpdateStatement;
|
|
1828
|
+
export { UpdateStatementExpr };
|
|
1829
|
+
/**
|
|
1830
|
+
* Describe ECSQL option clause.
|
|
1831
|
+
* @alpha
|
|
1832
|
+
*/
|
|
1833
|
+
class ECSqlOptionsClauseExpr extends Expr {
|
|
1834
|
+
constructor(options) {
|
|
1835
|
+
super(ECSqlOptionsClauseExpr.type);
|
|
1836
|
+
this.options = options;
|
|
1837
|
+
}
|
|
1838
|
+
get children() {
|
|
1839
|
+
return [];
|
|
1840
|
+
}
|
|
1841
|
+
static deserialize(node) {
|
|
1842
|
+
if (node.id !== NativeExpIds.Options) {
|
|
1843
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.Options'. ${JSON.stringify(node)}`);
|
|
1844
|
+
}
|
|
1845
|
+
return new ECSqlOptionsClauseExpr(node.options);
|
|
1846
|
+
}
|
|
1847
|
+
writeTo(writer) {
|
|
1848
|
+
writer.appendKeyword("ECSQLOPTIONS");
|
|
1849
|
+
writer.appendSpace();
|
|
1850
|
+
this.options.forEach((v, i) => {
|
|
1851
|
+
if (i > 0) {
|
|
1852
|
+
writer.appendSpace();
|
|
1853
|
+
}
|
|
1854
|
+
writer.append(v.name);
|
|
1855
|
+
if (v.value) {
|
|
1856
|
+
writer.appendBinaryOp("=");
|
|
1857
|
+
writer.append(v.value);
|
|
1858
|
+
}
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1862
|
+
ECSqlOptionsClauseExpr.type = ExprType.ECSqlOptionsClause;
|
|
1863
|
+
export { ECSqlOptionsClauseExpr };
|
|
1864
|
+
/**
|
|
1865
|
+
* A single property value assignment for update clause
|
|
1866
|
+
* @alpha
|
|
1867
|
+
*/
|
|
1868
|
+
class AssignmentExpr extends Expr {
|
|
1869
|
+
constructor(propertyName, valueExpr) {
|
|
1870
|
+
super(SetClauseExpr.type);
|
|
1871
|
+
this.propertyName = propertyName;
|
|
1872
|
+
this.valueExpr = valueExpr;
|
|
1873
|
+
}
|
|
1874
|
+
get children() {
|
|
1875
|
+
return [this.propertyName, this.valueExpr];
|
|
1876
|
+
}
|
|
1877
|
+
static deserialize(node) {
|
|
1878
|
+
if (node.id !== NativeExpIds.Assignment) {
|
|
1879
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.Assignment'. ${JSON.stringify(node)}`);
|
|
1880
|
+
}
|
|
1881
|
+
return new AssignmentExpr(PropertyNameExpr.deserialize(node.propertyName), ValueExpr.deserialize(node.value));
|
|
1882
|
+
}
|
|
1883
|
+
writeTo(writer) {
|
|
1884
|
+
writer.appendExp(this.propertyName);
|
|
1885
|
+
writer.appendBinaryOp("=");
|
|
1886
|
+
writer.appendExp(this.valueExpr);
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
AssignmentExpr.type = ExprType.Assignment;
|
|
1890
|
+
export { AssignmentExpr };
|
|
1891
|
+
/**
|
|
1892
|
+
* Describe a set clause in a UPDATE statement
|
|
1893
|
+
* @alpha
|
|
1894
|
+
*/
|
|
1895
|
+
class SetClauseExpr extends Expr {
|
|
1896
|
+
constructor(assignments) {
|
|
1897
|
+
super(SetClauseExpr.type);
|
|
1898
|
+
this.assignments = assignments;
|
|
1899
|
+
}
|
|
1900
|
+
get children() {
|
|
1901
|
+
return [...this.assignments];
|
|
1902
|
+
}
|
|
1903
|
+
static deserialize(node) {
|
|
1904
|
+
if (!Array.isArray(node)) {
|
|
1905
|
+
throw new Error(`AssignmentClause expect array of NativeECSqlParseNode. ${JSON.stringify(node)}`);
|
|
1906
|
+
}
|
|
1907
|
+
const setClause = node;
|
|
1908
|
+
const assignments = [];
|
|
1909
|
+
setClause.forEach((v) => {
|
|
1910
|
+
assignments.push(AssignmentExpr.deserialize(v));
|
|
1911
|
+
});
|
|
1912
|
+
return new SetClauseExpr(assignments);
|
|
1913
|
+
}
|
|
1914
|
+
writeTo(writer) {
|
|
1915
|
+
writer.appendKeyword("SET");
|
|
1916
|
+
writer.appendSpace();
|
|
1917
|
+
this.assignments.forEach((v, i) => {
|
|
1918
|
+
if (i > 0) {
|
|
1919
|
+
writer.appendComma();
|
|
1920
|
+
}
|
|
1921
|
+
writer.appendExp(v);
|
|
1922
|
+
});
|
|
1923
|
+
}
|
|
1924
|
+
}
|
|
1925
|
+
SetClauseExpr.type = ExprType.SetClause;
|
|
1926
|
+
export { SetClauseExpr };
|
|
1927
|
+
/**
|
|
1928
|
+
* Describe a strong typed IIF function in ECSQL
|
|
1929
|
+
* @alpha
|
|
1930
|
+
*/
|
|
1931
|
+
class IIFExpr extends ValueExpr {
|
|
1932
|
+
constructor(whenExpr, thenExpr, elseExpr) {
|
|
1933
|
+
super(IIFExpr.type);
|
|
1934
|
+
this.whenExpr = whenExpr;
|
|
1935
|
+
this.thenExpr = thenExpr;
|
|
1936
|
+
this.elseExpr = elseExpr;
|
|
1937
|
+
}
|
|
1938
|
+
get children() {
|
|
1939
|
+
return [this.whenExpr, this.thenExpr, this.elseExpr];
|
|
1940
|
+
}
|
|
1941
|
+
static deserialize(node) {
|
|
1942
|
+
if (node.id !== NativeExpIds.IIF) {
|
|
1943
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.IIF'. ${JSON.stringify(node)}`);
|
|
1944
|
+
}
|
|
1945
|
+
return new IIFExpr(BooleanExpr.deserialize(node.when), ValueExpr.deserialize(node.then), ValueExpr.deserialize(node.else));
|
|
1946
|
+
}
|
|
1947
|
+
writeTo(writer) {
|
|
1948
|
+
writer.appendKeyword("IIF");
|
|
1949
|
+
writer.append("(");
|
|
1950
|
+
writer.appendExp(this.whenExpr);
|
|
1951
|
+
writer.appendComma();
|
|
1952
|
+
writer.appendExp(this.thenExpr);
|
|
1953
|
+
writer.appendComma();
|
|
1954
|
+
writer.appendExp(this.elseExpr);
|
|
1955
|
+
writer.append(")");
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
IIFExpr.type = ExprType.IIF;
|
|
1959
|
+
export { IIFExpr };
|
|
1960
|
+
/**
|
|
1961
|
+
* Describe a CASE-WHEN-THEN expression in ECSQL
|
|
1962
|
+
* @alpha
|
|
1963
|
+
*/
|
|
1964
|
+
class SearchCaseExpr extends ValueExpr {
|
|
1965
|
+
constructor(whenThenList, elseExpr) {
|
|
1966
|
+
super(SearchCaseExpr.type);
|
|
1967
|
+
this.whenThenList = whenThenList;
|
|
1968
|
+
this.elseExpr = elseExpr;
|
|
1969
|
+
}
|
|
1970
|
+
get children() {
|
|
1971
|
+
const exprs = [];
|
|
1972
|
+
this.whenThenList.forEach((v) => {
|
|
1973
|
+
exprs.push(v.whenExpr, v.thenExpr);
|
|
1974
|
+
});
|
|
1975
|
+
if (this.elseExpr)
|
|
1976
|
+
exprs.push(this.elseExpr);
|
|
1977
|
+
return exprs;
|
|
1978
|
+
}
|
|
1979
|
+
static deserialize(node) {
|
|
1980
|
+
if (node.id !== NativeExpIds.SearchCaseValue) {
|
|
1981
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.SearchCaseValue'. ${JSON.stringify(node)}`);
|
|
1982
|
+
}
|
|
1983
|
+
const whenThenList = [];
|
|
1984
|
+
for (const whenThenProps of node.whenThenList) {
|
|
1985
|
+
whenThenList.push({
|
|
1986
|
+
whenExpr: BooleanExpr.deserialize(whenThenProps.when),
|
|
1987
|
+
thenExpr: ValueExpr.deserialize(whenThenProps.then),
|
|
1988
|
+
});
|
|
1989
|
+
}
|
|
1990
|
+
const elseExp = node.elseExp ? ValueExpr.deserialize(node.elseExp) : undefined;
|
|
1991
|
+
return new SearchCaseExpr(whenThenList, elseExp);
|
|
1992
|
+
}
|
|
1993
|
+
writeTo(writer) {
|
|
1994
|
+
writer.appendKeyword("CASE");
|
|
1995
|
+
this.whenThenList.forEach((v) => {
|
|
1996
|
+
writer.appendSpace();
|
|
1997
|
+
writer.appendKeyword("WHEN");
|
|
1998
|
+
writer.appendSpace();
|
|
1999
|
+
writer.appendExp(v.whenExpr);
|
|
2000
|
+
writer.appendSpace();
|
|
2001
|
+
writer.appendKeyword("THEN");
|
|
2002
|
+
writer.appendSpace();
|
|
2003
|
+
writer.appendExp(v.thenExpr);
|
|
2004
|
+
});
|
|
2005
|
+
if (this.elseExpr) {
|
|
2006
|
+
writer.appendSpace();
|
|
2007
|
+
writer.appendKeyword("ELSE");
|
|
2008
|
+
writer.appendSpace();
|
|
2009
|
+
writer.appendExp(this.elseExpr);
|
|
2010
|
+
}
|
|
2011
|
+
writer.appendSpace();
|
|
2012
|
+
writer.appendKeyword("END");
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
SearchCaseExpr.type = ExprType.SearchCase;
|
|
2016
|
+
export { SearchCaseExpr };
|
|
2017
|
+
/**
|
|
2018
|
+
* Describe a binary value expression
|
|
2019
|
+
* @alpha
|
|
2020
|
+
*/
|
|
2021
|
+
class BinaryValueExpr extends ValueExpr {
|
|
2022
|
+
constructor(op, lhsExpr, rhsExpr) {
|
|
2023
|
+
super(BinaryValueExpr.type);
|
|
2024
|
+
this.op = op;
|
|
2025
|
+
this.lhsExpr = lhsExpr;
|
|
2026
|
+
this.rhsExpr = rhsExpr;
|
|
2027
|
+
}
|
|
2028
|
+
get children() {
|
|
2029
|
+
return [this.lhsExpr, this.rhsExpr];
|
|
2030
|
+
}
|
|
2031
|
+
static deserialize(node) {
|
|
2032
|
+
if (node.id !== NativeExpIds.BinaryValue && node.id !== NativeExpIds.BinaryBoolean) {
|
|
2033
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.BinaryValue' . ${JSON.stringify(node)}`);
|
|
2034
|
+
}
|
|
2035
|
+
return new BinaryValueExpr(node.op, ValueExpr.deserialize(node.lhs), ValueExpr.deserialize(node.rhs));
|
|
2036
|
+
}
|
|
2037
|
+
writeTo(writer) {
|
|
2038
|
+
writer.append("(");
|
|
2039
|
+
writer.appendExp(this.lhsExpr);
|
|
2040
|
+
writer.appendBinaryOp(this.op);
|
|
2041
|
+
writer.appendExp(this.rhsExpr);
|
|
2042
|
+
writer.append(")");
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
BinaryValueExpr.type = ExprType.BinaryValue;
|
|
2046
|
+
export { BinaryValueExpr };
|
|
2047
|
+
/**
|
|
2048
|
+
* Cast a expression into a target time e.g. CAST(<expr> AS STRING)
|
|
2049
|
+
* @alpha
|
|
2050
|
+
*/
|
|
2051
|
+
class CastExpr extends ValueExpr {
|
|
2052
|
+
constructor(valueExpr, targetType) {
|
|
2053
|
+
super(CastExpr.type);
|
|
2054
|
+
this.valueExpr = valueExpr;
|
|
2055
|
+
this.targetType = targetType;
|
|
2056
|
+
}
|
|
2057
|
+
get children() {
|
|
2058
|
+
return [this.valueExpr];
|
|
2059
|
+
}
|
|
2060
|
+
static deserialize(node) {
|
|
2061
|
+
if (node.id !== NativeExpIds.Cast) {
|
|
2062
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.CastExp'. ${JSON.stringify(node)}`);
|
|
2063
|
+
}
|
|
2064
|
+
return new CastExpr(ValueExpr.deserialize(node.exp), node.as);
|
|
2065
|
+
}
|
|
2066
|
+
writeTo(writer) {
|
|
2067
|
+
writer.appendKeyword("CAST");
|
|
2068
|
+
writer.append("(");
|
|
2069
|
+
writer.appendExp(this.valueExpr);
|
|
2070
|
+
writer.appendSpace();
|
|
2071
|
+
writer.appendKeyword("AS");
|
|
2072
|
+
writer.appendSpace();
|
|
2073
|
+
writer.append(this.targetType);
|
|
2074
|
+
writer.append(")");
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
CastExpr.type = ExprType.Cast;
|
|
2078
|
+
export { CastExpr };
|
|
2079
|
+
/**
|
|
2080
|
+
* Represent a member function called w.r.t a ClassNameExpr
|
|
2081
|
+
* @alpha
|
|
2082
|
+
*/
|
|
2083
|
+
class MemberFuncCallExpr extends Expr {
|
|
2084
|
+
constructor(functionName, args) {
|
|
2085
|
+
super(MemberFuncCallExpr.type);
|
|
2086
|
+
this.functionName = functionName;
|
|
2087
|
+
this.args = args;
|
|
2088
|
+
}
|
|
2089
|
+
get children() {
|
|
2090
|
+
return [...this.args];
|
|
2091
|
+
}
|
|
2092
|
+
static deserialize(node) {
|
|
2093
|
+
if (node.id !== NativeExpIds.MemberFunctionCall) {
|
|
2094
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.MemberFunctionCall'. ${JSON.stringify(node)}`);
|
|
2095
|
+
}
|
|
2096
|
+
const args = Array.from(node.args.map((v) => ValueExpr.deserialize(v)));
|
|
2097
|
+
return new MemberFuncCallExpr(node.name, args);
|
|
2098
|
+
}
|
|
2099
|
+
writeTo(writer) {
|
|
2100
|
+
writer.appendQuoted(this.functionName);
|
|
2101
|
+
writer.append("(");
|
|
2102
|
+
this.args.forEach((v, i) => {
|
|
2103
|
+
if (i > 0) {
|
|
2104
|
+
writer.appendComma();
|
|
2105
|
+
}
|
|
2106
|
+
writer.appendExp(v);
|
|
2107
|
+
});
|
|
2108
|
+
writer.append(")");
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
MemberFuncCallExpr.type = ExprType.MemberFuncCall;
|
|
2112
|
+
export { MemberFuncCallExpr };
|
|
2113
|
+
/**
|
|
2114
|
+
* Represent a function call in ecsql
|
|
2115
|
+
* @alpha
|
|
2116
|
+
*/
|
|
2117
|
+
class FuncCallExpr extends ValueExpr {
|
|
2118
|
+
constructor(functionName, args, allOrDistinct) {
|
|
2119
|
+
super(FuncCallExpr.type);
|
|
2120
|
+
this.functionName = functionName;
|
|
2121
|
+
this.args = args;
|
|
2122
|
+
this.allOrDistinct = allOrDistinct;
|
|
2123
|
+
}
|
|
2124
|
+
get children() {
|
|
2125
|
+
return [...this.args];
|
|
2126
|
+
}
|
|
2127
|
+
static deserialize(node) {
|
|
2128
|
+
if (node.id !== NativeExpIds.FunctionCall) {
|
|
2129
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.FunctionCall'. ${JSON.stringify(node)}`);
|
|
2130
|
+
}
|
|
2131
|
+
const args = Array.from(node.args.map((v) => ValueExpr.deserialize(v)));
|
|
2132
|
+
const rowQuantifier = node.quantifier ? node.quantifier : undefined;
|
|
2133
|
+
return new FuncCallExpr(node.name, args, rowQuantifier);
|
|
2134
|
+
}
|
|
2135
|
+
writeTo(writer) {
|
|
2136
|
+
writer.append(this.functionName);
|
|
2137
|
+
writer.append("(");
|
|
2138
|
+
if (this.allOrDistinct) {
|
|
2139
|
+
writer.appendKeyword(this.allOrDistinct);
|
|
2140
|
+
writer.appendSpace();
|
|
2141
|
+
}
|
|
2142
|
+
this.args.forEach((v, i) => {
|
|
2143
|
+
if (i > 0) {
|
|
2144
|
+
writer.appendComma();
|
|
2145
|
+
}
|
|
2146
|
+
writer.appendExp(v);
|
|
2147
|
+
});
|
|
2148
|
+
writer.append(")");
|
|
2149
|
+
}
|
|
2150
|
+
static makeAbs(arg) {
|
|
2151
|
+
return new FuncCallExpr("ABS", [arg]);
|
|
2152
|
+
}
|
|
2153
|
+
static makeLower(arg) {
|
|
2154
|
+
return new FuncCallExpr("LOWER", [arg]);
|
|
2155
|
+
}
|
|
2156
|
+
static makeUpper(arg) {
|
|
2157
|
+
return new FuncCallExpr("UPPER", [arg]);
|
|
2158
|
+
}
|
|
2159
|
+
static makeLTrim(arg0, arg1) {
|
|
2160
|
+
return new FuncCallExpr("LTRIM", arg1 ? [arg0, arg1] : [arg0]);
|
|
2161
|
+
}
|
|
2162
|
+
static makeRTrim(arg0, arg1) {
|
|
2163
|
+
return new FuncCallExpr("RTRIM", arg1 ? [arg0, arg1] : [arg0]);
|
|
2164
|
+
}
|
|
2165
|
+
static makeLHex(arg) {
|
|
2166
|
+
return new FuncCallExpr("HEX", [arg]);
|
|
2167
|
+
}
|
|
2168
|
+
static makeLIfNull(arg0, arg1) {
|
|
2169
|
+
return new FuncCallExpr("IFNULL", [arg0, arg1]);
|
|
2170
|
+
}
|
|
2171
|
+
static makeInstr(arg0, arg1) {
|
|
2172
|
+
return new FuncCallExpr("INSTR", [arg0, arg1]);
|
|
2173
|
+
}
|
|
2174
|
+
static makeLength(arg0) {
|
|
2175
|
+
return new FuncCallExpr("LENGTH", [arg0]);
|
|
2176
|
+
}
|
|
2177
|
+
static makeLike(arg0, arg1, arg2) {
|
|
2178
|
+
return new FuncCallExpr("LIKE", arg2 ? [arg0, arg1, arg2] : [arg0, arg1]);
|
|
2179
|
+
}
|
|
2180
|
+
static makeLikelihood(arg0, arg1) {
|
|
2181
|
+
return new FuncCallExpr("LIKELIHOOD", [arg0, arg1]);
|
|
2182
|
+
}
|
|
2183
|
+
static makeMax(arg, ...optionalArgs) {
|
|
2184
|
+
return new FuncCallExpr("MAX", [arg, ...optionalArgs]);
|
|
2185
|
+
}
|
|
2186
|
+
static makeMin(arg, ...optionalArgs) {
|
|
2187
|
+
return new FuncCallExpr("MIN", [arg, ...optionalArgs]);
|
|
2188
|
+
}
|
|
2189
|
+
static makePrintf(arg, ...optionalArgs) {
|
|
2190
|
+
return new FuncCallExpr("PRINTF", [arg, ...optionalArgs]);
|
|
2191
|
+
}
|
|
2192
|
+
static makeRandom() {
|
|
2193
|
+
return new FuncCallExpr("RANDOM", []);
|
|
2194
|
+
}
|
|
2195
|
+
static makeQuote(arg) {
|
|
2196
|
+
return new FuncCallExpr("QUOTE", [arg]);
|
|
2197
|
+
}
|
|
2198
|
+
static makeRandomBlob(arg) {
|
|
2199
|
+
return new FuncCallExpr("RANDOMBLOB", [arg]);
|
|
2200
|
+
}
|
|
2201
|
+
static makeReplace(arg0, arg1, arg2) {
|
|
2202
|
+
return new FuncCallExpr("REPLACE", [arg0, arg1, arg2]);
|
|
2203
|
+
}
|
|
2204
|
+
static makeRound(arg0, arg1) {
|
|
2205
|
+
return new FuncCallExpr("ROUND", arg1 ? [arg0, arg1] : [arg0]);
|
|
2206
|
+
}
|
|
2207
|
+
static makeSign(arg0) {
|
|
2208
|
+
return new FuncCallExpr("SIGN", [arg0]);
|
|
2209
|
+
}
|
|
2210
|
+
static makeUnhex(arg0) {
|
|
2211
|
+
return new FuncCallExpr("UNHEX", [arg0]);
|
|
2212
|
+
}
|
|
2213
|
+
static makeSoundex(arg0) {
|
|
2214
|
+
return new FuncCallExpr("SOUNDEX", [arg0]);
|
|
2215
|
+
}
|
|
2216
|
+
static makeTrim(arg0, arg1) {
|
|
2217
|
+
return new FuncCallExpr("TRIM", arg1 ? [arg0, arg1] : [arg0]);
|
|
2218
|
+
}
|
|
2219
|
+
static makeTypeOf(arg0) {
|
|
2220
|
+
return new FuncCallExpr("TYPEOF", [arg0]);
|
|
2221
|
+
}
|
|
2222
|
+
static makeZeroBlob(arg0) {
|
|
2223
|
+
return new FuncCallExpr("ZEROBLOB", [arg0]);
|
|
2224
|
+
}
|
|
2225
|
+
static makeUnlikely(arg0) {
|
|
2226
|
+
return new FuncCallExpr("UNLIKELY", [arg0]);
|
|
2227
|
+
}
|
|
2228
|
+
static makeSubstring(arg0, arg1, arg2) {
|
|
2229
|
+
return new FuncCallExpr("SUBSTR", [arg0, arg1, arg2]);
|
|
2230
|
+
}
|
|
2231
|
+
static makeStrToGuid(arg0) {
|
|
2232
|
+
return new FuncCallExpr("STRTOGUID", [arg0]);
|
|
2233
|
+
}
|
|
2234
|
+
static makeGuidToStr(arg0) {
|
|
2235
|
+
return new FuncCallExpr("GUIDTOSTR", [arg0]);
|
|
2236
|
+
}
|
|
2237
|
+
static makeIdToHex(arg0) {
|
|
2238
|
+
return new FuncCallExpr("IDTOHEX", [arg0]);
|
|
2239
|
+
}
|
|
2240
|
+
static makeHexToId(arg0) {
|
|
2241
|
+
return new FuncCallExpr("HEXTOID", [arg0]);
|
|
2242
|
+
}
|
|
2243
|
+
static makeEcClassName(arg0, fmt = "s:c") {
|
|
2244
|
+
return new FuncCallExpr("EC_CLASSNAME", [arg0, new LiteralExpr(LiteralValueType.String, fmt)]);
|
|
2245
|
+
}
|
|
2246
|
+
static makeEcClassId(arg0) {
|
|
2247
|
+
return new FuncCallExpr("EC_CLASSId", [arg0]);
|
|
2248
|
+
}
|
|
2249
|
+
static makeInstanceOf(arg0, arg1) {
|
|
2250
|
+
return new FuncCallExpr("EC_INSTANCEOF", [arg0, arg1]);
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
FuncCallExpr.type = ExprType.FuncCall;
|
|
2254
|
+
export { FuncCallExpr };
|
|
2255
|
+
/**
|
|
2256
|
+
* Represent positional or named parameter
|
|
2257
|
+
* @alpha
|
|
2258
|
+
*/
|
|
2259
|
+
class ParameterExpr extends ValueExpr {
|
|
2260
|
+
constructor(name) {
|
|
2261
|
+
super(ParameterExpr.type);
|
|
2262
|
+
this.name = name;
|
|
2263
|
+
}
|
|
2264
|
+
get children() {
|
|
2265
|
+
return [];
|
|
2266
|
+
}
|
|
2267
|
+
static deserialize(node) {
|
|
2268
|
+
if (node.id !== NativeExpIds.Parameter) {
|
|
2269
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.Parameter'. ${JSON.stringify(node)}`);
|
|
2270
|
+
}
|
|
2271
|
+
return new ParameterExpr(node.name);
|
|
2272
|
+
}
|
|
2273
|
+
writeTo(writer) {
|
|
2274
|
+
if (this.name && this.name !== "")
|
|
2275
|
+
writer.append(`:${this.name}`);
|
|
2276
|
+
else
|
|
2277
|
+
writer.append(`?`);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
ParameterExpr.type = ExprType.Parameter;
|
|
2281
|
+
export { ParameterExpr };
|
|
2282
|
+
/**
|
|
2283
|
+
* Unary value with operator e.g. [+|-|~]<number>
|
|
2284
|
+
* @alpha
|
|
2285
|
+
*/
|
|
2286
|
+
class UnaryValueExpr extends ValueExpr {
|
|
2287
|
+
constructor(op, valueExpr) {
|
|
2288
|
+
super(UnaryValueExpr.type);
|
|
2289
|
+
this.op = op;
|
|
2290
|
+
this.valueExpr = valueExpr;
|
|
2291
|
+
}
|
|
2292
|
+
get children() {
|
|
2293
|
+
return [this.valueExpr];
|
|
2294
|
+
}
|
|
2295
|
+
static deserialize(node) {
|
|
2296
|
+
if (node.id !== NativeExpIds.UnaryValue && node.id !== NativeExpIds.BooleanFactor) {
|
|
2297
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.UnaryValue && node.id !== NativeExpIds.BooleanFactor'. ${JSON.stringify(node)}`);
|
|
2298
|
+
}
|
|
2299
|
+
if (node.op !== "+" && node.op !== "-" && node.op !== "~") {
|
|
2300
|
+
throw new Error(`Unrecognized operator in .node.op'. Must me on of UnaryOp. ${JSON.stringify(node)}`);
|
|
2301
|
+
}
|
|
2302
|
+
return new UnaryValueExpr(node.op, ValueExpr.deserialize(node.exp));
|
|
2303
|
+
}
|
|
2304
|
+
writeTo(writer) {
|
|
2305
|
+
writer.append(this.op);
|
|
2306
|
+
writer.appendExp(this.valueExpr);
|
|
2307
|
+
}
|
|
2308
|
+
}
|
|
2309
|
+
UnaryValueExpr.type = ExprType.Unary;
|
|
2310
|
+
export { UnaryValueExpr };
|
|
2311
|
+
/**
|
|
2312
|
+
* Represent constant literal like string, data, time, timestamp, number or null
|
|
2313
|
+
* @alpha
|
|
2314
|
+
*/
|
|
2315
|
+
class LiteralExpr extends ValueExpr {
|
|
2316
|
+
constructor(valueType, rawValue) {
|
|
2317
|
+
super(LiteralExpr.type);
|
|
2318
|
+
this.valueType = valueType;
|
|
2319
|
+
this.rawValue = rawValue;
|
|
2320
|
+
}
|
|
2321
|
+
get children() {
|
|
2322
|
+
return [];
|
|
2323
|
+
}
|
|
2324
|
+
static deserialize(node) {
|
|
2325
|
+
if (node.id !== NativeExpIds.LiteralValue) {
|
|
2326
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.LiteralValue'. ${JSON.stringify(node)}`);
|
|
2327
|
+
}
|
|
2328
|
+
return new LiteralExpr(node.kind, node.value);
|
|
2329
|
+
}
|
|
2330
|
+
writeTo(writer) {
|
|
2331
|
+
if (this.valueType === LiteralValueType.String)
|
|
2332
|
+
writer.appendStringLiteral(this.rawValue);
|
|
2333
|
+
else if (this.valueType === LiteralValueType.Date)
|
|
2334
|
+
writer.appendKeyword("DATE").appendSpace().appendStringLiteral(this.rawValue);
|
|
2335
|
+
else if (this.valueType === LiteralValueType.Time)
|
|
2336
|
+
writer.appendKeyword("TIME").appendSpace().appendStringLiteral(this.rawValue);
|
|
2337
|
+
else if (this.valueType === LiteralValueType.Timestamp)
|
|
2338
|
+
writer.appendKeyword("TIMESTAMP").appendSpace().appendStringLiteral(this.rawValue);
|
|
2339
|
+
else if (this.valueType === LiteralValueType.Null)
|
|
2340
|
+
writer.appendKeyword("NULL");
|
|
2341
|
+
else
|
|
2342
|
+
writer.append(this.rawValue);
|
|
2343
|
+
}
|
|
2344
|
+
static makeRaw(val) { return new LiteralExpr(LiteralValueType.Raw, val); }
|
|
2345
|
+
static makeString(val) { return new LiteralExpr(LiteralValueType.String, val); }
|
|
2346
|
+
static makeNumber(val) { return new LiteralExpr(LiteralValueType.Raw, val.toString()); }
|
|
2347
|
+
static makeDate(val) { return new LiteralExpr(LiteralValueType.Date, val.toDateString()); }
|
|
2348
|
+
static makeTime(val) { return new LiteralExpr(LiteralValueType.String, val.toTimeString()); }
|
|
2349
|
+
static makeTimestamp(val) { return new LiteralExpr(LiteralValueType.String, val.toTimeString()); }
|
|
2350
|
+
static makeNull() { return new LiteralExpr(LiteralValueType.Null, ""); }
|
|
2351
|
+
}
|
|
2352
|
+
LiteralExpr.type = ExprType.Literal;
|
|
2353
|
+
export { LiteralExpr };
|
|
2354
|
+
/**
|
|
2355
|
+
* Represent property name identifier
|
|
2356
|
+
* @alpha
|
|
2357
|
+
*/
|
|
2358
|
+
class PropertyNameExpr extends ValueExpr {
|
|
2359
|
+
constructor(propertyPath) {
|
|
2360
|
+
super(PropertyNameExpr.type);
|
|
2361
|
+
this.propertyPath = propertyPath;
|
|
2362
|
+
}
|
|
2363
|
+
get children() {
|
|
2364
|
+
return [];
|
|
2365
|
+
}
|
|
2366
|
+
static deserialize(node) {
|
|
2367
|
+
if (node.id !== NativeExpIds.PropertyName) {
|
|
2368
|
+
throw new Error(`Parse node is 'node.id !== NativeExpIds.PropertyNameExp'. ${JSON.stringify(node)}`);
|
|
2369
|
+
}
|
|
2370
|
+
return new PropertyNameExpr(node.path);
|
|
2371
|
+
}
|
|
2372
|
+
writeTo(writer) {
|
|
2373
|
+
// donot quote $
|
|
2374
|
+
const str = this.propertyPath.split("->");
|
|
2375
|
+
if (str.length === 2) {
|
|
2376
|
+
writer.append(str[0].split(".").map((v) => v.startsWith("[") || v === "$" ? v : `[${v}]`).join("."));
|
|
2377
|
+
writer.append("->");
|
|
2378
|
+
}
|
|
2379
|
+
writer.append(str[str.length - 1].split(".").map((v) => v.startsWith("[") || v === "$" ? v : `[${v}]`).join("."));
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
PropertyNameExpr.type = ExprType.PropertyName;
|
|
2383
|
+
export { PropertyNameExpr };
|
|
2384
|
+
//# sourceMappingURL=ECSqlAst.js.map
|