sqlparser-devexpress 2.3.1 → 2.3.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.3.1",
3
+ "version": "2.3.2",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -248,7 +248,7 @@ function DevExpressConverter() {
248
248
  if (!resultObject) return `{${placeholder}}`;
249
249
 
250
250
 
251
- return resultObject.hasOwnProperty(placeholder) ? resultObject[placeholder] : `{${placeholder}}`;
251
+ return resultObject.hasOwnProperty(placeholder) ? resultObject[placeholder] : `{${placeholder.value ?? placeholder}}`;
252
252
  }
253
253
 
254
254
  /**
@@ -184,6 +184,8 @@ export function parse(input, variables = []) {
184
184
  function parseValue(operatorToken) {
185
185
  if (!currentToken) throw new Error("Unexpected end of input");
186
186
 
187
+ if(currentToken.type === "function") return parseFunction();
188
+
187
189
  const token = currentToken;
188
190
  next(); // Move to the next token
189
191
 
@@ -199,11 +201,18 @@ export function parse(input, variables = []) {
199
201
  return { type: "placeholder", value: val };
200
202
  }
201
203
 
202
- operatorToken = operatorToken.toUpperCase();
204
+ operatorToken = operatorToken?.toUpperCase();
203
205
 
204
206
  // Handle IN operator which requires a list of values
205
207
  if (operatorToken && (operatorToken === "IN" || operatorToken === "NOT IN")) return parseInList(token);
206
208
 
209
+ // Handle ({Placeholder}) syntax for placeholders inside parentheses
210
+ const nextToken = tokenizer.peekNextToken();
211
+ if(token.type === "paren" && currentToken && currentToken.type === "placeholder" && nextToken && nextToken.type === "paren") {
212
+ const val = parseValue();
213
+ return { type: "placeholder", value: val };
214
+ }
215
+
207
216
  throw new Error(`Unexpected value: ${token.value}`);
208
217
  }
209
218
 
package/src/debug.js CHANGED
@@ -28,7 +28,7 @@
28
28
  // return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData });
29
29
  // }
30
30
 
31
- // const devexpress = parseFilterString("AddressType IN ('2', ('4')) OR AddressType =({ServiceOrderDocument .SourceID})", sampleData);
31
+ // const devexpress = parseFilterString("(ISNULL(TicketID, 0) = ISNULL({CustomerOrders.OrderID}, 0))", sampleData);
32
32
  // console.log("DevExpress Filter:", JSON.stringify(devexpress, null, 2));
33
33
  // // const devexpress = parseFilterString("(RS2ID in ({LeadStatementGlobalRpt.StateID}) Or ({LeadStatementGlobalRpt.StateID} =0)) And (RS3ID in (0,{LeadStatementGlobalRpt.RegionID}) Or {LeadStatementGlobalRpt.RegionID} =0 )", sampleData);
34
34
 
@@ -0,0 +1,66 @@
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
+ import { convertAstToDevextreme, convertSQLToAst } from "../src";
6
+
7
+ describe("Parser SQL to dx Filter Builder", () => {
8
+ const testCases = [
9
+ {
10
+ input: "NULL",
11
+ expected: []
12
+ },
13
+ {
14
+ input: "SELECT DISTINCT O.OrderID AS ID, O.CustomerName, O.OrderType, O.CustomerName AS [Online Order], O.OrderDate AS OrderDate, D.DeliveryStatus, O.OrderDate AS [Online Order Date], O.CompanyID, CAST(CAST(O.OrderDate AS DATE) AS VARCHAR(10)) AS DocumentDate FROM Orders O INNER JOIN Payment P ON P.OrderID = O.OrderID INNER JOIN Shipment S ON S.PaymentID = P.PaymentID INNER JOIN Delivery D ON D.ShipmentID = S.ShipmentID ",
15
+ expect: null
16
+ },
17
+ {
18
+ input: "CompanyID = CompanyID2 = {AccountingRule.CompanyID}",
19
+ expected: "Error: Invalid comparison: CompanyID = CompanyID2",
20
+ },
21
+ {
22
+ input: "( CompanyID = {AccountingRule.CompanyID}",
23
+ expected: "Error: Missing closing parenthesis"
24
+ }
25
+
26
+ ];
27
+
28
+ testCases.forEach(({ input, expected }, index) => {
29
+ it(`Test Case ${index + 1}: ${input}`, () => {
30
+
31
+ if (expected == undefined) {
32
+ expected = null
33
+ }
34
+
35
+ let astwithVariables;
36
+ try {
37
+ astwithVariables = convertSQLToAst(input);
38
+ } catch (error) {
39
+ expect(error.message).toEqual(expected.replace("Error: ", ""));
40
+ return;
41
+ }
42
+
43
+ if (astwithVariables == null) {
44
+ expect(null).toEqual(expected);
45
+ return;
46
+ }
47
+
48
+ const variables = astwithVariables.variables;
49
+ const ast = astwithVariables.ast;
50
+
51
+ const result = convertAstToDevextreme(ast, sampleData);
52
+
53
+ if (result == null || result == true || result == false) {
54
+ expect([]).toEqual(expected);
55
+ return;
56
+ }
57
+
58
+ expect(result).toEqual(expected);
59
+ });
60
+ });
61
+ });
62
+
63
+
64
+ const sampleData = {
65
+ "AccountingRule.CompanyID": 42,
66
+ };
@@ -102,10 +102,6 @@ describe("Parser SQL to dx Filter Builder", () => {
102
102
  ["ItemGroupType", "=", ""]
103
103
  ]
104
104
  },
105
- {
106
- input: "NULL",
107
- expected: []
108
- },
109
105
  {
110
106
  input: "((ISNULL({0}, 0) = 0 AND CompanyID = {1}) OR CompanyID IS NULL) OR BranchID = {0} | [LeadDocument.BranchID] | [LeadDocument.CompanyID]",
111
107
  expected: [
@@ -122,10 +118,6 @@ describe("Parser SQL to dx Filter Builder", () => {
122
118
  ["BranchID", "=", 42]
123
119
  ]
124
120
  },
125
- {
126
- input: "SELECT DISTINCT OP.DocID ID,OP.DocName,OP.DocType,OP.DocName [Work Purchase Order],OP.DocDate DocDate,SP.WoStatus,OP.DocDate [Work Purchase Order Date], OP.CompanyID, cast(cast(OP.DocDate as date) as varchar(10)) DocumentDate FROM OpenDocuments OP inner join PurchaseHeader PH on PH.Id=op.DocID inner JOIN PurchasePosting PP ON PP.DocID = PH.ID inner JOIN SalePosting SP ON SP.PurchasePostingLineID = PP.ID",
127
- expect: null
128
- },
129
121
  {
130
122
  input: "FromDate Between '10-10-2021' AND '10-10-2022'",
131
123
  expected: [
@@ -152,10 +144,6 @@ describe("Parser SQL to dx Filter Builder", () => {
152
144
  ["SourceID", "=", null]
153
145
  ]
154
146
  },
155
- {
156
- input: "CompanyID = CompanyID2 = {AccountingRule.CompanyID}",
157
- expected: "Error: Invalid comparison: CompanyID = CompanyID2",
158
- },
159
147
  {
160
148
  input: "(CompanyID = {LeadDocument.CompanyID} OR ISNULL(CompanyID,0) = 0) AND (ISNULL(IsSubdealer,0) = {LeadDocument.AllowSubDealer})",
161
149
  expected: [
@@ -193,6 +181,14 @@ describe("Parser SQL to dx Filter Builder", () => {
193
181
  "or",
194
182
  ["AddressType", "=", 2]
195
183
  ]
184
+ },
185
+ {
186
+ input: "(ISNULL(TicketID, 0) = ISNULL({SupportResolution.TicketID}, 0))",
187
+ expected: [
188
+ ["TicketID", "=", 123],
189
+ "or",
190
+ ["TicketID", "=", null]
191
+ ]
196
192
  }
197
193
  ];
198
194
 
@@ -204,12 +200,8 @@ describe("Parser SQL to dx Filter Builder", () => {
204
200
  }
205
201
 
206
202
  let astwithVariables;
207
- try {
208
- astwithVariables = convertSQLToAst(input);
209
- } catch (error) {
210
- expect(error.message).toEqual(expected.replace("Error: ", ""));
211
- return;
212
- }
203
+ astwithVariables = convertSQLToAst(input);
204
+
213
205
 
214
206
  if (astwithVariables == null) {
215
207
  expect(null).toEqual(expected);
@@ -256,5 +248,6 @@ const sampleData = {
256
248
  "LeadDocument.BranchID": 42,
257
249
  "LeadDocument.CompanyID": 7,
258
250
  "ServiceOrderDocument.SourceID": 2,
259
- "LeadDocument.AllowSubDealer": true
251
+ "LeadDocument.AllowSubDealer": true,
252
+ "SupportResolution.TicketID": 123
260
253
  };