sqlparser-devexpress 2.3.16 → 2.3.18
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/package.json +2 -2
- package/src/@types/core/converter.d.ts +1 -0
- package/src/@types/default.d.ts +2 -0
- package/src/core/converter.js +17 -6
- package/src/core/parser.js +18 -0
- package/src/debug.js +1 -1
- package/src/index.js +2 -2
- package/tests/parser.test.js +29 -1
package/package.json
CHANGED
package/src/@types/default.d.ts
CHANGED
|
@@ -32,10 +32,12 @@ export function convertSQLToAst(filterString: string, enableConsoleLogs?: boolea
|
|
|
32
32
|
* @param ast - The parsed AST from `convertSQLToAst`.
|
|
33
33
|
* @param state - An optional result object to resolve placeholders to actual values.
|
|
34
34
|
* @param enableShortCircuit - Whether to apply short-circuit evaluation.
|
|
35
|
+
* @param isValueNullShortCircuit - Whether to treat null values as short-circuit conditions.
|
|
35
36
|
* @returns DevExpressFilter - The DevExpress-compatible filter array or null.
|
|
36
37
|
*/
|
|
37
38
|
export function convertAstToDevextreme(
|
|
38
39
|
ast: ASTNode,
|
|
39
40
|
state?: ResultObject | null,
|
|
40
41
|
enableShortCircuit?: boolean,
|
|
42
|
+
isValueNullShortCircuit?: boolean
|
|
41
43
|
): DevExpressFilter;
|
package/src/core/converter.js
CHANGED
|
@@ -8,6 +8,7 @@ function DevExpressConverter() {
|
|
|
8
8
|
// Global variables accessible throughout the converter
|
|
9
9
|
let resultObject = null;
|
|
10
10
|
let EnableShortCircuit = true;
|
|
11
|
+
let IsValueNullShortCircuit = false; // Flag to enable/disable null short-circuiting
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Main conversion function that sets up the global context
|
|
@@ -16,10 +17,11 @@ function DevExpressConverter() {
|
|
|
16
17
|
* @param {boolean} enableShortCircuit - Optional enabling and disabling the shortcircuit ie evaluating value = value scenario
|
|
17
18
|
* @returns {Array|null} DevExpress format filter
|
|
18
19
|
*/
|
|
19
|
-
function convert(ast, ResultObject = null, enableShortCircuit = true) {
|
|
20
|
+
function convert(ast, ResultObject = null, enableShortCircuit = true, isValueNullShortCircuit = false) {
|
|
20
21
|
// Set up global context
|
|
21
22
|
resultObject = ResultObject;
|
|
22
23
|
EnableShortCircuit = enableShortCircuit;
|
|
24
|
+
IsValueNullShortCircuit = isValueNullShortCircuit;
|
|
23
25
|
|
|
24
26
|
// Process the AST
|
|
25
27
|
let result = processAstNode(ast);
|
|
@@ -89,6 +91,7 @@ function DevExpressConverter() {
|
|
|
89
91
|
const left = processAstNode(ast.left, operator);
|
|
90
92
|
const right = processAstNode(ast.right, operator);
|
|
91
93
|
|
|
94
|
+
|
|
92
95
|
if (EnableShortCircuit) {
|
|
93
96
|
// Short-circuit: always-true conditions
|
|
94
97
|
if (left === true || right === true) {
|
|
@@ -100,7 +103,6 @@ function DevExpressConverter() {
|
|
|
100
103
|
if (left === false || right === false) {
|
|
101
104
|
return left === false ? right : left;
|
|
102
105
|
}
|
|
103
|
-
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
// Detect and flatten nested logical expressions
|
|
@@ -137,9 +139,9 @@ function DevExpressConverter() {
|
|
|
137
139
|
}
|
|
138
140
|
|
|
139
141
|
const left = ast.left !== undefined ? processAstNode(ast.left) : convertValue(ast.field);
|
|
140
|
-
const leftDefault = ast.left?.args[1]?.value;
|
|
142
|
+
const leftDefault = ast.left?.args && ast.left?.args[1]?.value;
|
|
141
143
|
const right = ast.right !== undefined ? processAstNode(ast.right) : convertValue(ast.value);
|
|
142
|
-
const rightDefault = ast.right?.args[1]?.value;
|
|
144
|
+
const rightDefault = ast.right?.args && ast.right?.args[1]?.value;
|
|
143
145
|
let operatorToken = ast.operator.toLowerCase();
|
|
144
146
|
let includeExtradata = false;
|
|
145
147
|
|
|
@@ -165,6 +167,10 @@ function DevExpressConverter() {
|
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
// Apply short-circuit evaluation if enabled
|
|
170
|
+
if (EnableShortCircuit && IsValueNullShortCircuit && (left == null || right == null)) {
|
|
171
|
+
return true; // If either value is null, return true for short-circuit evaluation
|
|
172
|
+
}
|
|
173
|
+
|
|
168
174
|
if (EnableShortCircuit) {
|
|
169
175
|
if (isAlwaysTrue(comparison, leftDefault, rightDefault)) return true;
|
|
170
176
|
if (isAlwaysFalse(comparison, leftDefault, rightDefault)) return false;
|
|
@@ -242,6 +248,10 @@ function DevExpressConverter() {
|
|
|
242
248
|
}
|
|
243
249
|
}
|
|
244
250
|
|
|
251
|
+
if (EnableShortCircuit && IsValueNullShortCircuit && (ast.field?.type === "placeholder" || ast.value?.type === "placeholder" || ast.value === null) && resolvedValue === null) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
|
|
245
255
|
let operatorToken = operator === "IN" ? '=' : operator === "NOT IN" ? '!=' : operator;
|
|
246
256
|
let joinOperatorToken = operator === "IN" ? 'or' : operator === "NOT IN" ? 'and' : operator;
|
|
247
257
|
let field = convertValue(ast.field);
|
|
@@ -443,8 +453,9 @@ const devExpressConverter = DevExpressConverter();
|
|
|
443
453
|
* @param {Object} ast - The abstract syntax tree
|
|
444
454
|
* @param {Object} resultObject - Optional object for placeholder resolution
|
|
445
455
|
* @param {string} enableShortCircuit - Optional enabling and disabling the shortcircuit ie evaluating value = value scenario
|
|
456
|
+
* @param {boolean} isValueNullShortCircuit - Optional enabling and disabling the null shortcircuit ie evaluating value = null scenario
|
|
446
457
|
* @returns {Array|null} DevExpress format filter
|
|
447
458
|
*/
|
|
448
|
-
export function convertToDevExpressFormat({ ast, resultObject = null, enableShortCircuit = true }) {
|
|
449
|
-
return devExpressConverter.init(ast, resultObject, enableShortCircuit);
|
|
459
|
+
export function convertToDevExpressFormat({ ast, resultObject = null, enableShortCircuit = true, isValueNullShortCircuit = false }) {
|
|
460
|
+
return devExpressConverter.init(ast, resultObject, enableShortCircuit, isValueNullShortCircuit);
|
|
450
461
|
}
|
package/src/core/parser.js
CHANGED
|
@@ -140,6 +140,19 @@ export function parse(input, variables = []) {
|
|
|
140
140
|
// Recursively parse the right-hand expression with adjusted precedence
|
|
141
141
|
const right = parseExpression(OPERATOR_PRECEDENCE[operator]);
|
|
142
142
|
left = { type: "logical", operator, left, right };
|
|
143
|
+
} else if (currentToken?.type == "identifier") {
|
|
144
|
+
const right = parseValue(operator);
|
|
145
|
+
let newOp = operator;
|
|
146
|
+
if (operator === '>') newOp = '<';
|
|
147
|
+
else if (operator === '<') newOp = '>';
|
|
148
|
+
else if (operator === '>=') newOp = '<=';
|
|
149
|
+
else if (operator === '<=') newOp = '>=';
|
|
150
|
+
left = {
|
|
151
|
+
type: "comparison",
|
|
152
|
+
right: left,
|
|
153
|
+
operator: newOp,
|
|
154
|
+
left: { type: "field", value: right }
|
|
155
|
+
};
|
|
143
156
|
}
|
|
144
157
|
}
|
|
145
158
|
|
|
@@ -218,6 +231,11 @@ export function parse(input, variables = []) {
|
|
|
218
231
|
throw new Error(`Invalid comparison: ${field} ${operator} ${value}`);
|
|
219
232
|
}
|
|
220
233
|
|
|
234
|
+
// Swap the field and value if the field is a placeholder and the value is an identifier
|
|
235
|
+
if (valueType == "identifier" && fieldType == "placeholder") {
|
|
236
|
+
return { type: "comparison", value: field, operator, field: value, originalOperator };
|
|
237
|
+
}
|
|
238
|
+
|
|
221
239
|
return { type: "comparison", field, operator, value, originalOperator };
|
|
222
240
|
}
|
|
223
241
|
|
package/src/debug.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
// const astTree = parsedResult.ast;
|
|
26
26
|
// console.log("AST Tree:", JSON.stringify(astTree, null, 2), "\n");
|
|
27
27
|
|
|
28
|
-
// return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData });
|
|
28
|
+
// return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData, isValueNullShortCircuit: true });
|
|
29
29
|
// }
|
|
30
30
|
|
|
31
31
|
// const devexpress = parseFilterString("(ISNULL(TicketID, 0) = ISNULL({CustomerOrders.OrderID}, 0))", sampleData);
|
package/src/index.js
CHANGED
|
@@ -16,8 +16,8 @@ export function convertSQLToAst(filterString, enableConsoleLogs = false) {
|
|
|
16
16
|
return parsedResult;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export function convertAstToDevextreme(ast, state = null, enableShortCircuit = true) {
|
|
20
|
-
return convertToDevExpressFormat({ ast, resultObject: state, enableShortCircuit })
|
|
19
|
+
export function convertAstToDevextreme(ast, state = null, enableShortCircuit = true, isValueNullShortCircuit = false) {
|
|
20
|
+
return convertToDevExpressFormat({ ast, resultObject: state, enableShortCircuit, isValueNullShortCircuit })
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
|
package/tests/parser.test.js
CHANGED
|
@@ -260,6 +260,34 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
260
260
|
{
|
|
261
261
|
input: "{LeadDocument.AllowSubDealer} != null",
|
|
262
262
|
expected: []
|
|
263
|
+
},
|
|
264
|
+
{
|
|
265
|
+
input: "ID = {SaleOrderStatusStmtGlobalRpt.RegionID}",
|
|
266
|
+
expected: []
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
input: "ID IN ({SaleOrderStatusStmtGlobalRpt.RegionID})",
|
|
270
|
+
expected: []
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
input: "10 < ID AND ApplicableUoms IN ({WorkOrderLine.ApplicableUoms})",
|
|
274
|
+
expected: [
|
|
275
|
+
["ID", ">", 10],
|
|
276
|
+
"and",
|
|
277
|
+
[
|
|
278
|
+
["ApplicableUoms", "=", "UOM1"],
|
|
279
|
+
"or",
|
|
280
|
+
["ApplicableUoms", "=", "UOM2"],
|
|
281
|
+
"or",
|
|
282
|
+
["ApplicableUoms", "=", "UOM3"]
|
|
283
|
+
]
|
|
284
|
+
],
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
input: "{ServiceOrderDocument.SourceID} = ID",
|
|
288
|
+
expected: [
|
|
289
|
+
"ID", "=", 2
|
|
290
|
+
]
|
|
263
291
|
}
|
|
264
292
|
];
|
|
265
293
|
|
|
@@ -282,7 +310,7 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
282
310
|
const variables = astwithVariables.variables;
|
|
283
311
|
const ast = astwithVariables.ast;
|
|
284
312
|
|
|
285
|
-
const result = convertAstToDevextreme(ast, sampleData);
|
|
313
|
+
const result = convertAstToDevextreme(ast, sampleData, true, true);
|
|
286
314
|
|
|
287
315
|
if (result == null || result == true || result == false) {
|
|
288
316
|
expect([]).toEqual(expected);
|