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

Commit d27863d

Browse files
authored
add support for num operations (#28)
* add support for num operations * clean warnings
1 parent ca3605d commit d27863d

File tree

2 files changed

+229
-46
lines changed

2 files changed

+229
-46
lines changed

src/lib.rs

Lines changed: 139 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
#[macro_use]
22
extern crate redismodule;
33

4-
use redismodule::{Context, RedisResult, NextArg, REDIS_OK, RedisError};
54
use redismodule::native_types::RedisType;
5+
use redismodule::{Context, NextArg, RedisError, RedisResult, REDIS_OK};
66

77
mod redisjson;
88

9-
use crate::redisjson::RedisJSON;
9+
use crate::redisjson::{Error, RedisJSON};
1010

1111
static REDIS_JSON_TYPE: RedisType = RedisType::new("RedisJSON");
1212

@@ -25,7 +25,7 @@ fn json_del(ctx: &Context, args: Vec<String>) -> RedisResult {
2525
let key = ctx.open_key_writable(&key);
2626
let deleted = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
2727
Some(doc) => doc.delete_path(&path)?,
28-
None => 0
28+
None => 0,
2929
};
3030
Ok(deleted.into())
3131
}
@@ -37,13 +37,12 @@ fn json_set(ctx: &Context, args: Vec<String>) -> RedisResult {
3737
let path = args.next_string()?;
3838
let value = args.next_string()?;
3939

40-
let set_option = args.next()
41-
.map(|op| {
42-
match op.to_uppercase().as_str() {
43-
"NX" => Ok(SetOptions::NotExists),
44-
"XX" => Ok(SetOptions::AlreadyExists),
45-
_ => Err(RedisError::Str("ERR syntax error")),
46-
}
40+
let set_option = args
41+
.next()
42+
.map(|op| match op.to_uppercase().as_str() {
43+
"NX" => Ok(SetOptions::NotExists),
44+
"XX" => Ok(SetOptions::AlreadyExists),
45+
_ => Err(RedisError::Str("ERR syntax error")),
4746
})
4847
.transpose()?;
4948

@@ -73,63 +72,62 @@ fn json_get(ctx: &Context, args: Vec<String>) -> RedisResult {
7372
let mut path = loop {
7473
let arg = match args.next_string() {
7574
Ok(s) => s,
76-
Err(_) => "$".to_owned() // path is optional
75+
Err(_) => "$".to_owned(), // path is optional
7776
};
7877

7978
match arg.as_str() {
80-
"INDENT" => args.next(), // TODO add support
81-
"NEWLINE" => args.next(), // TODO add support
82-
"SPACE" => args.next(), // TODO add support
83-
"NOESCAPE" => continue, // TODO add support
84-
"." => break String::from("$"), // backward compatibility suuport
85-
_ => break arg
79+
"INDENT" => args.next(), // TODO add support
80+
"NEWLINE" => args.next(), // TODO add support
81+
"SPACE" => args.next(), // TODO add support
82+
"NOESCAPE" => continue, // TODO add support
83+
"." => break String::from("$"), // backward compatibility support
84+
_ => break arg,
8685
};
8786
};
8887

89-
if path.starts_with(".") { // backward compatibility
88+
if path.starts_with(".") {
89+
// backward compatibility
9090
path.insert(0, '$');
9191
}
9292

9393
let key = ctx.open_key_writable(&key);
9494

9595
let value = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
9696
Some(doc) => doc.to_string(&path)?.into(),
97-
None => ().into()
97+
None => ().into(),
9898
};
9999

100100
Ok(value)
101101
}
102102

103103
fn json_mget(ctx: &Context, args: Vec<String>) -> RedisResult {
104-
105104
if args.len() < 3 {
106105
return Err(RedisError::WrongArity);
107106
}
108107
if let Some(path) = args.last() {
109108
let mut path = path.clone();
110-
if path.starts_with(".") { // backward compatibility
109+
if path.starts_with(".") {
110+
// backward compatibility
111111
path.insert(0, '$');
112112
}
113-
let mut results: Vec<String> = Vec::with_capacity(args.len()-2);
114-
for key in &args[1..args.len()-1] {
113+
let mut results: Vec<String> = Vec::with_capacity(args.len() - 2);
114+
for key in &args[1..args.len() - 1] {
115115
let redis_key = ctx.open_key_writable(&key);
116116
match redis_key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
117117
Some(doc) => {
118118
let result = doc.to_string(&path)?;
119119
results.push(result);
120-
},
120+
}
121121
None => {}
122122
};
123-
124123
}
125124
Ok(results.into())
126125
} else {
127126
Err(RedisError::WrongArity)
128127
}
129128
}
130129

131-
132-
fn json_strlen(ctx: &Context, args: Vec<String>) -> RedisResult {
130+
fn json_str_len(ctx: &Context, args: Vec<String>) -> RedisResult {
133131
let mut args = args.into_iter().skip(1);
134132
let key = args.next_string()?;
135133
let path = args.next_string()?;
@@ -138,7 +136,7 @@ fn json_strlen(ctx: &Context, args: Vec<String>) -> RedisResult {
138136

139137
let length = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
140138
Some(doc) => doc.str_len(&path)?.into(),
141-
None => ().into()
139+
None => ().into(),
142140
};
143141

144142
Ok(length)
@@ -153,12 +151,107 @@ fn json_type(ctx: &Context, args: Vec<String>) -> RedisResult {
153151

154152
let value = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
155153
Some(doc) => doc.get_type(&path)?.into(),
156-
None => ().into()
154+
None => ().into(),
157155
};
158156

159157
Ok(value)
160158
}
161159

160+
fn json_num_incrby(ctx: &Context, args: Vec<String>) -> RedisResult {
161+
json_num_op(ctx, args, |num1, num2| num1 + num2)
162+
}
163+
164+
fn json_num_multby(ctx: &Context, args: Vec<String>) -> RedisResult {
165+
json_num_op(ctx, args, |num1, num2| num1 * num2)
166+
}
167+
168+
fn json_num_powby(ctx: &Context, args: Vec<String>) -> RedisResult {
169+
json_num_op(ctx, args, |num1, num2| num1.powf(num2))
170+
}
171+
172+
fn json_num_op<F>(ctx: &Context, args: Vec<String>, fun: F) -> RedisResult
173+
where F: Fn(f64, f64) -> f64 {
174+
let mut args = args.into_iter().skip(1);
175+
176+
let key = args.next_string()?;
177+
let path = args.next_string()?;
178+
let number: f64 = args.next_string()?.parse()?;
179+
180+
let key = ctx.open_key_writable(&key);
181+
182+
match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
183+
Some(doc) => Ok(doc.num_op(&path, number, fun)?.into()),
184+
None => Err("ERR could not perform this operation on a key that doesn't exist".into()),
185+
}
186+
}
187+
188+
fn json_str_append(_ctx: &Context, _args: Vec<String>) -> RedisResult {
189+
Err("Command was not implemented".into())
190+
}
191+
192+
fn json_arr_append(_ctx: &Context, _args: Vec<String>) -> RedisResult {
193+
Err("Command was not implemented".into())
194+
}
195+
196+
fn json_arr_index(_ctx: &Context, _args: Vec<String>) -> RedisResult {
197+
Err("Command was not implemented".into())
198+
}
199+
200+
fn json_arr_insert(_ctx: &Context, _args: Vec<String>) -> RedisResult {
201+
Err("Command was not implemented".into())
202+
}
203+
204+
fn json_arr_len(ctx: &Context, args: Vec<String>) -> RedisResult {
205+
json_len(ctx, args, |doc, path| doc.arr_len(path))
206+
}
207+
208+
fn json_arr_pop(_ctx: &Context, _args: Vec<String>) -> RedisResult {
209+
Err("Command was not implemented".into())
210+
}
211+
212+
fn json_arr_trim(_ctx: &Context, _args: Vec<String>) -> RedisResult {
213+
Err("Command was not implemented".into())
214+
}
215+
216+
fn json_obj_keys(_ctx: &Context, _args: Vec<String>) -> RedisResult {
217+
Err("Command was not implemented".into())
218+
}
219+
220+
fn json_obj_len(ctx: &Context, args: Vec<String>) -> RedisResult {
221+
json_len(ctx, args, |doc, path| doc.obj_len(path))
222+
}
223+
224+
fn json_debug(_ctx: &Context, _args: Vec<String>) -> RedisResult {
225+
Err("Command was not implemented".into())
226+
}
227+
228+
fn json_forget(_ctx: &Context, _args: Vec<String>) -> RedisResult {
229+
Err("Command was not implemented".into())
230+
}
231+
232+
fn json_resp(_ctx: &Context, _args: Vec<String>) -> RedisResult {
233+
Err("Command was not implemented".into())
234+
}
235+
236+
fn json_len<F: Fn(&RedisJSON, &String) -> Result<usize, Error>>(
237+
ctx: &Context,
238+
args: Vec<String>,
239+
fun: F,
240+
) -> RedisResult {
241+
let mut args = args.into_iter().skip(1);
242+
let key = args.next_string()?;
243+
let path = args.next_string()?;
244+
245+
let key = ctx.open_key_writable(&key);
246+
247+
let length = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
248+
Some(doc) => fun(&doc, &path)?.into(),
249+
None => ().into(),
250+
};
251+
252+
Ok(length)
253+
}
254+
162255
//////////////////////////////////////////////////////
163256

164257
redis_module! {
@@ -168,11 +261,26 @@ redis_module! {
168261
REDIS_JSON_TYPE,
169262
],
170263
commands: [
171-
["json.set", json_set, "write"],
172264
["json.del", json_del, "write"],
173265
["json.get", json_get, ""],
174266
["json.mget", json_mget, ""],
175-
["json.strlen", json_strlen, ""],
267+
["json.set", json_set, "write"],
176268
["json.type", json_type, ""],
269+
["json.numincrby", json_num_incrby, ""],
270+
["json.nummultby", json_num_multby, ""],
271+
["json.numpowby", json_num_powby, ""],
272+
["json.strappend", json_str_append, ""],
273+
["json.strlen", json_str_len, ""],
274+
["json.arrappend", json_arr_append, ""],
275+
["json.arrindex", json_arr_index, ""],
276+
["json.arrinsert", json_arr_insert, ""],
277+
["json.arrlen", json_arr_len, ""],
278+
["json.arrpop", json_arr_pop, ""],
279+
["json.arrtrim", json_arr_trim, ""],
280+
["json.objkeys", json_obj_keys, ""],
281+
["json.objlen", json_obj_len, ""],
282+
["json.debug", json_debug, ""],
283+
["json.forget", json_forget, ""],
284+
["json.resp", json_resp, ""],
177285
],
178286
}

0 commit comments

Comments
 (0)