Skip to content

Commit 71b64ed

Browse files
author
Thomas Hansen
committed
Fix $push and other changes to match MongoDB
1 parent 1efe67d commit 71b64ed

11 files changed

+388
-27
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ It also has additional converters for Mongo projections which are like "select"
66

77
The goal of this is to eventually provide an adapter which lets Postgres serve as a drop in replacement for Mongo, but that is not there yet.
88
Currently the project has many of the underlying conversions that will be required to do this.
9+
For that project, see [pgmongo](https://github.com/thomas4019/pgmongo).
910

1011
### Select Query Example 1
1112
```javascript
@@ -124,6 +125,7 @@ mongoToPostgres('data', { 'courses.distance': '5K' }, ['courses'])
124125
* [$expr](https://docs.mongodb.com/manual/reference/operator/query/expr/)
125126
* [Bitwise Operators](https://docs.mongodb.com/manual/reference/operator/query-bitwise/)
126127
* Update
128+
* [$pop](https://docs.mongodb.com/manual/reference/operator/update/pop/)
127129
* [$currentDate](https://docs.mongodb.com/manual/reference/operator/update/currentDate/)
128130
* [$setOnInsert](https://docs.mongodb.com/manual/reference/operator/update/setOnInsert/)
129131
* Other

index.js

+31-5
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,38 @@ function convertOp(path, op, value, parent, arrayPaths) {
4444
throw new Error('$and or $or requires an array.')
4545
}
4646
if (value.length == 0) {
47-
return (op === '$or' ? 'FALSE' : 'TRUE')
47+
throw new Error('$and/$or/$nor must be a nonempty array')
4848
} else {
49+
for (const v of value) {
50+
if (typeof v !== "object") {
51+
throw new Error('$or/$and/$nor entries need to be full objects')
52+
}
53+
}
4954
return '(' + value.map((subquery) => convert(path, subquery)).join(op === '$or' ? ' OR ' : ' AND ') + ')'
5055
}
5156
case '$elemMatch':
5257
return util.pathToText(path, false) + ' @> \'' + util.stringEscape(JSON.stringify(value)) + '\'::jsonb'
5358
case '$in':
5459
case '$nin':
55-
return util.pathToText(path, typeof value[0] == 'string') + (op == '$nin' ? ' NOT' : '') + ' IN (' + value.map(util.quote).join(', ') + ')'
60+
if (value.length === 1) {
61+
return convert(path, value[0], arrayPaths)
62+
}
63+
const cleanedValue = value.filter((v) => (v !== null && typeof v !== 'undefined'))
64+
let partial = util.pathToText(path, typeof value[0] == 'string') + (op == '$nin' ? ' NOT' : '') + ' IN (' + cleanedValue.map(util.quote).join(', ') + ')'
65+
if (value.length != cleanedValue.length) {
66+
return (op === '$in' ? '(' + partial + ' OR IS NULL)' : '(' + partial + ' AND IS NOT NULL)' )
67+
}
68+
return partial
5669
case '$regex':
5770
var op = '~'
71+
var op2 = '';
5872
if (parent['$options'] && parent['$options'].includes('i')) {
5973
op += '*'
6074
}
61-
return util.pathToText(path, true) + ' ' + op + ' \'' + util.stringEscape(value) + '\''
75+
if (!parent['$options'] || !parent['$options'].includes('s')) {
76+
op2 += '(?p)'
77+
}
78+
return util.pathToText(path, true) + ' ' + op + ' \'' + op2 + util.stringEscape(value) + '\''
6279
case '$eq':
6380
case '$gt':
6481
case '$gte':
@@ -93,7 +110,15 @@ var convert = function (path, query, arrayPaths) {
93110
var text = util.pathToText(path, typeof query == 'string')
94111
return text + '=' + util.quote(query)
95112
}
96-
if (typeof query == 'object') {
113+
if (query === null) {
114+
var text = util.pathToText(path, false)
115+
return '(' + text + ' IS NULL OR ' + text + ' = \'null\'::jsonb)'
116+
}
117+
if (query instanceof RegExp) {
118+
var op = query.ignoreCase ? '~*' : '~'
119+
return util.pathToText(path, true) + ' ' + op + ' \'' + util.stringEscape(query.source) + '\''
120+
}
121+
if (typeof query === 'object') {
97122
// Check for an empty object
98123
if (Object.keys(query).length === 0) {
99124
return 'TRUE'
@@ -120,6 +145,7 @@ module.exports = function (fieldName, query, arrays) {
120145
return convert([fieldName], query, arrays || [])
121146
}
122147
module.exports.convertDotNotation = util.convertDotNotation
148+
module.exports.pathToText = util.pathToText
123149
module.exports.convertSelect = require('./select');
124150
module.exports.convertUpdate = require('./update');
125-
module.exports.convertSort = require('./sort');
151+
module.exports.convertSort = require('./sort');

0 commit comments

Comments
 (0)