Skip to content

Commit 6cc907f

Browse files
authored
Merge pull request thomas4019#8 from jeniawhite/evgb-IncMulMinMaxOperators
Patching numeric operators in edge cases
2 parents c5afe16 + a50203f commit 6cc907f

File tree

3 files changed

+16
-7
lines changed

3 files changed

+16
-7
lines changed

test/update.js

+10-5
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,18 @@ describe('update: ', function() {
3838
})
3939

4040
it('$inc', function() {
41-
assert.equal(convertUpdate('data', { $inc: { count: 2 } }), 'jsonb_set(data,\'{count}\',to_jsonb(Cast(data->>\'count\' as numeric)+2))')
41+
assert.equal(convertUpdate('data', { $inc: { count: 2 } }), 'jsonb_set(data,\'{count}\',to_jsonb(COALESCE(Cast(data->>\'count\' as numeric),0)+2))')
4242
})
4343
it('$mul', function() {
44-
assert.equal(convertUpdate('data', { $mul: { count: 2 } }), 'jsonb_set(data,\'{count}\',to_jsonb(Cast(data->>\'count\' as numeric)*2))')
44+
assert.equal(convertUpdate('data', { $mul: { count: 2 } }), 'jsonb_set(data,\'{count}\',to_jsonb(COALESCE(Cast(data->>\'count\' as numeric),0)*2),TRUE)')
4545
})
4646

4747

4848
it('$min', function() {
49-
assert.equal(convertUpdate('data', { $min: { count: 5 } }), 'jsonb_set(data,\'{count}\',to_jsonb(LEAST(Cast(data->>\'count\' as numeric),5)))')
49+
assert.equal(convertUpdate('data', { $min: { count: 5 } }), 'jsonb_set(data,\'{count}\',to_jsonb(LEAST(COALESCE(Cast(data->>\'count\' as numeric),0),5)))')
5050
})
5151
it('$max', function() {
52-
assert.equal(convertUpdate('data', { $max: { count: 5 } }), 'jsonb_set(data,\'{count}\',to_jsonb(GREATEST(Cast(data->>\'count\' as numeric),5)))')
52+
assert.equal(convertUpdate('data', { $max: { count: 5 } }), 'jsonb_set(data,\'{count}\',to_jsonb(GREATEST(COALESCE(Cast(data->>\'count\' as numeric),0),5)))')
5353
})
5454

5555
it('$rename', function() {
@@ -67,6 +67,11 @@ describe('update: ', function() {
6767
})
6868

6969
describe('combined operators', function() {
70-
assert.equal(convertUpdate('data', { $set: { active: true }, $inc: { purchases: 2 } }), 'jsonb_set(jsonb_set(data,\'{active}\',\'true\'::jsonb),\'{purchases}\',to_jsonb(Cast(data->>\'purchases\' as numeric)+2))')
70+
it('$set,$inc', function() {
71+
assert.equal(convertUpdate('data', { $set: { active: true }, $inc: { purchases: 2 } }), 'jsonb_set(jsonb_set(data,\'{active}\',\'true\'::jsonb),\'{purchases}\',to_jsonb(COALESCE(Cast(data->>\'purchases\' as numeric),0)+2))')
72+
})
73+
it('$set,$unset,$inc', function() {
74+
assert.equal(convertUpdate('data', { $set: { active: true }, $unset: { field: 'value' }, $inc: { purchases: 2 } }), 'jsonb_set(jsonb_set(data,\'{active}\',\'true\'::jsonb) #- \'{field}\',\'{purchases}\',to_jsonb(COALESCE(Cast(data->>\'purchases\' as numeric),0)+2))')
75+
})
7176
})
7277
})

update.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,16 @@ function convertOp(input, op, data, fieldName, upsert) {
3232
case '$unset':
3333
return input + ' #- ' + pgPath
3434
case '$inc':
35+
// TODO: Handle null value keys (MongoDB drops the operation with "Cannot apply $inc to a value of non-numeric type null")
3536
return 'jsonb_set(' + input + ',' + pgPath + ',to_jsonb(' + prevNumericVal + '+' + value + '))'
3637
case '$mul':
37-
return 'jsonb_set(' + input + ',' + pgPath + ',to_jsonb(' + prevNumericVal + '*' + value + '))'
38+
// TODO: Handle null value keys (MongoDB drops the operation with "Cannot apply $mul to a value of non-numeric type null")
39+
return 'jsonb_set(' + input + ',' + pgPath + ',to_jsonb(' + prevNumericVal + '*' + value + '),TRUE)'
3840
case '$min':
41+
// TODO: $min between existing key with value null with anything will output null
3942
return 'jsonb_set(' + input + ',' + pgPath + ',to_jsonb(LEAST(' + prevNumericVal + ',' + value + ')))'
4043
case '$max':
44+
// TODO: $max between existing key with value null with anything will output value
4145
return 'jsonb_set(' + input + ',' + pgPath + ',to_jsonb(GREATEST(' + prevNumericVal + ',' + value + ')))'
4246
case '$rename':
4347
const pgNewPath = util.toPostgresPath(value.split('.'))

util.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ exports.toPostgresPath = function(path) {
4646
}
4747

4848
exports.toNumeric = function(path) {
49-
return 'Cast(' + path + ' as numeric)'
49+
return 'COALESCE(Cast(' + path + ' as numeric),0)'
5050
}
5151

5252
const typeMapping = {

0 commit comments

Comments
 (0)