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 CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "sqlparser-devexpress",
3
- "version": "2.3.16",
3
+ "version": "2.3.18",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "test": "vitest"
7
+ "test": "vitest run"
8
8
  },
9
9
  "exports": {
10
10
  "import": "./src/index.js",
@@ -10,6 +10,7 @@ export interface ConvertOptions {
10
10
  ast: ASTNode;
11
11
  resultObject?: ResultObject;
12
12
  enableShortCircuit?: boolean;
13
+ isValueNullShortCircuit?: boolean;
13
14
  }
14
15
 
15
16
  /**
@@ -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;
@@ -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
  }
@@ -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
 
@@ -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);