Skip to content

Commit 240e838

Browse files
committed
Fix issue thomas4019#14 by supporting array matching
1 parent ca3b1f9 commit 240e838

File tree

4 files changed

+30
-4
lines changed

4 files changed

+30
-4
lines changed

index.js

+10-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ function createElementOrArrayQuery(path, op, value, parent, arrayPathStr) {
9393
*/
9494
function convertOp(path, op, value, parent, arrayPaths) {
9595
const arrayPath = getMatchingArrayPath(op, arrayPaths)
96+
// It seems like direct matches shouldn't be array fields, but 2D arrays are possible in MongoDB
97+
// I will need to do more testing to see if we should handle this case differently.
98+
// const arrayDirectMatch = !isSpecialOp(op) && Array.isArray(value)
9699
if (arrayPath) {
97100
return createElementOrArrayQuery(path, op, value, parent, arrayPath)
98101
}
@@ -209,13 +212,19 @@ function convertOp(path, op, value, parent, arrayPaths) {
209212
return 'cast(' + text + ' AS numeric) % ' + value[0] + '=' + value[1]
210213
}
211214
default:
215+
// this is likely a top level field, recurse
212216
return convert(path.concat(op.split('.')), value)
213217
}
214218
}
215219

220+
function isSpecialOp(op) {
221+
return op in OPS || op in OTHER_OPS
222+
}
223+
224+
// top level keys are always special, since you never exact match the whole object
216225
function getSpecialKeys(path, query, forceExact) {
217226
return Object.keys(query).filter(function (key) {
218-
return (path.length === 1 && !forceExact) || key in OPS || key in OTHER_OPS
227+
return (path.length === 1 && !forceExact) || isSpecialOp(key)
219228
})
220229
}
221230

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mongo-query-to-postgres-jsonb",
3-
"version": "0.2.11",
3+
"version": "0.2.12",
44
"description": "Converts MongoDB queries to postgresql queries for jsonb fields.",
55
"main": "index.js",
66
"directories": {

test/filter.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ describe('string equality', function () {
1717
})
1818

1919
describe('array equality', function () {
20+
it('array match', function () {
21+
assert.equal('data @> \'{ "roles": ["Admin"] }\'', convert('data', {'roles': ['Admin']}))
22+
})
23+
it('array match', function () {
24+
assert.equal('data @> \'{ "roles": ["Admin","2"] }\'', convert('data', {'roles': ['Admin', '2']}))
25+
})
2026
it('should use =', function () {
21-
assert.equal('data @> \'{ "roles": Admin }\'', convert('data', {'roles': ['Admin']}))
27+
assert.equal('data @> \'{ "roles": "Admin" }\'', convert('data', {'roles': 'Admin'}))
2228
})
2329
it('should matching numeric indexes', function() {
2430
assert.equal('data->\'roles\'->>0=\'Admin\'', convert('data', {'roles.0': 'Admin'}))
@@ -215,6 +221,17 @@ describe('Match a Field Without Specifying Array Index', function () {
215221
'data->\'roles\') WHERE jsonb_typeof(data->\'roles\')=\'array\' AND value #>>\'{}\' IN (\'Test\', \'Admin\')))',
216222
convert('data', { 'roles': { $in: ['Test', 'Admin'] } }, ['roles']))
217223
})
224+
it('$all', function() {
225+
assert.equal('(data @> \'{ "roles": { "$all": ["Test","Admin"] } }\' OR (EXISTS (SELECT * ' +
226+
'FROM jsonb_array_elements(data->\'roles\') WHERE jsonb_typeof(data->\'roles\')=\'array\' ' +
227+
'AND value @> \'"Test"\') AND EXISTS (SELECT * FROM jsonb_array_elements(data->\'roles\') ' +
228+
'WHERE jsonb_typeof(data->\'roles\')=\'array\' AND value @> \'"Admin"\')))',
229+
convert('data', { 'roles': { $all: ['Test', 'Admin'] } }, ['roles']))
230+
})
231+
it('with another array', function() {
232+
assert.equal('(data @> \'{ "roles": ["Test","Admin"] }\' OR EXISTS (SELECT * FROM jsonb_array_elements(data->\'roles\') WHERE jsonb_typeof(data->\'roles\')=\'array\' AND value @> \'["Test","Admin"]\'::jsonb))',
233+
convert('data', { 'roles': ['Test', 'Admin'] }, ['roles']))
234+
})
218235
})
219236
describe('special cases', function () {
220237
it('should return true when passed no parameters', function() {

util.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ exports.pathToObjectHelper = function(path) {
4949
if (typeof path[0] == 'string') {
5050
return `"${path[0]}"`
5151
} else {
52-
return path[0]
52+
return JSON.stringify(path[0])
5353
}
5454
}
5555
const [head, ...tail] = path

0 commit comments

Comments
 (0)