diff --git a/lib/make/makeProjectionExpressionPart.js b/lib/make/makeProjectionExpressionPart.js index 1f29f98..092de87 100644 --- a/lib/make/makeProjectionExpressionPart.js +++ b/lib/make/makeProjectionExpressionPart.js @@ -11,7 +11,6 @@ exports.makeProjectionExpressionPart = makeProjectionExpressionPart; /** * Makes a projection expression sub part. - * * @param {import('../types').Expression} expr - the expression to make a projection from * @param {import('../types').NoqlContext} context - The Noql context to use when generating the output * @param {number} [depth] - the current recursive depth @@ -124,6 +123,9 @@ function makeArg(expr, depth, context) { if (expr.type === 'case') { return makeCaseConditionModule.makeCaseCondition(expr, context); } + if (expr.type === 'double_quote_string') { + return `$${expr.value}`; + } if (expr.value !== undefined) { return {$literal: expr.value}; } diff --git a/package.json b/package.json index 1ddabe4..29467e1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@synatic/noql", - "version": "4.2.5", + "version": "4.2.6", "description": "Convert SQL statements to mongo queries or aggregates", "main": "index.js", "files": [ diff --git a/test/bug-fix-tests/bug-fix.json b/test/bug-fix-tests/bug-fix.json index 55988d1..8593321 100644 --- a/test/bug-fix-tests/bug-fix.json +++ b/test/bug-fix-tests/bug-fix.json @@ -1333,5 +1333,47 @@ } ] } + }, + "ifNull": { + "case-1": { + "expectedResults": [ + { + "SKU": "almonds" + }, + { + "SKU": "Not Specified" + } + ] + }, + "case-2": { + "expectedResults": [ + { + "SKU": "almonds" + }, + { + "SKU": "Not Specified" + } + ] + }, + "case-3": { + "expectedResults": [ + { + "City": "Sasebo" + }, + { + "City": "Not Specified" + } + ] + }, + "case-4": { + "expectedResults": [ + { + "SKU": "almonds" + }, + { + "SKU": "Not Specified" + } + ] + } } } \ No newline at end of file diff --git a/test/bug-fix-tests/bug-fix.test.js b/test/bug-fix-tests/bug-fix.test.js index dec157f..d26d5ca 100644 --- a/test/bug-fix-tests/bug-fix.test.js +++ b/test/bug-fix-tests/bug-fix.test.js @@ -3095,4 +3095,188 @@ order by CurrentDv asc , SQ asc`; }); }); }); + + describe('ifNull', () => { + it('should handle ifNull for a simple statement', async () => { + const sql = ` + SELECT ifNull(sku, 'Not Specified') as SKU + FROM inventory + WHERE id in (1,5)`; + const {pipeline, results} = await queryResultTester({ + queryString: sql, + casePath: 'ifNull.case-1', + mode, + unsetId: true, + }); + assert.deepStrictEqual(results, [ + { + SKU: 'almonds', + }, + { + SKU: 'Not Specified', + }, + ]); + assert.deepStrictEqual(pipeline, [ + { + $match: { + id: { + $in: [1, 5], + }, + }, + }, + { + $project: { + SKU: { + $ifNull: [ + '$sku', + { + $literal: 'Not Specified', + }, + ], + }, + }, + }, + { + $unset: '_id', + }, + ]); + }); + it('should handle ifNull for a simple statement with a table alias', async () => { + const sql = ` + SELECT ifNull(i.sku, 'Not Specified') as SKU + FROM inventory i + WHERE id in (1,5)`; + const {pipeline, results} = await queryResultTester({ + queryString: sql, + casePath: 'ifNull.case-2', + mode, + unsetId: true, + }); + assert.deepStrictEqual(results, [ + { + SKU: 'almonds', + }, + { + SKU: 'Not Specified', + }, + ]); + assert.deepStrictEqual(pipeline, [ + { + $project: { + i: '$$ROOT', + }, + }, + { + $match: { + 'i.id': { + $in: [1, 5], + }, + }, + }, + { + $project: { + SKU: { + $ifNull: [ + '$i.sku', + { + $literal: 'Not Specified', + }, + ], + }, + }, + }, + { + $unset: '_id', + }, + ]); + }); + it('should handle ifNull for a simple statement with a nested field', async () => { + const sql = ` + SELECT ifNull(Address.City, 'Not Specified') as City + FROM customers + WHERE id in (1,599)`; + const {pipeline, results} = await queryResultTester({ + queryString: sql, + casePath: 'ifNull.case-3', + mode, + unsetId: true, + }); + assert.deepStrictEqual(results, [ + { + City: 'Sasebo', + }, + { + City: 'Not Specified', + }, + ]); + assert.deepStrictEqual(pipeline, [ + { + $match: { + id: { + $in: [1, 599], + }, + }, + }, + { + $project: { + City: { + $ifNull: [ + '$Address.City', + { + $literal: 'Not Specified', + }, + ], + }, + }, + }, + { + $unset: '_id', + }, + ]); + }); + it('should handle ifNull for a simple statement with double quotes', async () => { + const sql = ` + SELECT ifNull("sku", 'Not Specified') as SKU + FROM inventory + WHERE id in (1,5)`; + const {pipeline, results} = await queryResultTester({ + queryString: sql, + casePath: 'ifNull.case-4', + mode, + unsetId: true, + }); + assert.deepStrictEqual(results, [ + { + SKU: 'almonds', + }, + { + SKU: 'Not Specified', + }, + ]); + assert.deepStrictEqual(pipeline, [ + { + $match: { + id: { + $in: [1, 5], + }, + }, + }, + { + $project: { + SKU: { + $ifNull: [ + '$sku', + { + $literal: 'Not Specified', + }, + ], + }, + }, + }, + { + $unset: '_id', + }, + ]); + }); + }); }); diff --git a/test/exampleData/customers.json b/test/exampleData/customers.json index 575e6a0..8d293b6 100644 --- a/test/exampleData/customers.json +++ b/test/exampleData/customers.json @@ -1,6 +1,6 @@ [ { - "_id":"61b0fdcbdee485f7c0682db6", + "_id": "61b0fdcbdee485f7c0682db6", "Address": { "Address": "1913 Hanoi Way", "City": "Sasebo", @@ -248750,7 +248750,6 @@ { "Address": { "Address": "1325 Fukuyama Street", - "City": "Tieli", "Country": "China", "District": "Heilongjiang" }, diff --git a/test/individualTests/upgrade.test.js b/test/individualTests/upgrade.test.js index 20755ac..4e7eabf 100644 --- a/test/individualTests/upgrade.test.js +++ b/test/individualTests/upgrade.test.js @@ -307,7 +307,7 @@ describe('node-sql-parser upgrade tests', function () { SELECT id, item, orderDate as od1, - date_add(orderDate,'hour',2,"America/New_York") as od2, + date_add(orderDate,'hour',2,'America/New_York') as od2, unset(_id) FROM orders WHERE id=2 @@ -345,7 +345,7 @@ describe('node-sql-parser upgrade tests', function () { SELECT id, item, orderDate as od1, - date_subtract(orderDate,'hour',2,"America/New_York") as od2, + date_subtract(orderDate,'hour',2,'America/New_York') as od2, unset(_id) FROM orders WHERE id=2