Skip to content
This repository was archived by the owner on Apr 20, 2020. It is now read-only.

Commit 2143ec1

Browse files
authored
fix #55 return the right type on json.num* call (#56)
* fix #55 return the right type on json.num* call
1 parent 4c46496 commit 2143ec1

File tree

2 files changed

+57
-39
lines changed

2 files changed

+57
-39
lines changed

src/lib.rs

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -274,58 +274,76 @@ fn json_type(ctx: &Context, args: Vec<String>) -> RedisResult {
274274
/// JSON.NUMINCRBY <key> <path> <number>
275275
///
276276
fn json_num_incrby(ctx: &Context, args: Vec<String>) -> RedisResult {
277-
json_num_op(ctx, args, |num1, num2| num1 + num2)
277+
json_num_op(ctx, args, |i1, i2| i1 + i2, |f1, f2| f1 + f2)
278278
}
279279

280280
///
281281
/// JSON.NUMMULTBY <key> <path> <number>
282282
///
283283
fn json_num_multby(ctx: &Context, args: Vec<String>) -> RedisResult {
284-
json_num_op(ctx, args, |num1, num2| num1 * num2)
284+
json_num_op(ctx, args, |i1, i2| i1 * i2, |f1, f2| f1 * f2)
285285
}
286286

287287
///
288288
/// JSON.NUMPOWBY <key> <path> <number>
289289
///
290290
fn json_num_powby(ctx: &Context, args: Vec<String>) -> RedisResult {
291-
json_num_op(ctx, args, |num1, num2| num1.powf(num2))
291+
json_num_op(ctx, args, |i1, i2| i1.pow(i2 as u32), |f1, f2| f1.powf(f2))
292292
}
293293

294-
fn json_num_op<F>(ctx: &Context, args: Vec<String>, fun: F) -> RedisResult
294+
fn json_num_op<I, F>(ctx: &Context, args: Vec<String>, op_i64: I, op_f64: F) -> RedisResult
295295
where
296+
I: Fn(i64, i64) -> i64,
296297
F: Fn(f64, f64) -> f64,
297298
{
298299
let mut args = args.into_iter().skip(1);
299300

300301
let key = args.next_string()?;
301302
let path = backwards_compat_path(args.next_string()?);
302-
let number: f64 = args.next_string()?.parse()?;
303+
let number = args.next_string()?;
303304

304305
let key = ctx.open_key_writable(&key);
305306

306307
key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)?
307308
.ok_or_else(RedisError::nonexistent_key)
308309
.and_then(|doc| {
309-
doc.value_op(&path, |value| do_json_num_op(&fun, number, value))
310-
.map(|v| v.to_string().into())
311-
.map_err(|e| e.into())
310+
doc.value_op(&path, |value| {
311+
do_json_num_op(&number, value, &op_i64, &op_f64)
312+
})
313+
.map(|v| v.to_string().into())
314+
.map_err(|e| e.into())
312315
})
313316
}
314317

315-
fn do_json_num_op<F>(fun: F, number: f64, value: &Value) -> Result<Value, Error>
318+
fn do_json_num_op<I, F>(
319+
in_value: &str,
320+
curr_value: &Value,
321+
op_i64: I,
322+
op_f64: F,
323+
) -> Result<Value, Error>
316324
where
325+
I: FnOnce(i64, i64) -> i64,
317326
F: FnOnce(f64, f64) -> f64,
318327
{
319-
value
320-
.as_f64()
321-
.ok_or_else(|| err_json(value, "number"))
322-
.and_then(|curr_value| {
323-
let res = fun(curr_value, number);
324-
325-
Number::from_f64(res)
326-
.ok_or(Error::from("ERR cannot represent result as Number"))
327-
.map(Value::Number)
328-
})
328+
if let Value::Number(curr_value) = curr_value {
329+
let in_value = &serde_json::from_str(in_value)?;
330+
if let Value::Number(in_value) = in_value {
331+
let num_res = match (curr_value.as_i64(), in_value.as_i64()) {
332+
(Some(num1), Some(num2)) => op_i64(num1, num2).into(),
333+
_ => {
334+
let num1 = curr_value.as_f64().unwrap();
335+
let num2 = in_value.as_f64().unwrap();
336+
Number::from_f64(op_f64(num1, num2)).unwrap()
337+
}
338+
};
339+
340+
Ok(Value::Number(num_res))
341+
} else {
342+
Err(err_json(in_value, "number"))
343+
}
344+
} else {
345+
Err(err_json(curr_value, "number"))
346+
}
329347
}
330348

331349
fn err_json(value: &Value, expected_value: &'static str) -> Error {

test/pytest/test.py

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -599,10 +599,10 @@ def testNumIncrCommand(self):
599599
r.flushdb()
600600

601601
self.assertOk(r.execute_command('JSON.SET', 'test', '.', '{ "foo": 0, "bar": "baz" }'))
602-
# self.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', 1))
603-
# self.assertEqual('1', r.execute_command('JSON.GET', 'test', '.foo'))
604-
# self.assertEqual('3', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', 2))
605-
# self.assertEqual('3.5', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', .5))
602+
self.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', 1))
603+
self.assertEqual('1', r.execute_command('JSON.GET', 'test', '.foo'))
604+
self.assertEqual('3', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', 2))
605+
self.assertEqual('3.5', r.execute_command('JSON.NUMINCRBY', 'test', '.foo', .5))
606606

607607
# test a wrong type
608608
with self.assertRaises(redis.exceptions.ResponseError) as cm:
@@ -612,22 +612,22 @@ def testNumIncrCommand(self):
612612
# with self.assertRaises(redis.exceptions.ResponseError) as cm:
613613
# r.execute_command('JSON.NUMINCRBY', 'test', '.fuzz', 1)
614614
#
615-
# # test issue #9
616-
# self.assertOk(r.execute_command('JSON.SET', 'num', '.', '0'))
617-
# self.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'num', '.', 1))
618-
# self.assertEqual('2.5', r.execute_command('JSON.NUMINCRBY', 'num', '.', 1.5))
619-
#
620-
# # test issue 55
621-
# self.assertOk(r.execute_command('JSON.SET', 'foo', '.', '{"foo":0,"bar":42}'))
622-
# # Get the document once
623-
# r.execute_command('JSON.GET', 'foo', '.')
624-
# self.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'foo', 'foo', 1))
625-
# self.assertEqual('84', r.execute_command('JSON.NUMMULTBY', 'foo', 'bar', 2))
626-
# res = json.loads(r.execute_command('JSON.GET', 'foo', '.'))
627-
# self.assertEqual(1, res['foo'])
628-
# self.assertEqual(84, res['bar'])
629-
#
630-
#
615+
# test issue #9
616+
self.assertOk(r.execute_command('JSON.SET', 'num', '.', '0'))
617+
self.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'num', '.', 1))
618+
self.assertEqual('2.5', r.execute_command('JSON.NUMINCRBY', 'num', '.', 1.5))
619+
620+
# test issue 55
621+
self.assertOk(r.execute_command('JSON.SET', 'foo', '.', '{"foo":0,"bar":42}'))
622+
# Get the document once
623+
r.execute_command('JSON.GET', 'foo', '.')
624+
self.assertEqual('1', r.execute_command('JSON.NUMINCRBY', 'foo', 'foo', 1))
625+
self.assertEqual('84', r.execute_command('JSON.NUMMULTBY', 'foo', 'bar', 2))
626+
res = json.loads(r.execute_command('JSON.GET', 'foo', '.'))
627+
self.assertEqual(1, res['foo'])
628+
self.assertEqual(84, res['bar'])
629+
630+
631631
def testStrCommands(self):
632632
"""Test JSON.STRAPPEND and JSON.STRLEN commands"""
633633

0 commit comments

Comments
 (0)