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

Commit e71e135

Browse files
authored
Backward comparability fixes (#32)
* 1. json_del: backward fix on json_del to support full key delete 2. json_set: error on creation of key with path!=root 3. mark commands as "write" and open keys with open_key() on readonly 4. set_value: add support for root set and returns error when path not found 5. get_doc: return error on wrong path * fix comment
1 parent f8a51d7 commit e71e135

File tree

2 files changed

+86
-42
lines changed

2 files changed

+86
-42
lines changed

src/lib.rs

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,14 @@ fn json_del(ctx: &Context, args: Vec<String>) -> RedisResult {
4040

4141
let key = ctx.open_key_writable(&key);
4242
let deleted = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
43-
Some(doc) => doc.delete_path(&path)?,
43+
Some(doc) => {
44+
if path == "$" {
45+
key.delete()?;
46+
1
47+
} else {
48+
doc.delete_path(&path)?
49+
}
50+
}
4451
None => 0,
4552
};
4653
Ok(deleted.into())
@@ -74,12 +81,25 @@ fn json_set(ctx: &Context, args: Vec<String>) -> RedisResult {
7481
(None, Some(SetOptions::AlreadyExists)) => Ok(().into()),
7582
(None, _) => {
7683
let doc = RedisJSON::from_str(&value)?;
77-
key.set_value(&REDIS_JSON_TYPE, doc)?;
78-
REDIS_OK
84+
if path == "$" {
85+
key.set_value(&REDIS_JSON_TYPE, doc)?;
86+
REDIS_OK
87+
} else {
88+
Err("ERR new objects must be created at the root".into())
89+
}
7990
}
8091
}
8192
}
8293

94+
///
95+
/// JSON.GET <key>
96+
/// [INDENT indentation-string]
97+
/// [NEWLINE line-break-string]
98+
/// [SPACE space-string]
99+
/// [NOESCAPE]
100+
/// [path ...]
101+
///
102+
/// TODO add support for multi path
83103
fn json_get(ctx: &Context, args: Vec<String>) -> RedisResult {
84104
let mut args = args.into_iter().skip(1);
85105

@@ -111,6 +131,9 @@ fn json_get(ctx: &Context, args: Vec<String>) -> RedisResult {
111131
Ok(value)
112132
}
113133

134+
///
135+
/// JSON.MGET <key> [key ...] <path>
136+
///
114137
fn json_mget(ctx: &Context, args: Vec<String>) -> RedisResult {
115138
if args.len() < 3 {
116139
return Err(RedisError::WrongArity);
@@ -119,7 +142,7 @@ fn json_mget(ctx: &Context, args: Vec<String>) -> RedisResult {
119142
let path = backward_path(path.to_string());
120143
let mut results: Vec<String> = Vec::with_capacity(args.len() - 2);
121144
for key in &args[1..args.len() - 1] {
122-
let redis_key = ctx.open_key_writable(&key);
145+
let redis_key = ctx.open_key(&key);
123146
match redis_key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
124147
Some(doc) => {
125148
let result = doc.to_string(&path)?;
@@ -139,7 +162,7 @@ fn json_str_len(ctx: &Context, args: Vec<String>) -> RedisResult {
139162
let key = args.next_string()?;
140163
let path = backward_path(args.next_string()?);
141164

142-
let key = ctx.open_key_writable(&key);
165+
let key = ctx.open_key(&key);
143166

144167
let length = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
145168
Some(doc) => doc.str_len(&path)?.into(),
@@ -154,7 +177,7 @@ fn json_type(ctx: &Context, args: Vec<String>) -> RedisResult {
154177
let key = args.next_string()?;
155178
let path = backward_path(args.next_string()?);
156179

157-
let key = ctx.open_key_writable(&key);
180+
let key = ctx.open_key(&key);
158181

159182
let value = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
160183
Some(doc) => doc.get_type(&path)?.into(),
@@ -214,6 +237,9 @@ fn json_arr_len(ctx: &Context, args: Vec<String>) -> RedisResult {
214237
json_len(ctx, args, |doc, path| doc.arr_len(path))
215238
}
216239

240+
///
241+
/// JSON.ARRPOP <key> [path [index]]
242+
///
217243
fn json_arr_pop(_ctx: &Context, _args: Vec<String>) -> RedisResult {
218244
Err("Command was not implemented".into())
219245
}
@@ -234,10 +260,6 @@ fn json_debug(_ctx: &Context, _args: Vec<String>) -> RedisResult {
234260
Err("Command was not implemented".into())
235261
}
236262

237-
fn json_forget(_ctx: &Context, _args: Vec<String>) -> RedisResult {
238-
Err("Command was not implemented".into())
239-
}
240-
241263
fn json_resp(_ctx: &Context, _args: Vec<String>) -> RedisResult {
242264
Err("Command was not implemented".into())
243265
}
@@ -249,10 +271,9 @@ fn json_len<F: Fn(&RedisJSON, &String) -> Result<usize, Error>>(
249271
) -> RedisResult {
250272
let mut args = args.into_iter().skip(1);
251273
let key = args.next_string()?;
252-
let path = args.next_string()?;
253-
254-
let key = ctx.open_key_writable(&key);
274+
let path = backward_path(args.next_string()?);
255275

276+
let key = ctx.open_key(&key);
256277
let length = match key.get_value::<RedisJSON>(&REDIS_JSON_TYPE)? {
257278
Some(doc) => fun(&doc, &path)?.into(),
258279
None => ().into(),
@@ -261,6 +282,13 @@ fn json_len<F: Fn(&RedisJSON, &String) -> Result<usize, Error>>(
261282
Ok(length)
262283
}
263284

285+
fn json_cache_info(_ctx: &Context, _args: Vec<String>) -> RedisResult {
286+
Err("Command was not implemented".into())
287+
}
288+
289+
fn json_cache_init(_ctx: &Context, _args: Vec<String>) -> RedisResult {
290+
Err("Command was not implemented".into())
291+
}
264292
//////////////////////////////////////////////////////
265293

266294
redis_module! {
@@ -275,21 +303,23 @@ redis_module! {
275303
["json.mget", json_mget, ""],
276304
["json.set", json_set, "write"],
277305
["json.type", json_type, ""],
278-
["json.numincrby", json_num_incrby, ""],
279-
["json.nummultby", json_num_multby, ""],
280-
["json.numpowby", json_num_powby, ""],
281-
["json.strappend", json_str_append, ""],
306+
["json.numincrby", json_num_incrby, "write"],
307+
["json.nummultby", json_num_multby, "write"],
308+
["json.numpowby", json_num_powby, "write"],
309+
["json.strappend", json_str_append, "write"],
282310
["json.strlen", json_str_len, ""],
283-
["json.arrappend", json_arr_append, ""],
311+
["json.arrappend", json_arr_append, "write"],
284312
["json.arrindex", json_arr_index, ""],
285-
["json.arrinsert", json_arr_insert, ""],
313+
["json.arrinsert", json_arr_insert, "write"],
286314
["json.arrlen", json_arr_len, ""],
287-
["json.arrpop", json_arr_pop, ""],
288-
["json.arrtrim", json_arr_trim, ""],
315+
["json.arrpop", json_arr_pop, "write"],
316+
["json.arrtrim", json_arr_trim, "write"],
289317
["json.objkeys", json_obj_keys, ""],
290318
["json.objlen", json_obj_len, ""],
291319
["json.debug", json_debug, ""],
292-
["json.forget", json_forget, ""],
320+
["json.forget", json_del, "write"],
293321
["json.resp", json_resp, ""],
322+
["json._cacheinfo", json_cache_info, ""],
323+
["json._cacheinit", json_cache_init, "write"],
294324
],
295325
}

src/redisjson.rs

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,22 @@ impl RedisJSON {
6060
// Parse the string of data into serde_json::Value.
6161
let json: Value = serde_json::from_str(data)?;
6262

63-
let current_data = mem::replace(&mut self.data, Value::Null);
64-
let new_data = jsonpath_lib::replace_with(current_data, path, &mut |_v| json.clone())?;
65-
self.data = new_data;
66-
67-
Ok(())
63+
if path == "$" {
64+
self.data = json;
65+
Ok(())
66+
} else {
67+
let mut replaced = false;
68+
let current_data = mem::replace(&mut self.data, Value::Null);
69+
self.data = jsonpath_lib::replace_with(current_data, path, &mut |_v| {
70+
replaced = true;
71+
json.clone()
72+
})?;
73+
if replaced {
74+
Ok(())
75+
} else {
76+
Err(format!("ERR missing path {}", path).into())
77+
}
78+
}
6879
}
6980

7081
pub fn delete_path(&mut self, path: &str) -> Result<usize, Error> {
@@ -133,16 +144,16 @@ impl RedisJSON {
133144
let mut errors = vec![];
134145
let mut result: f64 = 0.0;
135146

136-
self.data = jsonpath_lib::replace_with(current_data, path, &mut |v| {
137-
match apply_op(v, number, &fun) {
138-
Ok((res, new_value)) => {
139-
result = res;
140-
new_value
141-
}
142-
Err(e) => {
143-
errors.push(e);
144-
v.clone()
145-
}
147+
self.data = jsonpath_lib::replace_with(current_data, path, &mut |v| match apply_op(
148+
v, number, &fun,
149+
) {
150+
Ok((res, new_value)) => {
151+
result = res;
152+
new_value
153+
}
154+
Err(e) => {
155+
errors.push(e);
156+
v.clone()
146157
}
147158
})?;
148159
if errors.is_empty() {
@@ -156,13 +167,15 @@ impl RedisJSON {
156167
let results = jsonpath_lib::select(&self.data, path)?;
157168
match results.first() {
158169
Some(s) => Ok(s),
159-
None => Ok(&Value::Null),
170+
None => Err("ERR path does not exist".into()),
160171
}
161172
}
162173
}
163174

164175
fn apply_op<F>(v: &Value, number: f64, fun: F) -> Result<(f64, Value), String>
165-
where F: Fn(f64, f64) -> f64 {
176+
where
177+
F: Fn(f64, f64) -> f64,
178+
{
166179
if let Value::Number(curr) = v {
167180
if let Some(curr_value) = curr.as_f64() {
168181
let res = fun(curr_value, number);
@@ -176,8 +189,9 @@ fn apply_op<F>(v: &Value, number: f64, fun: F) -> Result<(f64, Value), String>
176189
Err("ERR can not convert current value as f64".to_string())
177190
}
178191
} else {
179-
Err(format!("ERR wrong type of path value - expected a number but found {}",
180-
RedisJSON::value_name(&v)))
192+
Err(format!(
193+
"ERR wrong type of path value - expected a number but found {}",
194+
RedisJSON::value_name(&v)
195+
))
181196
}
182197
}
183-

0 commit comments

Comments
 (0)