sqlparser-devexpress 2.3.18 → 2.4.0

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.3.18",
3
+ "version": "2.4.0",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -9,8 +9,11 @@ export type DevExpressFilter = any[] | null;
9
9
  export interface ConvertOptions {
10
10
  ast: ASTNode;
11
11
  resultObject?: ResultObject;
12
- enableShortCircuit?: boolean;
13
- isValueNullShortCircuit?: boolean;
12
+ options?: {
13
+ enableShortCircuit?: boolean;
14
+ isValueNullShortCircuit?: boolean;
15
+ treatNumberAsNullableBit?: boolean;
16
+ };
14
17
  }
15
18
 
16
19
  /**
@@ -38,6 +38,9 @@ export function convertSQLToAst(filterString: string, enableConsoleLogs?: boolea
38
38
  export function convertAstToDevextreme(
39
39
  ast: ASTNode,
40
40
  state?: ResultObject | null,
41
- enableShortCircuit?: boolean,
42
- isValueNullShortCircuit?: boolean
41
+ options?: {
42
+ enableShortCircuit?: boolean;
43
+ isValueNullShortCircuit?: boolean;
44
+ treatNumberAsNullableBit?: boolean;
45
+ }
43
46
  ): DevExpressFilter;
@@ -9,19 +9,23 @@ function DevExpressConverter() {
9
9
  let resultObject = null;
10
10
  let EnableShortCircuit = true;
11
11
  let IsValueNullShortCircuit = false; // Flag to enable/disable null short-circuiting
12
+ let TreatNumberAsNullableBit = false; // Flag to enable/disable optional boolean with number conversion
12
13
 
13
14
  /**
14
15
  * Main conversion function that sets up the global context
15
16
  * @param {Object} ast - The abstract syntax tree
16
17
  * @param {Object} ResultObject - Optional object for placeholder resolution
17
18
  * @param {boolean} enableShortCircuit - Optional enabling and disabling the shortcircuit ie evaluating value = value scenario
19
+ * @param {boolean} isValueNullShortCircuit - Optional enabling and disabling the null shortcircuit ie evaluating value = null scenario
20
+ * @param {boolean} treatNumberAsNullableBit - Optional enabling and disabling the optional boolean with number conversion
18
21
  * @returns {Array|null} DevExpress format filter
19
22
  */
20
- function convert(ast, ResultObject = null, enableShortCircuit = true, isValueNullShortCircuit = false) {
23
+ function convert(ast, ResultObject = null, enableShortCircuit = true, isValueNullShortCircuit = false, treatNumberAsNullableBit = false) {
21
24
  // Set up global context
22
25
  resultObject = ResultObject;
23
26
  EnableShortCircuit = enableShortCircuit;
24
27
  IsValueNullShortCircuit = isValueNullShortCircuit;
28
+ TreatNumberAsNullableBit = treatNumberAsNullableBit;
25
29
 
26
30
  // Process the AST
27
31
  let result = processAstNode(ast);
@@ -176,6 +180,23 @@ function DevExpressConverter() {
176
180
  if (isAlwaysFalse(comparison, leftDefault, rightDefault)) return false;
177
181
  }
178
182
 
183
+ if (TreatNumberAsNullableBit && typeof right === "number" && (right == 0 || right == 1)) {
184
+
185
+ if (Array.isArray(comparison[0])) {
186
+ return [
187
+ ...comparison,
188
+ 'or',
189
+ [left, operatorToken, right == true]
190
+ ];
191
+ }
192
+
193
+ return [
194
+ [...comparison],
195
+ 'or',
196
+ [left, operatorToken, right == true]
197
+ ];
198
+ }
199
+
179
200
  return comparison;
180
201
  }
181
202
 
@@ -452,10 +473,13 @@ const devExpressConverter = DevExpressConverter();
452
473
  * Converts an abstract syntax tree to DevExpress format
453
474
  * @param {Object} ast - The abstract syntax tree
454
475
  * @param {Object} resultObject - Optional object for placeholder resolution
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
476
+ * @param {Object} options - Optional options for conversion
477
+ * @param {boolean} options.enableShortCircuit - Enable or disable short-circuit evaluation
478
+ * @param {boolean} options.isValueNullShortCircuit - Enable or disable null short-circuit evaluation
479
+ * @param {boolean} options.treatNumberAsNullableBit - Enable or disable optional boolean with number conversion
457
480
  * @returns {Array|null} DevExpress format filter
458
481
  */
459
- export function convertToDevExpressFormat({ ast, resultObject = null, enableShortCircuit = true, isValueNullShortCircuit = false }) {
460
- return devExpressConverter.init(ast, resultObject, enableShortCircuit, isValueNullShortCircuit);
482
+ export function convertToDevExpressFormat({ ast, resultObject = null, options = {} }) {
483
+ const { enableShortCircuit = true, isValueNullShortCircuit = false, treatNumberAsNullableBit = false } = options;
484
+ return devExpressConverter.init(ast, resultObject, enableShortCircuit, isValueNullShortCircuit, treatNumberAsNullableBit);
461
485
  }
@@ -142,15 +142,12 @@ export function parse(input, variables = []) {
142
142
  left = { type: "logical", operator, left, right };
143
143
  } else if (currentToken?.type == "identifier") {
144
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 = '>=';
145
+ let newOperator = inverseOperator(operator);
146
+
150
147
  left = {
151
148
  type: "comparison",
152
149
  right: left,
153
- operator: newOp,
150
+ operator: newOperator,
154
151
  left: { type: "field", value: right }
155
152
  };
156
153
  }
@@ -233,7 +230,8 @@ export function parse(input, variables = []) {
233
230
 
234
231
  // Swap the field and value if the field is a placeholder and the value is an identifier
235
232
  if (valueType == "identifier" && fieldType == "placeholder") {
236
- return { type: "comparison", value: field, operator, field: value, originalOperator };
233
+ let newOperator = inverseOperator(operator);
234
+ return { type: "comparison", value: field, operator: newOperator, field: value, originalOperator };
237
235
  }
238
236
 
239
237
  return { type: "comparison", field, operator, value, originalOperator };
@@ -242,6 +240,16 @@ export function parse(input, variables = []) {
242
240
  return { type: "field", value: field };
243
241
  }
244
242
 
243
+ function inverseOperator(operator) {
244
+ switch (operator.toUpperCase()) {
245
+ case ">": return "<";
246
+ case "<": return ">";
247
+ case ">=": return "<=";
248
+ case "<=": return ">=";
249
+ default: return operator; // Return the operator as is if no inverse is defined
250
+ }
251
+ }
252
+
245
253
  // Parses values including numbers, strings, placeholders, and IN lists
246
254
  function parseValue(operatorToken) {
247
255
  if (!currentToken) throw new Error("Unexpected end of input");
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, isValueNullShortCircuit = false) {
20
- return convertToDevExpressFormat({ ast, resultObject: state, enableShortCircuit, isValueNullShortCircuit })
19
+ export function convertAstToDevextreme(ast, state = null, options = {}) {
20
+ return convertToDevExpressFormat({ ast, resultObject: state, options })
21
21
  }
22
22
 
23
23
 
@@ -1,7 +1,4 @@
1
1
  import { describe, expect, it } from "vitest";
2
- import { convertToDevExpressFormat } from "../src/core/converter";
3
- import { parse } from "../src/core/parser";
4
- import { sanitizeQuery } from "../src/core/sanitizer";
5
2
  import { convertAstToDevextreme, convertSQLToAst } from "../src";
6
3
 
7
4
  describe("Parser SQL to dx Filter Builder", () => {
@@ -141,7 +141,9 @@ describe("Parser SQL to dx Filter Builder", () => {
141
141
  "or",
142
142
  ["SourceID", "=", 0],
143
143
  "or",
144
- ["SourceID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null]
144
+ ["SourceID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null],
145
+ "or",
146
+ ["SourceID", "=", false]
145
147
  ]
146
148
  },
147
149
  {
@@ -153,7 +155,9 @@ describe("Parser SQL to dx Filter Builder", () => {
153
155
  [
154
156
  ["CompanyID", "=", 0],
155
157
  "or",
156
- ["CompanyID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null]
158
+ ["CompanyID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null],
159
+ "or",
160
+ ["CompanyID", "=", false]
157
161
  ]
158
162
  ],
159
163
  "and",
@@ -199,7 +203,9 @@ describe("Parser SQL to dx Filter Builder", () => {
199
203
  "or",
200
204
  ["CompanyID", "=", 0],
201
205
  "or",
202
- ["CompanyID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null]
206
+ ["CompanyID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null],
207
+ "or",
208
+ ["CompanyID", "=", false]
203
209
 
204
210
  ]
205
211
  },
@@ -288,6 +294,14 @@ describe("Parser SQL to dx Filter Builder", () => {
288
294
  expected: [
289
295
  "ID", "=", 2
290
296
  ]
297
+ },
298
+ {
299
+ input: "IsChecked = 1",
300
+ expected: [
301
+ ["IsChecked", "=", 1],
302
+ "or",
303
+ ["IsChecked", "=", true]
304
+ ]
291
305
  }
292
306
  ];
293
307
 
@@ -310,7 +324,10 @@ describe("Parser SQL to dx Filter Builder", () => {
310
324
  const variables = astwithVariables.variables;
311
325
  const ast = astwithVariables.ast;
312
326
 
313
- const result = convertAstToDevextreme(ast, sampleData, true, true);
327
+ const result = convertAstToDevextreme(ast, sampleData, {
328
+ isValueNullShortCircuit: true,
329
+ treatNumberAsNullableBit: true
330
+ });
314
331
 
315
332
  if (result == null || result == true || result == false) {
316
333
  expect([]).toEqual(expected);