@@ -10,11 +10,14 @@ import (
10
10
"sync"
11
11
)
12
12
13
- var basicOperatorMap = map [string ]string {
14
- "$gt" : ">" ,
15
- "$gte" : ">=" ,
16
- "$lt" : "<" ,
17
- "$lte" : "<=" ,
13
+ var numericOperatorMap = map [string ]string {
14
+ "$gt" : ">" ,
15
+ "$gte" : ">=" ,
16
+ "$lt" : "<" ,
17
+ "$lte" : "<=" ,
18
+ }
19
+
20
+ var textOperatorMap = map [string ]string {
18
21
"$eq" : "=" ,
19
22
"$ne" : "!=" ,
20
23
"$regex" : "~*" ,
@@ -200,14 +203,7 @@ func (c *Converter) convertFilter(filter map[string]any, paramIndex int) (string
200
203
values = append (values , v [operator ])
201
204
case "$exists" :
202
205
// $exists only works on jsonb columns, so we need to check if the key is in the JSONB data first.
203
- isNestedColumn := c .nestedColumn != ""
204
- for _ , exemption := range c .nestedExemptions {
205
- if exemption == key {
206
- isNestedColumn = false
207
- break
208
- }
209
- }
210
- if ! isNestedColumn {
206
+ if ! c .isNestedColumn (key ) {
211
207
// There is no way in Postgres to check if a column exists on a table.
212
208
return "" , nil , fmt .Errorf ("$exists operator not supported on non-nested jsonb columns" )
213
209
}
@@ -217,20 +213,14 @@ func (c *Converter) convertFilter(filter map[string]any, paramIndex int) (string
217
213
}
218
214
inner = append (inner , fmt .Sprintf ("(%sjsonb_path_match(%s, 'exists($.%s)'))" , neg , c .nestedColumn , key ))
219
215
case "$elemMatch" :
220
- // $elemMatch needs a different implementation depending on if the column is in JSONB or not.
221
- isNestedColumn := c .nestedColumn != ""
222
- for _ , exemption := range c .nestedExemptions {
223
- if exemption == key {
224
- isNestedColumn = false
225
- break
226
- }
227
- }
228
216
innerConditions , innerValues , err := c .convertFilter (map [string ]any {c .placeholderName : v [operator ]}, paramIndex )
229
217
if err != nil {
230
218
return "" , nil , err
231
219
}
232
220
paramIndex += len (innerValues )
233
- if isNestedColumn {
221
+
222
+ // $elemMatch needs a different implementation depending on if the column is in JSONB or not.
223
+ if c .isNestedColumn (key ) {
234
224
// This will for example become:
235
225
//
236
226
// EXISTS (SELECT 1 FROM jsonb_array_elements("meta"->'foo') AS __filter_placeholder WHERE ("__filter_placeholder"::text = $1))
@@ -247,11 +237,29 @@ func (c *Converter) convertFilter(filter map[string]any, paramIndex int) (string
247
237
values = append (values , innerValues ... )
248
238
default :
249
239
value := v [operator ]
250
- op , ok := basicOperatorMap [operator ]
240
+ isNumericOperatorMap := false
241
+ op , ok := textOperatorMap [operator ]
251
242
if ! ok {
252
- return "" , nil , fmt .Errorf ("unknown operator: %s" , operator )
243
+ op , ok = numericOperatorMap [operator ]
244
+ if ! ok {
245
+ return "" , nil , fmt .Errorf ("unknown operator: %s" , operator )
246
+ }
247
+ isNumericOperatorMap = true
248
+ }
249
+
250
+ if ! isScalar (value ) {
251
+ return "" , nil , fmt .Errorf ("invalid comparison value (must be a primitive): %v" , value )
252
+ }
253
+
254
+ if isNumericOperatorMap && isNumeric (value ) {
255
+ if c .isNestedColumn (key ) {
256
+ inner = append (inner , fmt .Sprintf ("((%s)::numeric %s $%d)" , c .columnName (key ), op , paramIndex ))
257
+ } else {
258
+ inner = append (inner , fmt .Sprintf ("(%s %s $%d)" , c .columnName (key ), op , paramIndex ))
259
+ }
260
+ } else {
261
+ inner = append (inner , fmt .Sprintf ("(%s %s $%d)" , c .columnName (key ), op , paramIndex ))
253
262
}
254
- inner = append (inner , fmt .Sprintf ("(%s %s $%d)" , c .columnName (key ), op , paramIndex ))
255
263
paramIndex ++
256
264
values = append (values , value )
257
265
}
@@ -308,3 +316,15 @@ func (c *Converter) columnName(column string) string {
308
316
}
309
317
return fmt .Sprintf (`%q->>'%s'` , c .nestedColumn , column )
310
318
}
319
+
320
+ func (c * Converter ) isNestedColumn (column string ) bool {
321
+ if c .nestedColumn == "" {
322
+ return false
323
+ }
324
+ for _ , exemption := range c .nestedExemptions {
325
+ if exemption == column {
326
+ return false
327
+ }
328
+ }
329
+ return true
330
+ }
0 commit comments