sqlparser-devexpress 2.4.2 → 2.5.1
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 +1 -1
- package/src/core/converter.js +61 -11
- package/src/core/parser.js +45 -6
- package/src/debug.js +4 -3
- package/tests/parser.test.js +117 -60
package/package.json
CHANGED
package/src/core/converter.js
CHANGED
|
@@ -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
|
-
|
|
36
|
+
if (result.length == 1) {
|
|
37
|
+
return result[0];
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/**
|
|
@@ -164,27 +167,60 @@ function DevExpressConverter() {
|
|
|
164
167
|
if (includeExtradata)
|
|
165
168
|
comparison = [left, operatorToken, right, { type: originalOperator }, right];
|
|
166
169
|
|
|
167
|
-
|
|
168
|
-
|
|
170
|
+
let isLeftNullCheck = isFunctionNullCheck(ast.left, true);
|
|
171
|
+
let isRightNullCheck = isFunctionNullCheck(ast.right, false) || (ast.value && isFunctionNullCheck(ast.value, false));
|
|
172
|
+
let isBothNullChecks = isLeftNullCheck && isRightNullCheck;
|
|
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.
|
|
175
|
+
if (!isBothNullChecks && isLeftNullCheck) {
|
|
169
176
|
const nullCheckArg = (ast.left ?? ast.value).args[1]?.value;
|
|
177
|
+
let valueRight = null
|
|
178
|
+
|
|
170
179
|
let baseComparison = comparison;
|
|
171
180
|
|
|
172
181
|
if (Array.isArray(right) && (right.includes("or") || right.includes("and"))) {
|
|
173
|
-
|
|
182
|
+
isdestructured = true;
|
|
183
|
+
valueRight = right.shift();
|
|
174
184
|
baseComparison = [[left, operatorToken, valueRight], ...right];
|
|
175
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];
|
|
176
191
|
|
|
177
|
-
|
|
178
|
-
} else if (
|
|
179
|
-
const nullCheckArg = ast.right.args[1]?.value;
|
|
192
|
+
|
|
193
|
+
} else if (!isBothNullChecks && isRightNullCheck) {
|
|
194
|
+
const nullCheckArg = (ast.right ?? ast.value).args[1]?.value;
|
|
195
|
+
let valueLeft = null
|
|
180
196
|
let baseComparison = comparison;
|
|
181
197
|
|
|
182
|
-
if (Array.isArray(
|
|
183
|
-
|
|
184
|
-
|
|
198
|
+
if (Array.isArray(left) && (left.includes("or") || left.includes("and"))) {
|
|
199
|
+
isdestructured = true;
|
|
200
|
+
valueLeft = left.shift();
|
|
201
|
+
baseComparison = [[valueLeft, operatorToken, right], ...left];
|
|
185
202
|
}
|
|
203
|
+
const _val = !isdestructured ? baseComparison[2] : valueRight;
|
|
204
|
+
|
|
205
|
+
comparison = [...baseComparison, { type: "ISNULL", position: "value", defaultValue: nullCheckArg }, _val];
|
|
206
|
+
} else if (isBothNullChecks) {
|
|
207
|
+
const nullCheckArgleft = (ast.left ?? ast.value).args[1]?.value;
|
|
208
|
+
const nullCheckArgright = (ast.right ?? ast.value).args[1]?.value;
|
|
209
|
+
let valueLeft = null;
|
|
210
|
+
let baseComparison = comparison;
|
|
186
211
|
|
|
187
|
-
|
|
212
|
+
if (Array.isArray(left) && (left.includes("or") || left.includes("and"))) {
|
|
213
|
+
isdestructured = true;
|
|
214
|
+
valueLeft = left.shift();
|
|
215
|
+
baseComparison = [[valueLeft, operatorToken, right], ...left];
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const _val = !isdestructured ? baseComparison[2] : valueLeft;
|
|
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]];
|
|
188
224
|
}
|
|
189
225
|
|
|
190
226
|
// Apply short-circuit evaluation if enabled
|
|
@@ -217,6 +253,20 @@ function DevExpressConverter() {
|
|
|
217
253
|
return comparison;
|
|
218
254
|
}
|
|
219
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
|
+
|
|
220
270
|
/**
|
|
221
271
|
* Handles function calls, focusing on ISNULL.
|
|
222
272
|
* @param {Object} ast - The function AST node.
|
package/src/core/parser.js
CHANGED
|
@@ -106,6 +106,21 @@ export function parse(input, variables = []) {
|
|
|
106
106
|
return { type: "logical", operator, left: { type: "function", name: functionName, args: functionArgs }, right: rightOperand };
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
if (rightOperand.type === "logical" && nodeType === "comparison") {
|
|
110
|
+
return {
|
|
111
|
+
type: "logical",
|
|
112
|
+
left: {
|
|
113
|
+
type: "comparison",
|
|
114
|
+
left: { type: "function", name: functionName, args: functionArgs },
|
|
115
|
+
operator: operator,
|
|
116
|
+
right: rightOperand.left
|
|
117
|
+
},
|
|
118
|
+
operator: rightOperand.operator,
|
|
119
|
+
right: rightOperand.right
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
109
124
|
return {
|
|
110
125
|
type: "comparison",
|
|
111
126
|
left: { type: "function", name: functionName, args: functionArgs },
|
|
@@ -134,11 +149,10 @@ export function parse(input, variables = []) {
|
|
|
134
149
|
operator: operator,
|
|
135
150
|
value: rightList
|
|
136
151
|
};
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (LOGICAL_OPERATORS.includes(operator.toLowerCase())) {
|
|
152
|
+
} else if (LOGICAL_OPERATORS.includes(operator.toLowerCase())) {
|
|
140
153
|
// Recursively parse the right-hand expression with adjusted precedence
|
|
141
|
-
|
|
154
|
+
// Add 1 to ensure left-associativity for operators of the same precedence
|
|
155
|
+
const right = parseExpression(OPERATOR_PRECEDENCE[operator] + 1);
|
|
142
156
|
left = { type: "logical", operator, left, right };
|
|
143
157
|
} else if (currentToken?.type == "identifier") {
|
|
144
158
|
const right = parseValue(operator);
|
|
@@ -173,7 +187,32 @@ export function parse(input, variables = []) {
|
|
|
173
187
|
}
|
|
174
188
|
|
|
175
189
|
// Handle function calls like ISNULL(field)
|
|
176
|
-
if (currentToken.type === "function")
|
|
190
|
+
if (currentToken.type === "function") {
|
|
191
|
+
const functionNode = parseFunction();
|
|
192
|
+
|
|
193
|
+
// Check if the function is followed by a comparison operator
|
|
194
|
+
if (currentToken && currentToken.type === "operator" && !LOGICAL_OPERATORS.includes(currentToken.value.toLowerCase())) {
|
|
195
|
+
const operator = currentToken.value.toLowerCase();
|
|
196
|
+
const originalOperator = currentToken.originalValue;
|
|
197
|
+
next();
|
|
198
|
+
|
|
199
|
+
if (operator === "between") {
|
|
200
|
+
return parseBetweenComparison(functionNode, operator);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const value = parseValue(operator);
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
type: "comparison",
|
|
207
|
+
field: functionNode,
|
|
208
|
+
operator,
|
|
209
|
+
value,
|
|
210
|
+
originalOperator
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return functionNode;
|
|
215
|
+
}
|
|
177
216
|
|
|
178
217
|
// Handle literal values (numbers, strings, null)
|
|
179
218
|
if (LITERALS.includes(currentToken.type)) {
|
|
@@ -186,7 +225,7 @@ export function parse(input, variables = []) {
|
|
|
186
225
|
const field = parseValue();
|
|
187
226
|
|
|
188
227
|
// Check if it's part of a comparison expression
|
|
189
|
-
if (currentToken && currentToken.type === "operator") {
|
|
228
|
+
if (currentToken && currentToken.type === "operator" && !LOGICAL_OPERATORS.includes(currentToken.value.toLowerCase())) {
|
|
190
229
|
const operator = currentToken.value.toLowerCase();
|
|
191
230
|
const originalOperator = currentToken.originalValue;
|
|
192
231
|
next();
|
package/src/debug.js
CHANGED
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
// 'LeadStatementGlobalRpt.StateID': null,
|
|
12
12
|
// 'LeadStatementGlobalRpt.RegionID': null,
|
|
13
13
|
// 'ServiceOrderDocument.SourceID': 2,
|
|
14
|
-
// 'CustomerOrders.OrderID': 76548
|
|
14
|
+
// 'CustomerOrders.OrderID': 76548,
|
|
15
|
+
// "TransferOutwardDocument.CompanyID": 7,
|
|
15
16
|
// }
|
|
16
17
|
|
|
17
18
|
// export function parseFilterString(filterString, sampleData = null) {
|
|
@@ -25,10 +26,10 @@
|
|
|
25
26
|
// const astTree = parsedResult.ast;
|
|
26
27
|
// console.log("AST Tree:", JSON.stringify(astTree, null, 2), "\n");
|
|
27
28
|
|
|
28
|
-
// return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData, isValueNullShortCircuit: true });
|
|
29
|
+
// return convertToDevExpressFormat({ ast: astTree, resultObject: sampleData, options: { isValueNullShortCircuit: true, treatNumberAsNullableBit: true } });
|
|
29
30
|
// }
|
|
30
31
|
|
|
31
|
-
// const devexpress = parseFilterString("ISNULL(CompanyID,0) = ISNULL({
|
|
32
|
+
// const devexpress = parseFilterString("ISNULL(CompanyID,0) = ISNULL({TransferOutwardDocument.CompanyID},0) OR ISNULL(CompanyID,0) = 0", sampleData);
|
|
32
33
|
// console.log("DevExpress Filter:", JSON.stringify(devexpress, null, 2));
|
|
33
34
|
// // const devexpress = parseFilterString("(RS2ID in ({LeadStatementGlobalRpt.StateID}) Or ({LeadStatementGlobalRpt.StateID} =0)) And (RS3ID in (0,{LeadStatementGlobalRpt.RegionID}) Or {LeadStatementGlobalRpt.RegionID} =0 )", sampleData);
|
|
34
35
|
|
package/tests/parser.test.js
CHANGED
|
@@ -71,18 +71,20 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
71
71
|
expected: [
|
|
72
72
|
[
|
|
73
73
|
[
|
|
74
|
-
[
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
[
|
|
75
|
+
["FromDate", "<=", "2022-01-01"],
|
|
76
|
+
'and',
|
|
77
|
+
["ToDate", ">=", "2022-01-01"]
|
|
78
|
+
],
|
|
79
|
+
'or',
|
|
80
|
+
["ToDate", "=", null, { "type": "IS" }, null]
|
|
77
81
|
],
|
|
78
|
-
|
|
79
|
-
[
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"or",
|
|
85
|
-
["RefBranchID", "=", null, { "type": "IS" }, null]
|
|
82
|
+
"and",
|
|
83
|
+
[
|
|
84
|
+
["BranchID", "=", 42],
|
|
85
|
+
"or",
|
|
86
|
+
["RefBranchID", "=", null, { "type": "IS" }, null]
|
|
87
|
+
]
|
|
86
88
|
],
|
|
87
89
|
"and",
|
|
88
90
|
[
|
|
@@ -135,15 +137,15 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
135
137
|
{
|
|
136
138
|
input: "ISNULL(SourceID,0) = {ServiceOrderDocument.SourceID} OR ISNULL(SourceID,0) = 0",
|
|
137
139
|
expected: [
|
|
138
|
-
["SourceID", "=", 2],
|
|
139
|
-
"or",
|
|
140
|
-
["SourceID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null],
|
|
141
|
-
"or",
|
|
142
|
-
["SourceID", "=", 0],
|
|
140
|
+
["SourceID", "=", 2, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, 2],
|
|
143
141
|
"or",
|
|
144
|
-
[
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
[
|
|
143
|
+
["SourceID", "=", 0],
|
|
144
|
+
"or",
|
|
145
|
+
["SourceID", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null],
|
|
146
|
+
"or",
|
|
147
|
+
["SourceID", "=", false]
|
|
148
|
+
]
|
|
147
149
|
]
|
|
148
150
|
},
|
|
149
151
|
{
|
|
@@ -155,17 +157,19 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
155
157
|
[
|
|
156
158
|
["CompanyID", "=", 0],
|
|
157
159
|
"or",
|
|
158
|
-
["CompanyID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null],
|
|
160
|
+
["CompanyID", "=", null, { "defaultValue": 0, "position": "column", "type": "ISNULL" }, null],
|
|
159
161
|
"or",
|
|
160
162
|
["CompanyID", "=", false]
|
|
161
163
|
]
|
|
162
164
|
],
|
|
163
165
|
"and",
|
|
164
|
-
[
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
+
// ]
|
|
169
173
|
]
|
|
170
174
|
},
|
|
171
175
|
{
|
|
@@ -189,24 +193,23 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
189
193
|
{
|
|
190
194
|
input: "(ISNULL(TicketID, 0) = ISNULL({SupportResolution.TicketID}, 0))",
|
|
191
195
|
expected: [
|
|
192
|
-
["TicketID", "=", 123],
|
|
196
|
+
["TicketID", "=", 123, { "type": "ISNULL", "position": "both", "defaultValue": 0, "defaultValueRight": 0 }, 123],
|
|
193
197
|
"or",
|
|
194
|
-
["TicketID", "=", null
|
|
198
|
+
["TicketID", "=", null]
|
|
195
199
|
]
|
|
196
200
|
},
|
|
197
201
|
{
|
|
198
202
|
input: "CompanyID = ISNULL({LeadDocument.CompanyID},0) OR (ISNULL(CompanyID,0) = 0))",
|
|
199
203
|
expected: [
|
|
200
|
-
["CompanyID", "=", 7],
|
|
201
|
-
"or",
|
|
202
|
-
["CompanyID", "=", null, { "defaultValue": 0, "type": "ISNULL" }, null],
|
|
203
|
-
"or",
|
|
204
|
-
["CompanyID", "=", 0],
|
|
204
|
+
["CompanyID", "=", 7, { "type": "ISNULL", "position": "value", "defaultValue": 0 }, 7],
|
|
205
205
|
"or",
|
|
206
|
-
[
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
206
|
+
[
|
|
207
|
+
["CompanyID", "=", 0],
|
|
208
|
+
"or",
|
|
209
|
+
["CompanyID", "=", null, { "type": "ISNULL", "position": "column", "defaultValue": 0 }, null],
|
|
210
|
+
"or",
|
|
211
|
+
["CompanyID", "=", false]
|
|
212
|
+
]
|
|
210
213
|
]
|
|
211
214
|
},
|
|
212
215
|
{
|
|
@@ -306,31 +309,85 @@ describe("Parser SQL to dx Filter Builder", () => {
|
|
|
306
309
|
{
|
|
307
310
|
input: "ISNULL(CompanyID,0) = ISNULL({TransferOutwardDocument.CompanyID},0) OR (ISNULL(CompanyID,0) = 0)",
|
|
308
311
|
expected: [
|
|
309
|
-
[
|
|
310
|
-
|
|
311
|
-
["CompanyID", "=", 7],
|
|
312
|
-
"or",
|
|
313
|
-
[
|
|
314
|
-
["CompanyID", "=", 0],
|
|
315
|
-
"or",
|
|
316
|
-
["CompanyID", "=", null,
|
|
317
|
-
{
|
|
318
|
-
"type": "ISNULL",
|
|
319
|
-
"defaultValue": 0
|
|
320
|
-
}, null
|
|
321
|
-
],
|
|
322
|
-
"or",
|
|
323
|
-
["CompanyID", "=", false]
|
|
324
|
-
]
|
|
325
|
-
],
|
|
312
|
+
["CompanyID", "=", 7, { "type": "ISNULL", "position": "both", "defaultValue": 0, "defaultValueRight": 0 }, 7],
|
|
326
313
|
"or",
|
|
327
|
-
[
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
]
|
|
314
|
+
["CompanyID", "=", null],
|
|
315
|
+
"or",
|
|
316
|
+
["CompanyID", "=", 0],
|
|
317
|
+
"or",
|
|
318
|
+
["CompanyID", "=", null, { "type": "ISNULL", "position": "column", "defaultValue": 0 }, null],
|
|
319
|
+
"or",
|
|
320
|
+
["CompanyID", "=", false]
|
|
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]
|
|
334
391
|
]
|
|
335
392
|
}
|
|
336
393
|
];
|