diff --git a/src/lib/plugins/query/javascriptQueryLanguage.test.ts b/src/lib/plugins/query/javascriptQueryLanguage.test.ts index 2fe8d2aa..63d4accc 100644 --- a/src/lib/plugins/query/javascriptQueryLanguage.test.ts +++ b/src/lib/plugins/query/javascriptQueryLanguage.test.ts @@ -35,8 +35,8 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - " data = data.filter(item => item?.user?.name == 'Bob')\n" + ' return data\n' + + " .filter(item => item?.user?.name == 'Bob')\n" + '}' ) @@ -59,8 +59,8 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.filter(item => item?.["user name!"] == \'Bob\')\n' + ' return data\n' + + ' .filter(item => item?.["user name!"] == \'Bob\')\n' + '}' ) @@ -81,10 +81,7 @@ describe('javascriptQueryLanguage', () => { }) assert.deepStrictEqual( query, - 'function query (data) {\n' + - ' data = data.filter(item => item == 1)\n' + - ' return data\n' + - '}' + 'function query (data) {\n return data\n .filter(item => item == 1)\n}' ) const result = executeQuery(data, query, JSON) @@ -103,8 +100,8 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.filter(item => item?.user?.registered == true)\n' + ' return data\n' + + ' .filter(item => item?.user?.registered == true)\n' + '}' ) @@ -124,8 +121,8 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.filter(item => item?.user?.extra != null)\n' + ' return data\n' + + ' .filter(item => item?.user?.extra != null)\n' + '}' ) @@ -145,8 +142,8 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.filter(item => item?.user?.extra != undefined)\n' + ' return data\n' + + ' .filter(item => item?.user?.extra != undefined)\n' + '}' ) @@ -165,13 +162,14 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.slice().sort((a, b) => {\n' + - ' // sort ascending\n' + - ' const valueA = a?.user?.age\n' + - ' const valueB = b?.user?.age\n' + - ' return valueA > valueB ? 1 : valueA < valueB ? -1 : 0\n' + - ' })\n' + ' return data\n' + + ' .slice()\n' + + ' .sort((a, b) => {\n' + + ' // sort ascending\n' + + ' const valueA = a?.user?.age\n' + + ' const valueB = b?.user?.age\n' + + ' return valueA > valueB ? 1 : valueA < valueB ? -1 : 0\n' + + ' })\n' + '}' ) @@ -190,13 +188,14 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.slice().sort((a, b) => {\n' + - ' // sort descending\n' + - ' const valueA = a?.user?.age\n' + - ' const valueB = b?.user?.age\n' + - ' return valueA > valueB ? -1 : valueA < valueB ? 1 : 0\n' + - ' })\n' + ' return data\n' + + ' .slice()\n' + + ' .sort((a, b) => {\n' + + ' // sort descending\n' + + ' const valueA = a?.user?.age\n' + + ' const valueB = b?.user?.age\n' + + ' return valueA > valueB ? -1 : valueA < valueB ? 1 : 0\n' + + ' })\n' + '}' ) @@ -215,8 +214,8 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.map(item => item?.user?.name)\n' + ' return data\n' + + ' .map(item => item?.user?.name)\n' + '}' ) @@ -235,11 +234,11 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.map(item => ({\n' + - ' "name": item?.user?.name,\n' + - ' "_id": item?._id})\n' + - ' )\n' + ' return data\n' + + ' .map(item => ({\n' + + ' "name": item?.user?.name,\n' + + ' "_id": item?._id})\n' + + ' )\n' + '}' ) @@ -271,15 +270,16 @@ describe('javascriptQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = data.filter(item => item?.user?.age <= 7)\n' + - ' data = data.slice().sort((a, b) => {\n' + - ' // sort ascending\n' + - ' const valueA = a?.user?.name\n' + - ' const valueB = b?.user?.name\n' + - ' return valueA > valueB ? 1 : valueA < valueB ? -1 : 0\n' + - ' })\n' + - ' data = data.map(item => item?.user?.name)\n' + ' return data\n' + + ' .filter(item => item?.user?.age <= 7)\n' + + ' .slice()\n' + + ' .sort((a, b) => {\n' + + ' // sort ascending\n' + + ' const valueA = a?.user?.name\n' + + ' const valueB = b?.user?.name\n' + + ' return valueA > valueB ? 1 : valueA < valueB ? -1 : 0\n' + + ' })\n' + + ' .map(item => item?.user?.name)\n' + '}' ) diff --git a/src/lib/plugins/query/javascriptQueryLanguage.ts b/src/lib/plugins/query/javascriptQueryLanguage.ts index 364599b8..6ec47223 100644 --- a/src/lib/plugins/query/javascriptQueryLanguage.ts +++ b/src/lib/plugins/query/javascriptQueryLanguage.ts @@ -20,7 +20,7 @@ export const javascriptQueryLanguage: QueryLanguage = { function createQuery(json: JSONValue, queryOptions: QueryLanguageOptions): string { const { filter, sort, projection } = queryOptions - const queryParts = [] + const queryParts = [' return data\n'] if (filter && filter.path && filter.relation && filter.value) { // Note that the comparisons embrace type coercion, @@ -35,30 +35,30 @@ function createQuery(json: JSONValue, queryOptions: QueryLanguageOptions): strin ? `${filter.value}n` // bigint : filter.value - queryParts.push( - ` data = data.filter(${actualValueGetter} ${filter.relation} ${filterValueStr})\n` - ) + queryParts.push(` .filter(${actualValueGetter} ${filter.relation} ${filterValueStr})\n`) } if (sort && sort.path && sort.direction) { if (sort.direction === 'desc') { queryParts.push( - ` data = data.slice().sort((a, b) => {\n` + - ` // sort descending\n` + - ` const valueA = a${createPropertySelector(sort.path)}\n` + - ` const valueB = b${createPropertySelector(sort.path)}\n` + - ` return valueA > valueB ? -1 : valueA < valueB ? 1 : 0\n` + - ` })\n` + ` .slice()\n` + + ` .sort((a, b) => {\n` + + ` // sort descending\n` + + ` const valueA = a${createPropertySelector(sort.path)}\n` + + ` const valueB = b${createPropertySelector(sort.path)}\n` + + ` return valueA > valueB ? -1 : valueA < valueB ? 1 : 0\n` + + ` })\n` ) } else { // sort direction 'asc' queryParts.push( - ` data = data.slice().sort((a, b) => {\n` + - ` // sort ascending\n` + - ` const valueA = a${createPropertySelector(sort.path)}\n` + - ` const valueB = b${createPropertySelector(sort.path)}\n` + - ` return valueA > valueB ? 1 : valueA < valueB ? -1 : 0\n` + - ` })\n` + ` .slice()\n` + + ` .sort((a, b) => {\n` + + ` // sort ascending\n` + + ` const valueA = a${createPropertySelector(sort.path)}\n` + + ` const valueB = b${createPropertySelector(sort.path)}\n` + + ` return valueA > valueB ? 1 : valueA < valueB ? -1 : 0\n` + + ` })\n` ) } } @@ -70,19 +70,17 @@ function createQuery(json: JSONValue, queryOptions: QueryLanguageOptions): strin const paths = projection.paths.map((path) => { const name = path[path.length - 1] || 'item' // 'item' in case of having selected the whole item const item = `item${createPropertySelector(path)}` - return ` ${JSON.stringify(name)}: ${item}` + return ` ${JSON.stringify(name)}: ${item}` }) - queryParts.push(` data = data.map(item => ({\n${paths.join(',\n')}})\n )\n`) + queryParts.push(` .map(item => ({\n${paths.join(',\n')}})\n )\n`) } else { const item = `item${createPropertySelector(projection.paths[0])}` - queryParts.push(` data = data.map(item => ${item})\n`) + queryParts.push(` .map(item => ${item})\n`) } } - queryParts.push(' return data\n') - return `function query (data) {\n${queryParts.join('')}}` } diff --git a/src/lib/plugins/query/lodashQueryLanguage.test.ts b/src/lib/plugins/query/lodashQueryLanguage.test.ts index 33a37184..3bd15cae 100644 --- a/src/lib/plugins/query/lodashQueryLanguage.test.ts +++ b/src/lib/plugins/query/lodashQueryLanguage.test.ts @@ -20,7 +20,10 @@ describe('lodashQueryLanguage', () => { test('should create a and execute an empty query', () => { const query = createQuery(users, {}) const result = executeQuery(users, query, JSON) - assert.deepStrictEqual(query, 'function query (data) {\n return data\n}') + assert.deepStrictEqual( + query, + 'function query (data) {\n return _.chain(data)\n .value()\n}' + ) assert.deepStrictEqual(result, users) assert.deepStrictEqual(users, originalUsers) // must not touch the original users }) @@ -39,8 +42,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - " data = _.filter(data, item => item?.user?.name == 'Bob')\n" + - ' return data\n' + + ' return _.chain(data)\n' + + " .filter(item => item?.user?.name == 'Bob')\n" + + ' .value()\n' + '}' ) @@ -63,8 +67,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.filter(data, item => item?.["user name!"] == \'Bob\')\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .filter(item => item?.["user name!"] == \'Bob\')\n' + + ' .value()\n' + '}' ) @@ -86,8 +91,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.filter(data, item => item == 1)\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .filter(item => item == 1)\n' + + ' .value()\n' + '}' ) @@ -107,8 +113,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.filter(data, item => item?.user?.registered == true)\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .filter(item => item?.user?.registered == true)\n' + + ' .value()\n' + '}' ) @@ -128,8 +135,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.filter(data, item => item?.user?.extra != null)\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .filter(item => item?.user?.extra != null)\n' + + ' .value()\n' + '}' ) @@ -149,8 +157,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.filter(data, item => item?.user?.extra != undefined)\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .filter(item => item?.user?.extra != undefined)\n' + + ' .value()\n' + '}' ) @@ -169,8 +178,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - " data = _.orderBy(data, ['user.age'], ['asc'])\n" + - ' return data\n' + + ' return _.chain(data)\n' + + " .orderBy(['user.age'], ['asc'])\n" + + ' .value()\n' + '}' ) @@ -189,8 +199,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - " data = _.orderBy(data, ['user.age'], ['desc'])\n" + - ' return data\n' + + ' return _.chain(data)\n' + + " .orderBy(['user.age'], ['desc'])\n" + + ' .value()\n' + '}' ) @@ -208,8 +219,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.map(data, item => item?.user?.name)\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .map(item => item?.user?.name)\n' + + ' .value()\n' + '}' ) @@ -227,11 +239,12 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.map(data, item => ({\n' + - ' "name": item?.user?.name,\n' + - ' "_id": item?._id\n' + - ' }))\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .map(item => ({\n' + + ' "name": item?.user?.name,\n' + + ' "_id": item?._id\n' + + ' }))\n' + + ' .value()\n' + '}' ) @@ -264,10 +277,11 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.filter(data, item => item?.user?.age <= 7)\n' + - " data = _.orderBy(data, ['user.name'], ['asc'])\n" + - ' data = _.map(data, item => item?.user?.name)\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .filter(item => item?.user?.age <= 7)\n' + + " .orderBy(['user.name'], ['asc'])\n" + + ' .map(item => item?.user?.name)\n' + + ' .value()\n' + '}' ) @@ -299,8 +313,9 @@ describe('lodashQueryLanguage', () => { assert.deepStrictEqual( query, 'function query (data) {\n' + - ' data = _.orderBy(data, [["nested","complex \\"field\\" \'name\'"]], [\'asc\'])\n' + - ' return data\n' + + ' return _.chain(data)\n' + + ' .orderBy([["nested","complex \\"field\\" \'name\'"]], [\'asc\'])\n' + + ' .value()\n' + '}' ) diff --git a/src/lib/plugins/query/lodashQueryLanguage.ts b/src/lib/plugins/query/lodashQueryLanguage.ts index 9265b5e6..5fbeaa21 100644 --- a/src/lib/plugins/query/lodashQueryLanguage.ts +++ b/src/lib/plugins/query/lodashQueryLanguage.ts @@ -26,7 +26,7 @@ export const lodashQueryLanguage: QueryLanguage = { function createQuery(json: JSONValue, queryOptions: QueryLanguageOptions): string { const { filter, sort, projection } = queryOptions - const queryParts = [] + const queryParts = [' return _.chain(data)\n'] if (filter && filter.path && filter.relation && filter.value) { // Note that the comparisons embrace type coercion, @@ -41,16 +41,12 @@ function createQuery(json: JSONValue, queryOptions: QueryLanguageOptions): strin ? `${filter.value}n` // bigint : filter.value - queryParts.push( - ` data = _.filter(data, ${actualValueGetter} ${filter.relation} ${filterValueStr})\n` - ) + queryParts.push(` .filter(${actualValueGetter} ${filter.relation} ${filterValueStr})\n`) } if (sort && sort.path && sort.direction) { queryParts.push( - ` data = _.orderBy(data, [${createLodashPropertySelector(sort.path)}], ['${ - sort.direction - }'])\n` + ` .orderBy([${createLodashPropertySelector(sort.path)}], ['${sort.direction}'])\n` ) } @@ -61,16 +57,16 @@ function createQuery(json: JSONValue, queryOptions: QueryLanguageOptions): strin // Note that we do not use _.pick() here because this function doesn't flatten the results const paths = projection.paths.map((path) => { const name = last(path) || 'item' // 'item' in case of having selected the whole item - return ` ${JSON.stringify(name)}: item${createPropertySelector(path)}` + return ` ${JSON.stringify(name)}: item${createPropertySelector(path)}` }) - queryParts.push(` data = _.map(data, item => ({\n${paths.join(',\n')}\n }))\n`) + queryParts.push(` .map(item => ({\n${paths.join(',\n')}\n }))\n`) } else { const path = projection.paths[0] - queryParts.push(` data = _.map(data, item => item${createPropertySelector(path)})\n`) + queryParts.push(` .map(item => item${createPropertySelector(path)})\n`) } } - queryParts.push(' return data\n') + queryParts.push(' .value()\n') return `function query (data) {\n${queryParts.join('')}}` }