Skip to content

Commit

Permalink
feat: change the JavaScript and Lodash query languages to generate im…
Browse files Browse the repository at this point in the history
…mutable, chained queries
  • Loading branch information
josdejong committed Feb 22, 2023
1 parent e2c8e3d commit 3e92c10
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 96 deletions.
68 changes: 34 additions & 34 deletions src/lib/plugins/query/javascriptQueryLanguage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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" +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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)
Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand Down Expand Up @@ -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' +
'}'
)

Expand Down
40 changes: 19 additions & 21 deletions src/lib/plugins/query/javascriptQueryLanguage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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`
)
}
}
Expand All @@ -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('')}}`
}

Expand Down
75 changes: 45 additions & 30 deletions src/lib/plugins/query/lodashQueryLanguage.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand All @@ -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' +
'}'
)

Expand Down Expand Up @@ -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' +
'}'
)

Expand Down Expand Up @@ -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' +
'}'
)

Expand Down

0 comments on commit 3e92c10

Please sign in to comment.