sqlparser-devexpress 2.5.0 → 2.5.2

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,6 +1,6 @@
1
1
  {
2
2
  "name": "sqlparser-devexpress",
3
- "version": "2.5.0",
3
+ "version": "2.5.2",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -13,7 +13,7 @@
13
13
  "types": "src/@types/default.d.ts",
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "https://github.com/RohitM-IN/SQLParser.git"
16
+ "url": "git+https://github.com/RohitM-IN/SQLParser.git"
17
17
  },
18
18
  "keywords": [
19
19
  "sql",
@@ -32,4 +32,4 @@
32
32
  "devDependencies": {
33
33
  "vitest": "^3.0.5"
34
34
  }
35
- }
35
+ }
@@ -33,7 +33,10 @@ function DevExpressConverter() {
33
33
  // Handle special cases for short circuit
34
34
  if (result === true || result === false || result === null) return [];
35
35
 
36
- return processAstNode(ast);
36
+ if (result.length == 1) {
37
+ return result[0];
38
+ }
39
+ return result;
37
40
  }
38
41
 
39
42
  /**
@@ -167,67 +170,58 @@ function DevExpressConverter() {
167
170
  let isLeftNullCheck = isFunctionNullCheck(ast.left, true);
168
171
  let isRightNullCheck = isFunctionNullCheck(ast.right, false) || (ast.value && isFunctionNullCheck(ast.value, false));
169
172
  let isBothNullChecks = isLeftNullCheck && isRightNullCheck;
170
-
173
+ let isdestructured = false;
174
+ // Last null because of special case when using dropdown it https://github.com/DevExpress/DevExtreme/blob/25_1/packages/devextreme/js/__internal/data/m_utils.ts#L18 it takes last value.
171
175
  if (!isBothNullChecks && isLeftNullCheck) {
172
176
  const nullCheckArg = (ast.left ?? ast.value).args[1]?.value;
177
+ let valueRight = null
173
178
 
174
179
  let baseComparison = comparison;
175
180
 
176
181
  if (Array.isArray(right) && (right.includes("or") || right.includes("and"))) {
177
- const valueRight = right.shift();
182
+ isdestructured = true;
183
+ valueRight = right.shift();
178
184
  baseComparison = [[left, operatorToken, valueRight], ...right];
179
185
  }
186
+ const _val = !isdestructured ? baseComparison[2] : valueRight;
187
+ if (normalizeBool(_val) == normalizeBool(nullCheckArg))
188
+ comparison = [[...baseComparison], 'or', [left, operatorToken, null, { type: "ISNULL", position: "column", defaultValue: nullCheckArg }, null]];
189
+ else
190
+ comparison = [...baseComparison, { type: "ISNULL", position: "column", defaultValue: nullCheckArg }, _val];
180
191
 
181
- comparison = [[...baseComparison], 'or', [left, operatorToken, null, { type: "ISNULL", position: "column", defaultValue: nullCheckArg }, null]];
182
192
 
183
193
  } else if (!isBothNullChecks && isRightNullCheck) {
184
194
  const nullCheckArg = (ast.right ?? ast.value).args[1]?.value;
185
-
195
+ let valueLeft = null
186
196
  let baseComparison = comparison;
187
197
 
188
198
  if (Array.isArray(left) && (left.includes("or") || left.includes("and"))) {
189
- const valueLeft = left.shift();
199
+ isdestructured = true;
200
+ valueLeft = left.shift();
190
201
  baseComparison = [[valueLeft, operatorToken, right], ...left];
191
202
  }
203
+ const _val = !isdestructured ? baseComparison[2] : valueRight;
192
204
 
193
- comparison = [[...baseComparison], 'or', [left, operatorToken, null, { type: "ISNULL", position: "value", defaultValue: nullCheckArg }, null]];
194
-
205
+ comparison = [...baseComparison, { type: "ISNULL", position: "value", defaultValue: nullCheckArg }, _val];
195
206
  } else if (isBothNullChecks) {
196
207
  const nullCheckArgleft = (ast.left ?? ast.value).args[1]?.value;
197
208
  const nullCheckArgright = (ast.right ?? ast.value).args[1]?.value;
198
-
209
+ let valueLeft = null;
199
210
  let baseComparison = comparison;
200
211
 
201
212
  if (Array.isArray(left) && (left.includes("or") || left.includes("and"))) {
202
- const valueLeft = left.shift();
213
+ isdestructured = true;
214
+ valueLeft = left.shift();
203
215
  baseComparison = [[valueLeft, operatorToken, right], ...left];
204
216
  }
205
217
 
206
- comparison = [[...baseComparison, { type: "ISNULL", position: "both", defaultValue: nullCheckArgleft, defaultValueRight: nullCheckArgright }, baseComparison[2]], 'or', [left, operatorToken, null]];
218
+ const _val = !isdestructured ? baseComparison[2] : valueLeft;
207
219
 
220
+ if (normalizeBool(nullCheckArgleft) == normalizeBool(nullCheckArgright))
221
+ comparison = [[...baseComparison, { type: "ISNULL", position: "both", defaultValue: nullCheckArgleft, defaultValueRight: nullCheckArgright }, _val], 'or', [left, operatorToken, null]];
222
+ else
223
+ comparison = [[...baseComparison, { type: "ISNULL", position: "both", defaultValue: nullCheckArgleft, defaultValueRight: nullCheckArgright }, _val]];
208
224
  }
209
- // Last null because of special case when using dropdown it https://github.com/DevExpress/DevExtreme/blob/25_1/packages/devextreme/js/__internal/data/m_utils.ts#L18 it takes last value as null
210
- // if ((ast.left && isFunctionNullCheck(ast.left, true)) || (ast.value && isFunctionNullCheck(ast.value, false))) {
211
- // const nullCheckArg = (ast.left ?? ast.value).args[1]?.value;
212
- // let baseComparison = comparison;
213
-
214
- // if (Array.isArray(right) && (right.includes("or") || right.includes("and"))) {
215
- // const valueRight = right.shift();
216
- // baseComparison = [[left, operatorToken, valueRight], ...right];
217
- // }
218
-
219
- // comparison = [baseComparison, 'or', [left, operatorToken, null, { type: "ISNULL", defaultValue: nullCheckArg }, null]];
220
- // } else if (ast.right && isFunctionNullCheck(ast.right, true)) {
221
- // const nullCheckArg = ast.right.args[1]?.value;
222
- // let baseComparison = comparison;
223
-
224
- // if (Array.isArray(right) && (right.includes("or") || right.includes("and"))) {
225
- // const valueRight = right.shift();
226
- // baseComparison = [[left, operatorToken, valueRight], ...right];
227
- // }
228
-
229
- // comparison = [baseComparison, 'or', [right, operatorToken, null, { type: "ISNULL", defaultValue: nullCheckArg }, null]];
230
- // }
231
225
 
232
226
  // Apply short-circuit evaluation if enabled
233
227
  if (EnableShortCircuit && IsValueNullShortCircuit && (left == null || right == null)) {
@@ -259,6 +253,20 @@ function DevExpressConverter() {
259
253
  return comparison;
260
254
  }
261
255
 
256
+ /**
257
+ * Normalizes numeric boolean-like values to actual booleans.
258
+ *
259
+ * Converts the number `0` to `false` and `1` to `true`.
260
+ * If the input is not exactly `0` or `1`, it returns the value unchanged.
261
+ *
262
+ * @param {*} value - The value to normalize. Can be of any type.
263
+ * @returns {*} - Returns `false` if `value` is `0`, `true` if `value` is `1`, otherwise returns the original value.
264
+ */
265
+ function normalizeBool(value) {
266
+ return value === 0 || value === 1 ? Boolean(value) : value;
267
+ }
268
+
269
+
262
270
  /**
263
271
  * Handles function calls, focusing on ISNULL.
264
272
  * @param {Object} ast - The function AST node.
@@ -510,13 +518,17 @@ function DevExpressConverter() {
510
518
  return null; // Any comparison with null should return null
511
519
  }
512
520
 
521
+ // Normalize boolean values to numbers for comparison with numbers
522
+ const normalizedLeft = normalizeBool(left);
523
+ const normalizedRight = normalizeBool(right);
524
+
513
525
  switch (operator) {
514
- case '=': case '==': return left === right;
515
- case '<>': case '!=': return left !== right;
516
- case '>': return left > right;
517
- case '>=': return left >= right;
518
- case '<': return left < right;
519
- case '<=': return left <= right;
526
+ case '=': case '==': return normalizedLeft === normalizedRight;
527
+ case '<>': case '!=': return normalizedLeft !== normalizedRight;
528
+ case '>': return normalizedLeft > normalizedRight;
529
+ case '>=': return normalizedLeft >= normalizedRight;
530
+ case '<': return normalizedLeft < normalizedRight;
531
+ case '<=': return normalizedLeft <= normalizedRight;
520
532
  default: return null; // Invalid operator
521
533
  }
522
534
  }
package/src/debug.js CHANGED
@@ -26,7 +26,7 @@
26
26
  // const astTree = parsedResult.ast;
27
27
  // console.log("AST Tree:", JSON.stringify(astTree, null, 2), "\n");
28
28
 
29
- // return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData, isValueNullShortCircuit: true });
29
+ // return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData, options: { isValueNullShortCircuit: true, treatNumberAsNullableBit: true } });
30
30
  // }
31
31
 
32
32
  // const devexpress = parseFilterString("ISNULL(CompanyID,0) = ISNULL({TransferOutwardDocument.CompanyID},0) OR ISNULL(CompanyID,0) = 0", sampleData);
@@ -137,15 +137,15 @@ describe("Parser SQL to dx Filter Builder", () => {
137
137
  {
138
138
  input: "ISNULL(SourceID,0) = {ServiceOrderDocument.SourceID} OR ISNULL(SourceID,0) = 0",
139
139
  expected: [
140
- ["SourceID", "=", 2],
140
+ ["SourceID", "=", 2, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, 2],
141
141
  "or",
142
- ["SourceID", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null],
143
- "or",
144
- ["SourceID", "=", 0],
145
- "or",
146
- ["SourceID", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null],
147
- "or",
148
- ["SourceID", "=", false]
142
+ [
143
+ ["SourceID", "=", 0],
144
+ "or",
145
+ ["SourceID", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null],
146
+ "or",
147
+ ["SourceID", "=", false]
148
+ ]
149
149
  ]
150
150
  },
151
151
  {
@@ -163,11 +163,13 @@ describe("Parser SQL to dx Filter Builder", () => {
163
163
  ]
164
164
  ],
165
165
  "and",
166
- [
167
- ["IsSubdealer", "=", true],
168
- "or",
169
- ["IsSubdealer", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null]
170
- ]
166
+ // [
167
+ // ["IsSubdealer", "=", 0],
168
+ // "or",
169
+ // ["IsSubdealer", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null],
170
+ // "or",
171
+ ["IsSubdealer", "=", true, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, true],
172
+ // ]
171
173
  ]
172
174
  },
173
175
  {
@@ -199,15 +201,15 @@ describe("Parser SQL to dx Filter Builder", () => {
199
201
  {
200
202
  input: "CompanyID = ISNULL({LeadDocument.CompanyID},0) OR (ISNULL(CompanyID,0) = 0))",
201
203
  expected: [
202
- ["CompanyID", "=", 7],
203
- "or",
204
- ["CompanyID", "=", null, { "type": "ISNULL", "position": "value", "defaultValue": 0 }, null],
205
- "or",
206
- ["CompanyID", "=", 0],
207
- "or",
208
- ["CompanyID", "=", null, { "type": "ISNULL", "position": "column", "defaultValue": 0 }, null],
204
+ ["CompanyID", "=", 7, { "type": "ISNULL", "position": "value", "defaultValue": 0 }, 7],
209
205
  "or",
210
- ["CompanyID", "=", false]
206
+ [
207
+ ["CompanyID", "=", 0],
208
+ "or",
209
+ ["CompanyID", "=", null, { "type": "ISNULL", "position": "column", "defaultValue": 0 }, null],
210
+ "or",
211
+ ["CompanyID", "=", false]
212
+ ]
211
213
  ]
212
214
  },
213
215
  {
@@ -317,6 +319,88 @@ describe("Parser SQL to dx Filter Builder", () => {
317
319
  "or",
318
320
  ["CompanyID", "=", false]
319
321
  ]
322
+ },
323
+ {
324
+ input: "ISNULL(CompanyID,0) = ISNULL({TransferOutwardDocument.CompanyID},0) OR (ISNULL(CompanyID,1) = 0)",
325
+ expected: [
326
+ ["CompanyID", "=", 7, { "type": "ISNULL", "position": "both", "defaultValue": 0, "defaultValueRight": 0 }, 7],
327
+ "or",
328
+ ["CompanyID", "=", null],
329
+ "or",
330
+ ["CompanyID", "=", 0, { "type": "ISNULL", "position": "column", "defaultValue": 1 }, 0],
331
+ "or",
332
+ ["CompanyID", "=", false]
333
+ ]
334
+ },
335
+ {
336
+ input: "ISNULL(CompanyID,0) = {LeadDocument.CompanyID}",
337
+ expected: [
338
+ "CompanyID", "=", 7, { "type": "ISNULL", "position": "column", "defaultValue": 0 }, 7
339
+ ]
340
+ },
341
+ {
342
+ input: "ISNULL(CompanyID,0) = ISNULL({LeadDocument.CompanyID},0)",
343
+ expected: [
344
+ ["CompanyID", "=", 7, { "type": "ISNULL", "position": "both", "defaultValue": 0, "defaultValueRight": 0 }, 7],
345
+ "or",
346
+ ["CompanyID", "=", null]
347
+ ]
348
+ },
349
+ {
350
+ input: "ISNULL(CompanyID,1) = ISNULL({LeadDocument.CompanyID},2)",
351
+ expected: [
352
+ "CompanyID", "=", 7, { "type": "ISNULL", "position": "both", "defaultValue": 1, "defaultValueRight": 2 }, 7
353
+ ]
354
+ },
355
+ {
356
+ input: "CompanyID = ISNULL({LeadDocument.CompanyID},0)",
357
+ expected: [
358
+ "CompanyID", "=", 7, { "type": "ISNULL", "position": "value", "defaultValue": 0 }, 7
359
+ ]
360
+ },
361
+ {
362
+ input: "AllowSubDealer = ISNULL({LeadDocument.AllowSubDealer},0)",
363
+ expected: [
364
+ "AllowSubDealer", "=", true, { "type": "ISNULL", "position": "value", "defaultValue": 0 }, true
365
+ ]
366
+ },
367
+ {
368
+ input: "AllowSubDealer = ISNULL({LeadDocument.AllowSubDealer},1)",
369
+ expected: [
370
+ "AllowSubDealer", "=", true, { "type": "ISNULL", "position": "value", "defaultValue": 1 }, true
371
+ ]
372
+ },
373
+ {
374
+ input: "ISNULL(AllowSubDealer,0) = ISNULL({LeadDocument.AllowSubDealer},1)",
375
+ expected: [
376
+ "AllowSubDealer", "=", true, { "type": "ISNULL", "position": "both", "defaultValue": 0, "defaultValueRight": 1 }, true
377
+ ]
378
+ },
379
+ {
380
+ input: "ISNULL(AllowSubDealer,0) = {LeadDocument.AllowSubDealer}",
381
+ expected: [
382
+ "AllowSubDealer", "=", true, { "type": "ISNULL", "position": "column", "defaultValue": 0 }, true
383
+ ]
384
+ },
385
+ {
386
+ input: "ISNULL(AllowSubDealer,1) = {LeadDocument.AllowSubDealer}",
387
+ expected: [
388
+ ["AllowSubDealer", "=", true],
389
+ 'or',
390
+ ["AllowSubDealer", "=", null, { "type": "ISNULL", "position": "column", "defaultValue": 1 }, null]
391
+ ],
392
+ },
393
+ {
394
+ input: "(CompanyID = {LeadDocument.CompanyID} OR CompanyID IS NULL) AND ItemGroupType IN ({Item.AllowedItemGroupTypeOne}) AND ({PurchaseOrderDocument.IsMultiBrand} = 0 OR ({PurchaseOrderDocument.IsMultiBrand} = 1 AND Make IN ({PurchaseOrderDocument.AllowedApplicableMake})))",
395
+ expected: [
396
+ [
397
+ ["CompanyID", "=", 7],
398
+ "or",
399
+ ["CompanyID", "=", null, { "type": "IS" }, null]
400
+ ],
401
+ "and",
402
+ ["ItemGroupType", "=", "1"]
403
+ ]
320
404
  }
321
405
  ];
322
406
 
@@ -356,6 +440,7 @@ describe("Parser SQL to dx Filter Builder", () => {
356
440
 
357
441
 
358
442
  const sampleData = {
443
+ "Example.ZeroValue": 0,
359
444
  "CoreEntity0022.CompanyGroupID": 42,
360
445
  "CoreEntity0022.BranchID": 7,
361
446
  "Employee.District": 0,
@@ -369,6 +454,7 @@ const sampleData = {
369
454
  "Item.ID": 42,
370
455
  "Item.BranchID": 7,
371
456
  "Item.AllowedItemGroupType": "1,2",
457
+ "Item.AllowedItemGroupTypeOne": "1",
372
458
  "WorkOrderLine.ApplicableUoms": ["UOM1", "UOM2", "UOM3"],
373
459
  "WorkOrderLine.CompanyID": 2,
374
460
  "WorkOrderDocument.CompanyID": 42,
@@ -384,4 +470,6 @@ const sampleData = {
384
470
  "SaleOrderStatusStmtGlobalRpt.StateID": null,
385
471
  "SaleOrderStatusStmtGlobalRpt.RegionID": null,
386
472
  "WorkOrderLine.CompanyIDs": ["0,1"],
473
+ "PurchaseOrderDocument.IsMultiBrand": false,
474
+ "PurchaseOrderDocument.AllowedApplicableMake": "0"
387
475
  };