diff --git a/package.json b/package.json index a794f72..97c1d88 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "sqlparser-devexpress", - "version": "2.3.17", + "version": "2.3.19", "main": "src/index.js", "type": "module", "scripts": { - "test": "vitest" + "test": "vitest run" }, "exports": { "import": "./src/index.js", diff --git a/src/core/converter.js b/src/core/converter.js index 5ca3651..c4f2834 100644 --- a/src/core/converter.js +++ b/src/core/converter.js @@ -139,9 +139,9 @@ function DevExpressConverter() { } const left = ast.left !== undefined ? processAstNode(ast.left) : convertValue(ast.field); - const leftDefault = ast.left?.args[1]?.value; + const leftDefault = ast.left?.args && ast.left?.args[1]?.value; const right = ast.right !== undefined ? processAstNode(ast.right) : convertValue(ast.value); - const rightDefault = ast.right?.args[1]?.value; + const rightDefault = ast.right?.args && ast.right?.args[1]?.value; let operatorToken = ast.operator.toLowerCase(); let includeExtradata = false; diff --git a/src/core/parser.js b/src/core/parser.js index 9bbc6f7..d2afc5b 100644 --- a/src/core/parser.js +++ b/src/core/parser.js @@ -140,6 +140,16 @@ export function parse(input, variables = []) { // Recursively parse the right-hand expression with adjusted precedence const right = parseExpression(OPERATOR_PRECEDENCE[operator]); left = { type: "logical", operator, left, right }; + } else if (currentToken?.type == "identifier") { + const right = parseValue(operator); + let newOperator = inverseOperator(operator); + + left = { + type: "comparison", + right: left, + operator: newOperator, + left: { type: "field", value: right } + }; } } @@ -218,12 +228,28 @@ export function parse(input, variables = []) { throw new Error(`Invalid comparison: ${field} ${operator} ${value}`); } + // Swap the field and value if the field is a placeholder and the value is an identifier + if (valueType == "identifier" && fieldType == "placeholder") { + let newOperator = inverseOperator(operator); + return { type: "comparison", value: field, operator: newOperator, field: value, originalOperator }; + } + return { type: "comparison", field, operator, value, originalOperator }; } return { type: "field", value: field }; } + function inverseOperator(operator) { + switch (operator.toUpperCase()) { + case ">": return "<"; + case "<": return ">"; + case ">=": return "<="; + case "<=": return ">="; + default: return operator; // Return the operator as is if no inverse is defined + } + } + // Parses values including numbers, strings, placeholders, and IN lists function parseValue(operatorToken) { if (!currentToken) throw new Error("Unexpected end of input"); diff --git a/tests/parser.test.js b/tests/parser.test.js index 80cdc43..8657290 100644 --- a/tests/parser.test.js +++ b/tests/parser.test.js @@ -268,6 +268,26 @@ describe("Parser SQL to dx Filter Builder", () => { { input: "ID IN ({SaleOrderStatusStmtGlobalRpt.RegionID})", expected: [] + }, + { + input: "10 < ID AND ApplicableUoms IN ({WorkOrderLine.ApplicableUoms})", + expected: [ + ["ID", ">", 10], + "and", + [ + ["ApplicableUoms", "=", "UOM1"], + "or", + ["ApplicableUoms", "=", "UOM2"], + "or", + ["ApplicableUoms", "=", "UOM3"] + ] + ], + }, + { + input: "{ServiceOrderDocument.SourceID} = ID", + expected: [ + "ID", "=", 2 + ] } ];