@@ -44,21 +44,38 @@ function convertOp(path, op, value, parent, arrayPaths) {
44
44
throw new Error ( '$and or $or requires an array.' )
45
45
}
46
46
if ( value . length == 0 ) {
47
- return ( op === '$or' ? 'FALSE' : 'TRUE ')
47
+ throw new Error ( '$and/$or/$nor must be a nonempty array ')
48
48
} 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
+ }
49
54
return '(' + value . map ( ( subquery ) => convert ( path , subquery ) ) . join ( op === '$or' ? ' OR ' : ' AND ' ) + ')'
50
55
}
51
56
case '$elemMatch' :
52
57
return util . pathToText ( path , false ) + ' @> \'' + util . stringEscape ( JSON . stringify ( value ) ) + '\'::jsonb'
53
58
case '$in' :
54
59
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
56
69
case '$regex' :
57
70
var op = '~'
71
+ var op2 = '' ;
58
72
if ( parent [ '$options' ] && parent [ '$options' ] . includes ( 'i' ) ) {
59
73
op += '*'
60
74
}
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 ) + '\''
62
79
case '$eq' :
63
80
case '$gt' :
64
81
case '$gte' :
@@ -93,7 +110,15 @@ var convert = function (path, query, arrayPaths) {
93
110
var text = util . pathToText ( path , typeof query == 'string' )
94
111
return text + '=' + util . quote ( query )
95
112
}
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' ) {
97
122
// Check for an empty object
98
123
if ( Object . keys ( query ) . length === 0 ) {
99
124
return 'TRUE'
@@ -120,6 +145,7 @@ module.exports = function (fieldName, query, arrays) {
120
145
return convert ( [ fieldName ] , query , arrays || [ ] )
121
146
}
122
147
module . exports . convertDotNotation = util . convertDotNotation
148
+ module . exports . pathToText = util . pathToText
123
149
module . exports . convertSelect = require ( './select' ) ;
124
150
module . exports . convertUpdate = require ( './update' ) ;
125
- module . exports . convertSort = require ( './sort' ) ;
151
+ module . exports . convertSort = require ( './sort' ) ;
0 commit comments