1 use crate::error::Error;
2 use crate::formatter::RedisJsonFormatter;
3 use crate::manager::err_msg_json_path_doesnt_exist_with_param;
4 use crate::manager::{err_msg_json_expected, err_msg_json_path_doesnt_exist_with_param_or};
5 use crate::manager::{AddUpdateInfo, Manager, ReadHolder, SetUpdateInfo, UpdateInfo, WriteHolder};
6 use crate::nodevisitor::{StaticPathElement, StaticPathParser, VisitStatus};
7 use crate::redisjson::{normalize_arr_indices, Format, Path};
8 use jsonpath_lib::select::select_value::{SelectValue, SelectValueType};
9 use jsonpath_lib::select::Selector;
10 use redis_module::{Context, RedisValue};
11 use redis_module::{NextArg, RedisError, RedisResult, RedisString, REDIS_OK};
12 use std::cmp::Ordering;
13
14 use crate::redisjson::SetOptions;
15
16 use serde_json::{Number, Value};
17
18 use itertools::FoldWhile::{Continue, Done};
19 use itertools::{EitherOrBoth, Itertools};
20 use serde::{Serialize, Serializer};
21 use std::collections::HashMap;
22
23 const JSON_ROOT_PATH: &str = "$";
24 const JSON_ROOT_PATH_LEGACY: &str = ".";
25 const CMD_ARG_NOESCAPE: &str = "NOESCAPE";
26 const CMD_ARG_INDENT: &str = "INDENT";
27 const CMD_ARG_NEWLINE: &str = "NEWLINE";
28 const CMD_ARG_SPACE: &str = "SPACE";
29 const CMD_ARG_FORMAT: &str = "FORMAT";
30
31 // Compile time evaluation of the max len() of all elements of the array
max_strlen(arr: &[&str]) -> usize32 const fn max_strlen(arr: &[&str]) -> usize {
33 let mut max_strlen = 0;
34 let arr_len = arr.len();
35 if arr_len < 1 {
36 return max_strlen;
37 }
38 let mut pos = 0;
39 while pos < arr_len {
40 let curr_strlen = arr[pos].len();
41 if max_strlen < curr_strlen {
42 max_strlen = curr_strlen;
43 }
44 pos += 1;
45 }
46 max_strlen
47 }
48
49 // We use this constant to further optimize json_get command, by calculating the max subcommand length
50 // Any subcommand added to JSON.GET should be included on the following array
51 const JSONGET_SUBCOMMANDS_MAXSTRLEN: usize = max_strlen(&[
52 CMD_ARG_NOESCAPE,
53 CMD_ARG_INDENT,
54 CMD_ARG_NEWLINE,
55 CMD_ARG_SPACE,
56 CMD_ARG_FORMAT,
57 ]);
58
59 enum Values<'a, V: SelectValue> {
60 Single(&'a V),
61 Multi(Vec<&'a V>),
62 }
63
64 impl<'a, V: SelectValue> Serialize for Values<'a, V> {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,65 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
66 where
67 S: Serializer,
68 {
69 match self {
70 Values::Single(v) => v.serialize(serializer),
71 Values::Multi(v) => v.serialize(serializer),
72 }
73 }
74 }
75
76 pub struct KeyValue<'a, V: SelectValue> {
77 val: &'a V,
78 }
79
80 impl<'a, V: SelectValue> KeyValue<'a, V> {
new(v: &'a V) -> KeyValue<'a, V>81 pub fn new(v: &'a V) -> KeyValue<'a, V> {
82 KeyValue { val: v }
83 }
84
get_first<'b>(&'a self, path: &'b str) -> Result<&'a V, Error>85 fn get_first<'b>(&'a self, path: &'b str) -> Result<&'a V, Error> {
86 let results = self.get_values(path)?;
87 match results.first() {
88 Some(s) => Ok(s),
89 None => Err(err_msg_json_path_doesnt_exist_with_param(path)
90 .as_str()
91 .into()),
92 }
93 }
94
resp_serialize(&'a self, path: Path) -> RedisResult95 fn resp_serialize(&'a self, path: Path) -> RedisResult {
96 if path.is_legacy() {
97 let v = self.get_first(path.get_path())?;
98 Ok(self.resp_serialize_inner(v))
99 } else {
100 Ok(self
101 .get_values(path.get_path())?
102 .iter()
103 .map(|v| self.resp_serialize_inner(v))
104 .collect::<Vec<RedisValue>>()
105 .into())
106 }
107 }
108
resp_serialize_inner(&'a self, v: &V) -> RedisValue109 fn resp_serialize_inner(&'a self, v: &V) -> RedisValue {
110 match v.get_type() {
111 SelectValueType::Null => RedisValue::Null,
112
113 SelectValueType::Bool => {
114 let bool_val = v.get_bool();
115 match bool_val {
116 true => RedisValue::SimpleString("true".to_string()),
117 false => RedisValue::SimpleString("false".to_string()),
118 }
119 }
120
121 SelectValueType::Long => RedisValue::Integer(v.get_long()),
122
123 SelectValueType::Double => RedisValue::Float(v.get_double()),
124
125 SelectValueType::String => RedisValue::BulkString(v.get_str()),
126
127 SelectValueType::Array => {
128 let mut res: Vec<RedisValue> = Vec::with_capacity(v.len().unwrap() + 1);
129 res.push(RedisValue::SimpleStringStatic("["));
130 v.values()
131 .unwrap()
132 .for_each(|v| res.push(self.resp_serialize_inner(v)));
133 RedisValue::Array(res)
134 }
135
136 SelectValueType::Object => {
137 let mut res: Vec<RedisValue> = Vec::with_capacity(v.len().unwrap() + 1);
138 res.push(RedisValue::SimpleStringStatic("{"));
139 for (k, v) in v.items().unwrap() {
140 res.push(RedisValue::BulkString(k.to_string()));
141 res.push(self.resp_serialize_inner(v));
142 }
143 RedisValue::Array(res)
144 }
145 }
146 }
147
get_values<'b>(&'a self, path: &'b str) -> Result<Vec<&'a V>, Error>148 fn get_values<'b>(&'a self, path: &'b str) -> Result<Vec<&'a V>, Error> {
149 let mut selector = Selector::new();
150 selector.str_path(path)?;
151 selector.value(self.val);
152 let results = selector.select()?;
153 Ok(results)
154 }
155
serialize_object<O: Serialize>( o: &O, indent: Option<&str>, newline: Option<&str>, space: Option<&str>, ) -> String156 pub fn serialize_object<O: Serialize>(
157 o: &O,
158 indent: Option<&str>,
159 newline: Option<&str>,
160 space: Option<&str>,
161 ) -> String {
162 let formatter = RedisJsonFormatter::new(indent, space, newline);
163
164 let mut out = serde_json::Serializer::with_formatter(Vec::new(), formatter);
165 o.serialize(&mut out).unwrap();
166 String::from_utf8(out.into_inner()).unwrap()
167 }
168
to_json_multi( &'a self, paths: &mut Vec<Path>, indent: Option<&str>, newline: Option<&str>, space: Option<&str>, is_legacy: bool, ) -> Result<RedisValue, Error>169 fn to_json_multi(
170 &'a self,
171 paths: &mut Vec<Path>,
172 indent: Option<&str>,
173 newline: Option<&str>,
174 space: Option<&str>,
175 is_legacy: bool,
176 ) -> Result<RedisValue, Error> {
177 // TODO: Creating a temp doc here duplicates memory usage. This can be very memory inefficient.
178 // A better way would be to create a doc of references to the original doc but no current support
179 // in serde_json. I'm going for this implementation anyway because serde_json isn't supposed to be
180 // memory efficient and we're using it anyway. See https://github.com/serde-rs/json/issues/635.
181 let mut missing_path = None;
182 let temp_doc = paths.drain(..).fold(HashMap::new(), |mut acc, path: Path| {
183 let mut selector = Selector::new();
184 selector.value(self.val);
185 if selector.str_path(path.get_path()).is_err() {
186 return acc;
187 }
188 let value = match selector.select() {
189 Ok(s) if is_legacy && !s.is_empty() => Some(Values::Single(s[0])),
190 Ok(s) if !is_legacy => Some(Values::Multi(s)),
191 _ => None,
192 };
193
194 if value.is_none() && missing_path.is_none() {
195 missing_path = Some(path.get_original().to_string());
196 }
197 acc.insert(path.get_original(), value);
198 acc
199 });
200 if let Some(p) = missing_path {
201 return Err(err_msg_json_path_doesnt_exist_with_param(p.as_str()).into());
202 }
203 Ok(Self::serialize_object(&temp_doc, indent, newline, space).into())
204 }
205
to_json_single( &'a self, path: &str, indent: Option<&str>, newline: Option<&str>, space: Option<&str>, is_legacy: bool, ) -> Result<RedisValue, Error>206 fn to_json_single(
207 &'a self,
208 path: &str,
209 indent: Option<&str>,
210 newline: Option<&str>,
211 space: Option<&str>,
212 is_legacy: bool,
213 ) -> Result<RedisValue, Error> {
214 if is_legacy {
215 Ok(self.to_string_single(path, indent, newline, space)?.into())
216 } else {
217 Ok(self.to_string_multi(path, indent, newline, space)?.into())
218 }
219 }
220
to_json( &'a self, paths: &mut Vec<Path>, indent: Option<&str>, newline: Option<&str>, space: Option<&str>, format: Format, ) -> Result<RedisValue, Error>221 fn to_json(
222 &'a self,
223 paths: &mut Vec<Path>,
224 indent: Option<&str>,
225 newline: Option<&str>,
226 space: Option<&str>,
227 format: Format,
228 ) -> Result<RedisValue, Error> {
229 if format == Format::BSON {
230 return Err("ERR Soon to come...".into());
231 }
232 let is_legacy = !paths.iter().any(|p| !p.is_legacy());
233 if paths.len() > 1 {
234 self.to_json_multi(paths, indent, newline, space, is_legacy)
235 } else {
236 self.to_json_single(paths[0].get_path(), indent, newline, space, is_legacy)
237 }
238 }
239
find_add_paths(&mut self, path: &str) -> Result<Vec<UpdateInfo>, Error>240 fn find_add_paths(&mut self, path: &str) -> Result<Vec<UpdateInfo>, Error> {
241 let mut parsed_static_path = StaticPathParser::check(path)?;
242
243 if parsed_static_path.valid != VisitStatus::Valid {
244 return Err("Err: wrong static path".into());
245 }
246 if parsed_static_path.static_path_elements.len() < 2 {
247 return Err("Err: path must end with object key to set".into());
248 }
249
250 let last = parsed_static_path.static_path_elements.pop().unwrap();
251
252 if let StaticPathElement::ObjectKey(key) = last {
253 if let StaticPathElement::Root = parsed_static_path.static_path_elements.last().unwrap()
254 {
255 // Adding to the root
256 Ok(vec![UpdateInfo::AUI(AddUpdateInfo {
257 path: Vec::new(),
258 key,
259 })])
260 } else {
261 // Adding somewhere in existing object, use jsonpath_lib::replace_with
262 let p = parsed_static_path
263 .static_path_elements
264 .iter()
265 .map(|e| e.to_string())
266 .collect::<Vec<_>>()
267 .join("");
268 let mut selector = Selector::default();
269 if let Err(e) = selector.str_path(&p) {
270 return Err(e.into());
271 }
272 selector.value(self.val);
273 let mut res = selector.select_with_paths(|_| true)?;
274 Ok(res
275 .drain(..)
276 .map(|v| {
277 UpdateInfo::AUI(AddUpdateInfo {
278 path: v,
279 key: key.to_string(),
280 })
281 })
282 .collect())
283 }
284 } else if let StaticPathElement::ArrayIndex(_) = last {
285 // if we reach here with array path we must be out of range
286 // otherwise the path would be valid to be set and we would not
287 // have reached here!!
288 Err("ERR array index out of range".into())
289 } else {
290 Err("ERR path not an object or array".into())
291 }
292 }
293
find_paths( &mut self, path: &str, option: &SetOptions, ) -> Result<Vec<UpdateInfo>, Error>294 pub fn find_paths(
295 &mut self,
296 path: &str,
297 option: &SetOptions,
298 ) -> Result<Vec<UpdateInfo>, Error> {
299 if SetOptions::NotExists != *option {
300 let mut selector = Selector::default();
301 let mut res = selector
302 .str_path(path)?
303 .value(self.val)
304 .select_with_paths(|_| true)?;
305 if !res.is_empty() {
306 return Ok(res
307 .drain(..)
308 .map(|v| UpdateInfo::SUI(SetUpdateInfo { path: v }))
309 .collect());
310 }
311 }
312 if SetOptions::AlreadyExists != *option {
313 self.find_add_paths(path)
314 } else {
315 Ok(Vec::new()) // empty vector means no updates
316 }
317 }
318
serialize(results: &V, format: Format) -> Result<String, Error>319 pub fn serialize(results: &V, format: Format) -> Result<String, Error> {
320 let res = match format {
321 Format::JSON => serde_json::to_string(results)?,
322 Format::BSON => return Err("ERR Soon to come...".into()), //results.into() as Bson,
323 };
324 Ok(res)
325 }
326
to_string(&self, path: &str, format: Format) -> Result<String, Error>327 pub fn to_string(&self, path: &str, format: Format) -> Result<String, Error> {
328 let results = self.get_first(path)?;
329 Self::serialize(results, format)
330 }
331
to_string_single( &self, path: &str, indent: Option<&str>, newline: Option<&str>, space: Option<&str>, ) -> Result<String, Error>332 pub fn to_string_single(
333 &self,
334 path: &str,
335 indent: Option<&str>,
336 newline: Option<&str>,
337 space: Option<&str>,
338 ) -> Result<String, Error> {
339 let result = self.get_first(path)?;
340 Ok(Self::serialize_object(&result, indent, newline, space))
341 }
342
to_string_multi( &self, path: &str, indent: Option<&str>, newline: Option<&str>, space: Option<&str>, ) -> Result<String, Error>343 pub fn to_string_multi(
344 &self,
345 path: &str,
346 indent: Option<&str>,
347 newline: Option<&str>,
348 space: Option<&str>,
349 ) -> Result<String, Error> {
350 let results = self.get_values(path)?;
351 Ok(Self::serialize_object(&results, indent, newline, space))
352 }
353
get_type(&self, path: &str) -> Result<String, Error>354 pub fn get_type(&self, path: &str) -> Result<String, Error> {
355 let s = Self::value_name(self.get_first(path)?);
356 Ok(s.to_string())
357 }
358
value_name(value: &V) -> &str359 pub fn value_name(value: &V) -> &str {
360 match value.get_type() {
361 SelectValueType::Null => "null",
362 SelectValueType::Bool => "boolean",
363 SelectValueType::Long => "integer",
364 SelectValueType::Double => "number",
365 SelectValueType::String => "string",
366 SelectValueType::Array => "array",
367 SelectValueType::Object => "object",
368 }
369 }
370
str_len(&self, path: &str) -> Result<usize, Error>371 pub fn str_len(&self, path: &str) -> Result<usize, Error> {
372 let first = self.get_first(path)?;
373 match first.get_type() {
374 SelectValueType::String => Ok(first.get_str().len()),
375 _ => Err(
376 err_msg_json_expected("string", self.get_type(path).unwrap().as_str())
377 .as_str()
378 .into(),
379 ),
380 }
381 }
382
arr_len(&self, path: &str) -> Result<usize, Error>383 pub fn arr_len(&self, path: &str) -> Result<usize, Error> {
384 let first = self.get_first(path)?;
385 match first.get_type() {
386 SelectValueType::Array => Ok(first.len().unwrap()),
387 _ => Err(
388 err_msg_json_expected("array", self.get_type(path).unwrap().as_str())
389 .as_str()
390 .into(),
391 ),
392 }
393 }
394
obj_len(&self, path: &str) -> Result<ObjectLen, Error>395 pub fn obj_len(&self, path: &str) -> Result<ObjectLen, Error> {
396 match self.get_first(path) {
397 Ok(first) => match first.get_type() {
398 SelectValueType::Object => Ok(ObjectLen::Len(first.len().unwrap())),
399 _ => Err(
400 err_msg_json_expected("object", self.get_type(path).unwrap().as_str())
401 .as_str()
402 .into(),
403 ),
404 },
405 _ => Ok(ObjectLen::NoneExisting),
406 }
407 }
408
is_equal<T1: SelectValue, T2: SelectValue>(&self, a: &T1, b: &T2) -> bool409 pub fn is_equal<T1: SelectValue, T2: SelectValue>(&self, a: &T1, b: &T2) -> bool {
410 match (a.get_type(), b.get_type()) {
411 (SelectValueType::Null, SelectValueType::Null) => true,
412 (SelectValueType::Bool, SelectValueType::Bool) => a.get_bool() == b.get_bool(),
413 (SelectValueType::Long, SelectValueType::Long) => a.get_long() == b.get_long(),
414 (SelectValueType::Double, SelectValueType::Double) => a.get_double() == b.get_double(),
415 (SelectValueType::String, SelectValueType::String) => a.get_str() == b.get_str(),
416 (SelectValueType::Array, SelectValueType::Array) => {
417 if a.len().unwrap() != b.len().unwrap() {
418 false
419 } else {
420 for (i, e) in a.values().unwrap().into_iter().enumerate() {
421 if !self.is_equal(e, b.get_index(i).unwrap()) {
422 return false;
423 }
424 }
425 true
426 }
427 }
428 (SelectValueType::Object, SelectValueType::Object) => {
429 if a.len().unwrap() != b.len().unwrap() {
430 false
431 } else {
432 for k in a.keys().unwrap() {
433 let temp1 = a.get_key(k);
434 let temp2 = b.get_key(k);
435 match (temp1, temp2) {
436 (Some(a1), Some(b1)) => {
437 if !self.is_equal(a1, b1) {
438 return false;
439 }
440 }
441 (_, _) => return false,
442 }
443 }
444 true
445 }
446 }
447 (_, _) => false,
448 }
449 }
450
arr_index( &self, path: &str, scalar_value: Value, start: i64, end: i64, ) -> Result<RedisValue, Error>451 pub fn arr_index(
452 &self,
453 path: &str,
454 scalar_value: Value,
455 start: i64,
456 end: i64,
457 ) -> Result<RedisValue, Error> {
458 let res = self
459 .get_values(path)?
460 .iter()
461 .map(|value| {
462 self.arr_first_index_single(value, &scalar_value, start, end)
463 .into()
464 })
465 .collect::<Vec<RedisValue>>();
466 Ok(res.into())
467 }
468
arr_index_legacy( &self, path: &str, scalar_value: Value, start: i64, end: i64, ) -> Result<RedisValue, Error>469 pub fn arr_index_legacy(
470 &self,
471 path: &str,
472 scalar_value: Value,
473 start: i64,
474 end: i64,
475 ) -> Result<RedisValue, Error> {
476 let arr = self.get_first(path)?;
477 match self.arr_first_index_single(arr, &scalar_value, start, end) {
478 FoundIndex::NotArray => Err(Error::from(err_msg_json_expected(
479 "array",
480 self.get_type(path).unwrap().as_str(),
481 ))),
482 i => Ok(i.into()),
483 }
484 }
485
486 /// Returns first array index of `v` in `arr`, or NotFound if not found in `arr`, or NotArray if `arr` is not an array
arr_first_index_single(&self, arr: &V, v: &Value, start: i64, end: i64) -> FoundIndex487 fn arr_first_index_single(&self, arr: &V, v: &Value, start: i64, end: i64) -> FoundIndex {
488 if !arr.is_array() {
489 return FoundIndex::NotArray;
490 }
491
492 let len = arr.len().unwrap() as i64;
493 if len == 0 {
494 return FoundIndex::NotFound;
495 }
496 // end=0 means INFINITY to support backward with RedisJSON
497 let (start, end) = normalize_arr_indices(start, end, len);
498
499 if end < start {
500 // don't search at all
501 return FoundIndex::NotFound;
502 }
503
504 for index in start..end {
505 if self.is_equal(arr.get_index(index as usize).unwrap(), v) {
506 return FoundIndex::Index(index);
507 }
508 }
509
510 FoundIndex::NotFound
511 }
512
obj_keys(&self, path: &str) -> Result<Box<dyn Iterator<Item = &'_ str> + '_>, Error>513 pub fn obj_keys(&self, path: &str) -> Result<Box<dyn Iterator<Item = &'_ str> + '_>, Error> {
514 self.get_first(path)?.keys().ok_or_else(|| {
515 err_msg_json_expected("object", self.get_type(path).unwrap().as_str())
516 .as_str()
517 .into()
518 })
519 }
520 }
521
command_json_get<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult522 pub fn command_json_get<M: Manager>(
523 manager: M,
524 ctx: &Context,
525 args: Vec<RedisString>,
526 ) -> RedisResult {
527 let mut args = args.into_iter().skip(1);
528 let key = args.next_arg()?;
529
530 // Set Capcity to 1 assumiung the common case has one path
531 let mut paths: Vec<Path> = Vec::with_capacity(1);
532 let mut format = Format::JSON;
533 let mut indent = None;
534 let mut space = None;
535 let mut newline = None;
536 while let Ok(arg) = args.next_str() {
537 match arg {
538 // fast way to consider arg a path by using the max length of all possible subcommands
539 // See #390 for the comparison of this function with/without this optimization
540 arg if arg.len() > JSONGET_SUBCOMMANDS_MAXSTRLEN => paths.push(Path::new(arg)),
541 arg if arg.eq_ignore_ascii_case(CMD_ARG_INDENT) => indent = Some(args.next_str()?),
542 arg if arg.eq_ignore_ascii_case(CMD_ARG_NEWLINE) => newline = Some(args.next_str()?),
543 arg if arg.eq_ignore_ascii_case(CMD_ARG_SPACE) => space = Some(args.next_str()?),
544 // Silently ignore. Compatibility with ReJSON v1.0 which has this option. See #168 TODO add support
545 arg if arg.eq_ignore_ascii_case(CMD_ARG_NOESCAPE) => continue,
546 arg if arg.eq_ignore_ascii_case(CMD_ARG_FORMAT) => {
547 format = Format::from_str(args.next_str()?)?
548 }
549 _ => paths.push(Path::new(arg)),
550 };
551 }
552
553 // path is optional -> no path found we use root "$"
554 if paths.is_empty() {
555 paths.push(Path::new(JSON_ROOT_PATH_LEGACY));
556 }
557
558 let key = manager.open_key_read(ctx, &key)?;
559 let value = match key.get_value()? {
560 Some(doc) => KeyValue::new(doc).to_json(&mut paths, indent, newline, space, format)?,
561 None => RedisValue::Null,
562 };
563
564 Ok(value)
565 }
566
command_json_set<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult567 pub fn command_json_set<M: Manager>(
568 manager: M,
569 ctx: &Context,
570 args: Vec<RedisString>,
571 ) -> RedisResult {
572 let mut args = args.into_iter().skip(1);
573
574 let key = args.next_arg()?;
575 let path = Path::new(args.next_str()?);
576 let value = args.next_str()?;
577
578 let mut format = Format::JSON;
579 let mut set_option = SetOptions::None;
580
581 while let Some(s) = args.next() {
582 match s.try_as_str()? {
583 arg if arg.eq_ignore_ascii_case("NX") && set_option == SetOptions::None => {
584 set_option = SetOptions::NotExists
585 }
586 arg if arg.eq_ignore_ascii_case("XX") && set_option == SetOptions::None => {
587 set_option = SetOptions::AlreadyExists
588 }
589 arg if arg.eq_ignore_ascii_case("FORMAT") => {
590 format = Format::from_str(args.next_str()?)?;
591 }
592 _ => return Err(RedisError::Str("ERR syntax error")),
593 };
594 }
595
596 let mut redis_key = manager.open_key_write(ctx, key)?;
597 let current = redis_key.get_value()?;
598
599 let val = manager.from_str(value, format)?;
600
601 match (current, set_option) {
602 (Some(ref mut doc), ref op) => {
603 if path.get_path() == JSON_ROOT_PATH {
604 if *op != SetOptions::NotExists {
605 redis_key.set_value(Vec::new(), val)?;
606 redis_key.apply_changes(ctx, "json.set")?;
607 REDIS_OK
608 } else {
609 Ok(RedisValue::Null)
610 }
611 } else {
612 let mut update_info = KeyValue::new(*doc).find_paths(path.get_path(), op)?;
613 if !update_info.is_empty() {
614 let mut res = false;
615 if update_info.len() == 1 {
616 res = match update_info.pop().unwrap() {
617 UpdateInfo::SUI(sui) => redis_key.set_value(sui.path, val)?,
618 UpdateInfo::AUI(aui) => redis_key.dict_add(aui.path, &aui.key, val)?,
619 }
620 } else {
621 for ui in update_info {
622 res = match ui {
623 UpdateInfo::SUI(sui) => {
624 redis_key.set_value(sui.path, val.clone())?
625 }
626 UpdateInfo::AUI(aui) => {
627 redis_key.dict_add(aui.path, &aui.key, val.clone())?
628 }
629 }
630 }
631 }
632 if res {
633 redis_key.apply_changes(ctx, "json.set")?;
634 REDIS_OK
635 } else {
636 Ok(RedisValue::Null)
637 }
638 } else {
639 Ok(RedisValue::Null)
640 }
641 }
642 }
643 (None, SetOptions::AlreadyExists) => Ok(RedisValue::Null),
644 (None, _) => {
645 if path.get_path() == JSON_ROOT_PATH {
646 redis_key.set_value(Vec::new(), val)?;
647 redis_key.apply_changes(ctx, "json.set")?;
648 REDIS_OK
649 } else {
650 Err(RedisError::Str(
651 "ERR new objects must be created at the root",
652 ))
653 }
654 }
655 }
656 }
657
find_paths<T: SelectValue, F: FnMut(&T) -> bool>( path: &str, doc: &T, f: F, ) -> Result<Vec<Vec<String>>, RedisError>658 fn find_paths<T: SelectValue, F: FnMut(&T) -> bool>(
659 path: &str,
660 doc: &T,
661 f: F,
662 ) -> Result<Vec<Vec<String>>, RedisError> {
663 Ok(Selector::default()
664 .str_path(path)?
665 .value(doc)
666 .select_with_paths(f)?)
667 }
668
669 /// Returns tuples of Value and its concrete path which match the given `path`
get_all_values_and_paths<'a, T: SelectValue>( path: &str, doc: &'a T, ) -> Result<Vec<(&'a T, Vec<String>)>, RedisError>670 fn get_all_values_and_paths<'a, T: SelectValue>(
671 path: &str,
672 doc: &'a T,
673 ) -> Result<Vec<(&'a T, Vec<String>)>, RedisError> {
674 Ok(Selector::default()
675 .str_path(path)?
676 .value(doc)
677 .select_values_with_paths()?)
678 }
679
680 /// Returns a Vec of paths with `None` for Values that do not match the filter
filter_paths<T, F>( mut values_and_paths: Vec<(&T, Vec<String>)>, f: F, ) -> Vec<Option<Vec<String>>> where F: Fn(&T) -> bool,681 fn filter_paths<T, F>(
682 mut values_and_paths: Vec<(&T, Vec<String>)>,
683 f: F,
684 ) -> Vec<Option<Vec<String>>>
685 where
686 F: Fn(&T) -> bool,
687 {
688 values_and_paths
689 .drain(..)
690 .map(|(v, p)| match f(v) {
691 true => Some(p),
692 _ => None,
693 })
694 .collect::<Vec<Option<Vec<String>>>>()
695 }
696
697 /// Returns a Vec of Values with `None` for Values that do not match the filter
filter_values<T, F>(mut values_and_paths: Vec<(&T, Vec<String>)>, f: F) -> Vec<Option<&T>> where F: Fn(&T) -> bool,698 fn filter_values<T, F>(mut values_and_paths: Vec<(&T, Vec<String>)>, f: F) -> Vec<Option<&T>>
699 where
700 F: Fn(&T) -> bool,
701 {
702 values_and_paths
703 .drain(..)
704 .map(|(v, _)| match f(v) {
705 true => Some(v),
706 _ => None,
707 })
708 .collect::<Vec<Option<&T>>>()
709 }
710
find_all_paths<T: SelectValue, F: FnMut(&T) -> bool>( path: &str, doc: &T, f: F, ) -> Result<Vec<Option<Vec<String>>>, RedisError> where F: Fn(&T) -> bool,711 fn find_all_paths<T: SelectValue, F: FnMut(&T) -> bool>(
712 path: &str,
713 doc: &T,
714 f: F,
715 ) -> Result<Vec<Option<Vec<String>>>, RedisError>
716 where
717 F: Fn(&T) -> bool,
718 {
719 let res = get_all_values_and_paths(path, doc)?;
720 match res.is_empty() {
721 false => Ok(filter_paths(res, f)),
722 _ => Ok(vec![]),
723 }
724 }
725
find_all_values<'a, T: SelectValue, F: FnMut(&T) -> bool>( path: &str, doc: &'a T, f: F, ) -> Result<Vec<Option<&'a T>>, RedisError> where F: Fn(&T) -> bool,726 fn find_all_values<'a, T: SelectValue, F: FnMut(&T) -> bool>(
727 path: &str,
728 doc: &'a T,
729 f: F,
730 ) -> Result<Vec<Option<&'a T>>, RedisError>
731 where
732 F: Fn(&T) -> bool,
733 {
734 let res = get_all_values_and_paths(path, doc)?;
735 match res.is_empty() {
736 false => Ok(filter_values(res, f)),
737 _ => Ok(vec![]),
738 }
739 }
740
to_json_value<T>(values: Vec<Option<T>>, none_value: Value) -> Vec<Value> where Value: From<T>,741 fn to_json_value<T>(values: Vec<Option<T>>, none_value: Value) -> Vec<Value>
742 where
743 Value: From<T>,
744 {
745 values
746 .into_iter()
747 .map(|n| match n {
748 Some(t) => t.into(),
749 _ => none_value.clone(),
750 })
751 .collect::<Vec<Value>>()
752 }
753
754 /// Sort the paths so higher indices precede lower indices on the same array,
755 /// And if one path is a sub-path of the other, then paths with shallower hierarchy (closer to the top-level) precedes paths with deeper hierarchy
prepare_paths_for_deletion(paths: &mut Vec<Vec<String>>)756 fn prepare_paths_for_deletion(paths: &mut Vec<Vec<String>>) {
757 paths.sort_by(|v1, v2| {
758 v1.iter()
759 .zip_longest(v2.iter())
760 .fold_while(Ordering::Equal, |_acc, v| {
761 match v {
762 EitherOrBoth::Left(_) => Done(Ordering::Greater), // Shorter paths before longer paths
763 EitherOrBoth::Right(_) => Done(Ordering::Less), // Shorter paths before longer paths
764 EitherOrBoth::Both(p1, p2) => {
765 let i1 = p1.parse::<usize>();
766 let i2 = p2.parse::<usize>();
767 match (i1, i2) {
768 (Err(_), Err(_)) => match p1.cmp(p2) {
769 // String compare
770 Ordering::Less => Done(Ordering::Less),
771 Ordering::Equal => Continue(Ordering::Equal),
772 Ordering::Greater => Done(Ordering::Greater),
773 },
774 (Ok(_), Err(_)) => Done(Ordering::Greater), //String before Numeric
775 (Err(_), Ok(_)) => Done(Ordering::Less), //String before Numeric
776 (Ok(i1), Ok(i2)) => {
777 // Numeric compare - higher indices before lower ones
778 if i1 < i2 {
779 Done(Ordering::Greater)
780 } else if i2 < i1 {
781 Done(Ordering::Less)
782 } else {
783 Continue(Ordering::Equal)
784 }
785 }
786 }
787 }
788 }
789 })
790 .into_inner()
791 });
792 }
793
command_json_del<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult794 pub fn command_json_del<M: Manager>(
795 manager: M,
796 ctx: &Context,
797 args: Vec<RedisString>,
798 ) -> RedisResult {
799 let mut args = args.into_iter().skip(1);
800
801 let key = args.next_arg()?;
802 let path = match args.next() {
803 None => Path::new(JSON_ROOT_PATH_LEGACY),
804 Some(s) => Path::new(s.try_as_str()?),
805 };
806
807 let mut redis_key = manager.open_key_write(ctx, key)?;
808 let deleted = match redis_key.get_value()? {
809 Some(doc) => {
810 let res = if path.get_path() == JSON_ROOT_PATH {
811 redis_key.delete()?;
812 1
813 } else {
814 let mut paths = find_paths(path.get_path(), doc, |_| true)?;
815 prepare_paths_for_deletion(&mut paths);
816 let mut changed = 0;
817 for p in paths {
818 if redis_key.delete_path(p)? {
819 changed += 1;
820 }
821 }
822 changed
823 };
824 if res > 0 {
825 redis_key.apply_changes(ctx, "json.del")?;
826 }
827 res
828 }
829 None => 0,
830 };
831 Ok((deleted as i64).into())
832 }
833
command_json_mget<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult834 pub fn command_json_mget<M: Manager>(
835 manager: M,
836 ctx: &Context,
837 args: Vec<RedisString>,
838 ) -> RedisResult {
839 if args.len() < 3 {
840 return Err(RedisError::WrongArity);
841 }
842
843 args.last().ok_or(RedisError::WrongArity).and_then(|path| {
844 let path = Path::new(path.try_as_str()?);
845 let keys = &args[1..args.len() - 1];
846
847 let to_string =
848 |doc: &M::V| KeyValue::new(doc).to_string_multi(path.get_path(), None, None, None);
849 let to_string_legacy =
850 |doc: &M::V| KeyValue::new(doc).to_string_single(path.get_path(), None, None, None);
851 let is_legacy = path.is_legacy();
852
853 let results: Result<Vec<RedisValue>, RedisError> = keys
854 .iter()
855 .map(|key| {
856 manager
857 .open_key_read(ctx, key)?
858 .get_value()?
859 .map(|doc| {
860 if !is_legacy {
861 to_string(doc)
862 } else {
863 to_string_legacy(doc)
864 }
865 })
866 .transpose()
867 .map_or_else(|_| Ok(RedisValue::Null), |v| Ok(v.into()))
868 })
869 .collect();
870
871 Ok(results?.into())
872 })
873 }
874
command_json_type<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult875 pub fn command_json_type<M: Manager>(
876 manager: M,
877 ctx: &Context,
878 args: Vec<RedisString>,
879 ) -> RedisResult {
880 let mut args = args.into_iter().skip(1);
881 let key = args.next_arg()?;
882 let path = Path::new(args.next_str().unwrap_or(JSON_ROOT_PATH_LEGACY));
883
884 let key = manager.open_key_read(ctx, &key)?;
885
886 if !path.is_legacy() {
887 json_type::<M>(&key, path.get_path())
888 } else {
889 json_type_legacy::<M>(&key, path.get_path())
890 }
891 }
892
json_type<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult where M: Manager,893 fn json_type<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult
894 where
895 M: Manager,
896 {
897 let root = redis_key.get_value()?;
898 let res = match root {
899 Some(root) => KeyValue::new(root)
900 .get_values(path)?
901 .iter()
902 .map(|v| (KeyValue::value_name(*v)).into())
903 .collect::<Vec<RedisValue>>()
904 .into(),
905 None => RedisValue::Null,
906 };
907 Ok(res)
908 }
909
json_type_legacy<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult where M: Manager,910 fn json_type_legacy<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult
911 where
912 M: Manager,
913 {
914 let value = redis_key.get_value()?.map_or_else(
915 || RedisValue::Null,
916 |doc| match KeyValue::new(doc).get_type(path) {
917 Ok(s) => s.into(),
918 Err(_) => RedisValue::Null,
919 },
920 );
921
922 Ok(value)
923 }
924
925 enum NumOp {
926 Incr,
927 Mult,
928 Pow,
929 }
930
command_json_num_op<M>( manager: M, ctx: &Context, args: Vec<RedisString>, cmd: &str, op: NumOp, ) -> RedisResult where M: Manager,931 fn command_json_num_op<M>(
932 manager: M,
933 ctx: &Context,
934 args: Vec<RedisString>,
935 cmd: &str,
936 op: NumOp,
937 ) -> RedisResult
938 where
939 M: Manager,
940 {
941 let mut args = args.into_iter().skip(1);
942
943 let key = args.next_arg()?;
944 let path = Path::new(args.next_str()?);
945 let number = args.next_str()?;
946
947 let mut redis_key = manager.open_key_write(ctx, key)?;
948
949 if !path.is_legacy() {
950 json_num_op::<M>(&mut redis_key, ctx, path.get_path(), number, op, cmd)
951 } else {
952 json_num_op_legacy::<M>(&mut redis_key, ctx, path.get_path(), number, op, cmd)
953 }
954 }
955
json_num_op<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, number: &str, op: NumOp, cmd: &str, ) -> RedisResult where M: Manager,956 fn json_num_op<M>(
957 redis_key: &mut M::WriteHolder,
958 ctx: &Context,
959 path: &str,
960 number: &str,
961 op: NumOp,
962 cmd: &str,
963 ) -> RedisResult
964 where
965 M: Manager,
966 {
967 let root = redis_key
968 .get_value()?
969 .ok_or_else(RedisError::nonexistent_key)?;
970 let paths = find_all_paths(path, root, |v| match v.get_type() {
971 SelectValueType::Double | SelectValueType::Long => true,
972 _ => false,
973 })?;
974
975 let mut res = vec![];
976 let mut need_notify = false;
977 for p in paths {
978 res.push(match p {
979 Some(p) => {
980 need_notify = true;
981 Some(match op {
982 NumOp::Incr => redis_key.incr_by(p, number)?,
983 NumOp::Mult => redis_key.mult_by(p, number)?,
984 NumOp::Pow => redis_key.pow_by(p, number)?,
985 })
986 }
987 _ => None,
988 });
989 }
990 if need_notify {
991 redis_key.apply_changes(ctx, cmd)?;
992 }
993
994 let res = to_json_value::<Number>(res, Value::Null);
995 Ok(KeyValue::<M::V>::serialize_object(&res, None, None, None).into())
996 }
997
json_num_op_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, number: &str, op: NumOp, cmd: &str, ) -> RedisResult where M: Manager,998 fn json_num_op_legacy<M>(
999 redis_key: &mut M::WriteHolder,
1000 ctx: &Context,
1001 path: &str,
1002 number: &str,
1003 op: NumOp,
1004 cmd: &str,
1005 ) -> RedisResult
1006 where
1007 M: Manager,
1008 {
1009 let root = redis_key
1010 .get_value()?
1011 .ok_or_else(RedisError::nonexistent_key)?;
1012 let paths = find_paths(path, root, |v| {
1013 v.get_type() == SelectValueType::Double || v.get_type() == SelectValueType::Long
1014 })?;
1015 if !paths.is_empty() {
1016 let mut res = None;
1017 for p in paths {
1018 res = Some(match op {
1019 NumOp::Incr => redis_key.incr_by(p, number)?,
1020 NumOp::Mult => redis_key.mult_by(p, number)?,
1021 NumOp::Pow => redis_key.pow_by(p, number)?,
1022 });
1023 }
1024 redis_key.apply_changes(ctx, cmd)?;
1025 Ok(res.unwrap().to_string().into())
1026 } else {
1027 Err(RedisError::String(
1028 err_msg_json_path_doesnt_exist_with_param_or(path, "does not contains a number"),
1029 ))
1030 }
1031 }
1032
command_json_num_incrby<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1033 pub fn command_json_num_incrby<M: Manager>(
1034 manager: M,
1035 ctx: &Context,
1036 args: Vec<RedisString>,
1037 ) -> RedisResult {
1038 command_json_num_op(manager, ctx, args, "json.numincrby", NumOp::Incr)
1039 }
1040
command_json_num_multby<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1041 pub fn command_json_num_multby<M: Manager>(
1042 manager: M,
1043 ctx: &Context,
1044 args: Vec<RedisString>,
1045 ) -> RedisResult {
1046 command_json_num_op(manager, ctx, args, "json.nummultby", NumOp::Mult)
1047 }
1048
command_json_num_powby<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1049 pub fn command_json_num_powby<M: Manager>(
1050 manager: M,
1051 ctx: &Context,
1052 args: Vec<RedisString>,
1053 ) -> RedisResult {
1054 command_json_num_op(manager, ctx, args, "json.numpowby", NumOp::Pow)
1055 }
1056
command_json_bool_toggle<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1057 pub fn command_json_bool_toggle<M: Manager>(
1058 manager: M,
1059 ctx: &Context,
1060 args: Vec<RedisString>,
1061 ) -> RedisResult {
1062 let mut args = args.into_iter().skip(1);
1063 let key = args.next_arg()?;
1064 let path = Path::new(args.next_str()?);
1065 let mut redis_key = manager.open_key_write(ctx, key)?;
1066
1067 if !path.is_legacy() {
1068 json_bool_toggle::<M>(&mut redis_key, ctx, path.get_path())
1069 } else {
1070 json_bool_toggle_legacy::<M>(&mut redis_key, ctx, path.get_path())
1071 }
1072 }
1073
json_bool_toggle<M>(redis_key: &mut M::WriteHolder, ctx: &Context, path: &str) -> RedisResult where M: Manager,1074 fn json_bool_toggle<M>(redis_key: &mut M::WriteHolder, ctx: &Context, path: &str) -> RedisResult
1075 where
1076 M: Manager,
1077 {
1078 let root = redis_key
1079 .get_value()?
1080 .ok_or_else(RedisError::nonexistent_key)?;
1081 let paths = find_all_paths(path, root, |v| v.get_type() == SelectValueType::Bool)?;
1082 let mut res: Vec<RedisValue> = vec![];
1083 let mut need_notify = false;
1084 for p in paths {
1085 res.push(match p {
1086 Some(p) => {
1087 need_notify = true;
1088 RedisValue::Integer((redis_key.bool_toggle(p)?).into())
1089 }
1090 None => RedisValue::Null,
1091 });
1092 }
1093 if need_notify {
1094 redis_key.apply_changes(ctx, "json.arrpop")?;
1095 }
1096 Ok(res.into())
1097 }
1098
json_bool_toggle_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, ) -> RedisResult where M: Manager,1099 fn json_bool_toggle_legacy<M>(
1100 redis_key: &mut M::WriteHolder,
1101 ctx: &Context,
1102 path: &str,
1103 ) -> RedisResult
1104 where
1105 M: Manager,
1106 {
1107 let root = redis_key
1108 .get_value()?
1109 .ok_or_else(RedisError::nonexistent_key)?;
1110 let paths = find_paths(path, root, |v| v.get_type() == SelectValueType::Bool)?;
1111 if !paths.is_empty() {
1112 let mut res = false;
1113 for p in paths {
1114 res = redis_key.bool_toggle(p)?;
1115 }
1116 redis_key.apply_changes(ctx, "json.toggle")?;
1117 Ok(res.to_string().into())
1118 } else {
1119 Err(RedisError::String(
1120 err_msg_json_path_doesnt_exist_with_param_or(path, "not a bool"),
1121 ))
1122 }
1123 }
1124
command_json_str_append<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1125 pub fn command_json_str_append<M: Manager>(
1126 manager: M,
1127 ctx: &Context,
1128 args: Vec<RedisString>,
1129 ) -> RedisResult {
1130 let mut args = args.into_iter().skip(1);
1131
1132 let key = args.next_arg()?;
1133 let path_or_json = args.next_str()?;
1134
1135 let path;
1136 let json;
1137
1138 // path is optional
1139 if let Ok(val) = args.next_arg() {
1140 path = Path::new(path_or_json);
1141 json = val.try_as_str()?;
1142 } else {
1143 path = Path::new(JSON_ROOT_PATH_LEGACY);
1144 json = path_or_json;
1145 }
1146
1147 let mut redis_key = manager.open_key_write(ctx, key)?;
1148
1149 if !path.is_legacy() {
1150 json_str_append::<M>(&mut redis_key, ctx, path.get_path(), json)
1151 } else {
1152 json_str_append_legacy::<M>(&mut redis_key, ctx, path.get_path(), json)
1153 }
1154 }
1155
json_str_append<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, json: &str, ) -> RedisResult where M: Manager,1156 fn json_str_append<M>(
1157 redis_key: &mut M::WriteHolder,
1158 ctx: &Context,
1159 path: &str,
1160 json: &str,
1161 ) -> RedisResult
1162 where
1163 M: Manager,
1164 {
1165 let root = redis_key
1166 .get_value()?
1167 .ok_or_else(RedisError::nonexistent_key)?;
1168
1169 let paths = find_all_paths(path, root, |v| v.get_type() == SelectValueType::String)?;
1170
1171 let mut res: Vec<RedisValue> = vec![];
1172 let mut need_notify = false;
1173 for p in paths {
1174 res.push(match p {
1175 Some(p) => {
1176 need_notify = true;
1177 (redis_key.str_append(p, json.to_string())?).into()
1178 }
1179 _ => RedisValue::Null,
1180 });
1181 }
1182 if need_notify {
1183 redis_key.apply_changes(ctx, "json.strappend")?;
1184 }
1185 Ok(res.into())
1186 }
1187
json_str_append_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, json: &str, ) -> RedisResult where M: Manager,1188 fn json_str_append_legacy<M>(
1189 redis_key: &mut M::WriteHolder,
1190 ctx: &Context,
1191 path: &str,
1192 json: &str,
1193 ) -> RedisResult
1194 where
1195 M: Manager,
1196 {
1197 let root = redis_key
1198 .get_value()?
1199 .ok_or_else(RedisError::nonexistent_key)?;
1200
1201 let paths = find_paths(path, root, |v| v.get_type() == SelectValueType::String)?;
1202 if !paths.is_empty() {
1203 let mut res = None;
1204 for p in paths {
1205 res = Some(redis_key.str_append(p, json.to_string())?);
1206 }
1207 redis_key.apply_changes(ctx, "json.strappend")?;
1208 Ok(res.unwrap().into())
1209 } else {
1210 Err(RedisError::String(
1211 err_msg_json_path_doesnt_exist_with_param_or(path, "not a string"),
1212 ))
1213 }
1214 }
1215
command_json_str_len<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1216 pub fn command_json_str_len<M: Manager>(
1217 manager: M,
1218 ctx: &Context,
1219 args: Vec<RedisString>,
1220 ) -> RedisResult {
1221 let mut args = args.into_iter().skip(1);
1222 let key = args.next_arg()?;
1223 let path = Path::new(args.next_str().unwrap_or(JSON_ROOT_PATH_LEGACY));
1224
1225 let key = manager.open_key_read(ctx, &key)?;
1226
1227 if !path.is_legacy() {
1228 json_str_len::<M>(&key, path.get_path())
1229 } else {
1230 json_str_len_legacy::<M>(&key, path.get_path())
1231 }
1232 }
1233
json_str_len<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult where M: Manager,1234 fn json_str_len<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult
1235 where
1236 M: Manager,
1237 {
1238 let root = redis_key
1239 .get_value()?
1240 .ok_or_else(RedisError::nonexistent_key)?;
1241 let values = find_all_values(path, root, |v| v.get_type() == SelectValueType::String)?;
1242 let mut res: Vec<RedisValue> = vec![];
1243 for v in values {
1244 res.push(match v {
1245 Some(v) => (v.get_str().len() as i64).into(),
1246 _ => RedisValue::Null,
1247 });
1248 }
1249 Ok(res.into())
1250 }
1251
json_str_len_legacy<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult where M: Manager,1252 fn json_str_len_legacy<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult
1253 where
1254 M: Manager,
1255 {
1256 match redis_key.get_value()? {
1257 Some(doc) => Ok(RedisValue::Integer(KeyValue::new(doc).str_len(path)? as i64)),
1258 None => Ok(RedisValue::Null),
1259 }
1260 }
1261
command_json_arr_append<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1262 pub fn command_json_arr_append<M: Manager>(
1263 manager: M,
1264 ctx: &Context,
1265 args: Vec<RedisString>,
1266 ) -> RedisResult {
1267 let mut args = args.into_iter().skip(1).peekable();
1268
1269 let key = args.next_arg()?;
1270 let path = Path::new(args.next_str()?);
1271
1272 // We require at least one JSON item to append
1273 args.peek().ok_or(RedisError::WrongArity)?;
1274
1275 let args = args.try_fold::<_, _, Result<_, RedisError>>(
1276 Vec::with_capacity(args.len()),
1277 |mut acc, arg| {
1278 let json = arg.try_as_str()?;
1279 acc.push(manager.from_str(json, Format::JSON)?);
1280 Ok(acc)
1281 },
1282 )?;
1283
1284 let mut redis_key = manager.open_key_write(ctx, key)?;
1285
1286 if !path.is_legacy() {
1287 json_arr_append::<M>(&mut redis_key, ctx, path.get_path(), args)
1288 } else {
1289 json_arr_append_legacy::<M>(&mut redis_key, ctx, &path, args)
1290 }
1291 }
1292
json_arr_append_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &Path, args: Vec<M::O>, ) -> RedisResult where M: Manager,1293 fn json_arr_append_legacy<M>(
1294 redis_key: &mut M::WriteHolder,
1295 ctx: &Context,
1296 path: &Path,
1297 args: Vec<M::O>,
1298 ) -> RedisResult
1299 where
1300 M: Manager,
1301 {
1302 let root = redis_key
1303 .get_value()?
1304 .ok_or_else(RedisError::nonexistent_key)?;
1305 let mut paths = find_paths(path.get_path(), root, |v| {
1306 v.get_type() == SelectValueType::Array
1307 })?;
1308 if paths.is_empty() {
1309 Err(RedisError::String(
1310 err_msg_json_path_doesnt_exist_with_param_or(path.get_original(), "not an array"),
1311 ))
1312 } else if paths.len() == 1 {
1313 let res = redis_key.arr_append(paths.pop().unwrap(), args)?;
1314 redis_key.apply_changes(ctx, "json.arrappend")?;
1315 Ok(res.into())
1316 } else {
1317 let mut res = 0;
1318 for p in paths {
1319 res = redis_key.arr_append(p, args.clone())?;
1320 }
1321 redis_key.apply_changes(ctx, "json.arrappend")?;
1322 Ok(res.into())
1323 }
1324 }
1325
json_arr_append<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, args: Vec<M::O>, ) -> RedisResult where M: Manager,1326 fn json_arr_append<M>(
1327 redis_key: &mut M::WriteHolder,
1328 ctx: &Context,
1329 path: &str,
1330 args: Vec<M::O>,
1331 ) -> RedisResult
1332 where
1333 M: Manager,
1334 {
1335 let root = redis_key
1336 .get_value()?
1337 .ok_or_else(RedisError::nonexistent_key)?;
1338 let paths = find_all_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1339
1340 let mut res = vec![];
1341 let mut need_notify = false;
1342 for p in paths {
1343 res.push(match p {
1344 Some(p) => {
1345 need_notify = true;
1346 (redis_key.arr_append(p, args.clone())? as i64).into()
1347 }
1348 _ => RedisValue::Null,
1349 });
1350 }
1351 if need_notify {
1352 redis_key.apply_changes(ctx, "json.arrappend")?;
1353 }
1354 Ok(res.into())
1355 }
1356
1357 enum FoundIndex {
1358 Index(i64),
1359 NotFound,
1360 NotArray,
1361 }
1362
1363 impl From<FoundIndex> for RedisValue {
from(e: FoundIndex) -> Self1364 fn from(e: FoundIndex) -> Self {
1365 match e {
1366 FoundIndex::NotFound => RedisValue::Integer(-1),
1367 FoundIndex::NotArray => RedisValue::Null,
1368 FoundIndex::Index(i) => RedisValue::Integer(i),
1369 }
1370 }
1371 }
1372
1373 pub enum ObjectLen {
1374 Len(usize),
1375 NoneExisting,
1376 NotObject,
1377 }
1378
command_json_arr_index<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1379 pub fn command_json_arr_index<M: Manager>(
1380 manager: M,
1381 ctx: &Context,
1382 args: Vec<RedisString>,
1383 ) -> RedisResult {
1384 let mut args = args.into_iter().skip(1);
1385
1386 let key = args.next_arg()?;
1387 let path = Path::new(args.next_str()?);
1388 let json_scalar = args.next_str()?;
1389 let start: i64 = args.next().map(|v| v.parse_integer()).unwrap_or(Ok(0))?;
1390 let end: i64 = args.next().map(|v| v.parse_integer()).unwrap_or(Ok(0))?;
1391
1392 args.done()?; // TODO: Add to other functions as well to terminate args list
1393
1394 let key = manager.open_key_read(ctx, &key)?;
1395
1396 let is_legacy = path.is_legacy();
1397 let scalar_value: Value = serde_json::from_str(json_scalar)?;
1398 if !is_legacy && (scalar_value.is_array() || scalar_value.is_object()) {
1399 return Err(RedisError::String(err_msg_json_expected(
1400 "scalar",
1401 json_scalar,
1402 )));
1403 }
1404
1405 let res = key.get_value()?.map_or_else(
1406 || {
1407 Err(Error::from(err_msg_json_path_doesnt_exist_with_param(
1408 path.get_original(),
1409 )))
1410 },
1411 |doc| {
1412 if path.is_legacy() {
1413 KeyValue::new(doc).arr_index_legacy(path.get_path(), scalar_value, start, end)
1414 } else {
1415 KeyValue::new(doc).arr_index(path.get_path(), scalar_value, start, end)
1416 }
1417 },
1418 )?;
1419
1420 Ok(res)
1421 }
1422
command_json_arr_insert<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1423 pub fn command_json_arr_insert<M: Manager>(
1424 manager: M,
1425 ctx: &Context,
1426 args: Vec<RedisString>,
1427 ) -> RedisResult {
1428 let mut args = args.into_iter().skip(1).peekable();
1429
1430 let key = args.next_arg()?;
1431 let path = Path::new(args.next_str()?);
1432 let index = args.next_i64()?;
1433
1434 // We require at least one JSON item to insert
1435 args.peek().ok_or(RedisError::WrongArity)?;
1436 let args = args.try_fold::<_, _, Result<_, RedisError>>(
1437 Vec::with_capacity(args.len()),
1438 |mut acc, arg| {
1439 let json = arg.try_as_str()?;
1440 acc.push(manager.from_str(json, Format::JSON)?);
1441 Ok(acc)
1442 },
1443 )?;
1444 let mut redis_key = manager.open_key_write(ctx, key)?;
1445 if !path.is_legacy() {
1446 json_arr_insert::<M>(&mut redis_key, ctx, path.get_path(), index, args)
1447 } else {
1448 json_arr_insert_legacy::<M>(&mut redis_key, ctx, path.get_path(), index, args)
1449 }
1450 }
1451
json_arr_insert<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, index: i64, args: Vec<M::O>, ) -> RedisResult where M: Manager,1452 fn json_arr_insert<M>(
1453 redis_key: &mut M::WriteHolder,
1454 ctx: &Context,
1455 path: &str,
1456 index: i64,
1457 args: Vec<M::O>,
1458 ) -> RedisResult
1459 where
1460 M: Manager,
1461 {
1462 let root = redis_key
1463 .get_value()?
1464 .ok_or_else(RedisError::nonexistent_key)?;
1465
1466 let paths = find_all_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1467
1468 let mut res: Vec<RedisValue> = vec![];
1469 let mut need_notify = false;
1470 for p in paths {
1471 res.push(match p {
1472 Some(p) => {
1473 need_notify = true;
1474 (redis_key.arr_insert(p, &args, index)? as i64).into()
1475 }
1476 _ => RedisValue::Null,
1477 });
1478 }
1479
1480 if need_notify {
1481 redis_key.apply_changes(ctx, "json.arrinsert")?;
1482 }
1483 Ok(res.into())
1484 }
1485
json_arr_insert_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, index: i64, args: Vec<M::O>, ) -> RedisResult where M: Manager,1486 fn json_arr_insert_legacy<M>(
1487 redis_key: &mut M::WriteHolder,
1488 ctx: &Context,
1489 path: &str,
1490 index: i64,
1491 args: Vec<M::O>,
1492 ) -> RedisResult
1493 where
1494 M: Manager,
1495 {
1496 let root = redis_key
1497 .get_value()?
1498 .ok_or_else(RedisError::nonexistent_key)?;
1499
1500 let paths = find_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1501 if !paths.is_empty() {
1502 let mut res = None;
1503 for p in paths {
1504 res = Some(redis_key.arr_insert(p, &args, index)?);
1505 }
1506 redis_key.apply_changes(ctx, "json.arrinsert")?;
1507 Ok(res.unwrap().into())
1508 } else {
1509 Err(RedisError::String(
1510 err_msg_json_path_doesnt_exist_with_param_or(path, "not an array"),
1511 ))
1512 }
1513 }
1514
command_json_arr_len<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1515 pub fn command_json_arr_len<M: Manager>(
1516 manager: M,
1517 ctx: &Context,
1518 args: Vec<RedisString>,
1519 ) -> RedisResult {
1520 let mut args = args.into_iter().skip(1);
1521 let key = args.next_arg()?;
1522 let path = Path::new(args.next_str().unwrap_or(JSON_ROOT_PATH_LEGACY));
1523 let is_legacy = path.is_legacy();
1524 let key = manager.open_key_read(ctx, &key)?;
1525 let root = match key.get_value()? {
1526 Some(k) => k,
1527 None if is_legacy => {
1528 return Ok(RedisValue::Null);
1529 }
1530 None => {
1531 return Err(RedisError::nonexistent_key());
1532 }
1533 };
1534 let values = find_all_values(path.get_path(), root, |v| {
1535 v.get_type() == SelectValueType::Array
1536 })?;
1537 if is_legacy && values.is_empty() {
1538 return Err(RedisError::String(
1539 err_msg_json_path_doesnt_exist_with_param(path.get_original()),
1540 ));
1541 }
1542 let mut res = vec![];
1543 for v in values {
1544 let cur_val: RedisValue = match v {
1545 Some(v) => (v.len().unwrap() as i64).into(),
1546 _ => {
1547 if !is_legacy {
1548 RedisValue::Null
1549 } else {
1550 return Err(RedisError::String(
1551 err_msg_json_path_doesnt_exist_with_param_or(
1552 path.get_original(),
1553 "not an array",
1554 ),
1555 ));
1556 }
1557 }
1558 };
1559 if !is_legacy {
1560 res.push(cur_val);
1561 } else {
1562 return Ok(cur_val);
1563 }
1564 }
1565 Ok(res.into())
1566 }
1567
command_json_arr_pop<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1568 pub fn command_json_arr_pop<M: Manager>(
1569 manager: M,
1570 ctx: &Context,
1571 args: Vec<RedisString>,
1572 ) -> RedisResult {
1573 let mut args = args.into_iter().skip(1);
1574
1575 let key = args.next_arg()?;
1576
1577 let (path, index) = match args.next() {
1578 None => (Path::new(JSON_ROOT_PATH_LEGACY), i64::MAX),
1579 Some(s) => {
1580 let path = Path::new(s.try_as_str()?);
1581 let index = args.next_i64().unwrap_or(-1);
1582 (path, index)
1583 }
1584 };
1585
1586 let mut redis_key = manager.open_key_write(ctx, key)?;
1587 if !path.is_legacy() {
1588 json_arr_pop::<M>(&mut redis_key, ctx, path.get_path(), index)
1589 } else {
1590 json_arr_pop_legacy::<M>(&mut redis_key, ctx, path.get_path(), index)
1591 }
1592 }
1593
json_arr_pop<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, index: i64, ) -> RedisResult where M: Manager,1594 fn json_arr_pop<M>(
1595 redis_key: &mut M::WriteHolder,
1596 ctx: &Context,
1597 path: &str,
1598 index: i64,
1599 ) -> RedisResult
1600 where
1601 M: Manager,
1602 {
1603 let root = redis_key
1604 .get_value()?
1605 .ok_or_else(RedisError::nonexistent_key)?;
1606
1607 let paths = find_all_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1608 let mut res: Vec<RedisValue> = vec![];
1609 let mut need_notify = false;
1610 for p in paths {
1611 res.push(match p {
1612 Some(p) => match redis_key.arr_pop(p, index)? {
1613 Some(v) => {
1614 need_notify = true;
1615 v.into()
1616 }
1617 _ => RedisValue::Null, // Empty array
1618 },
1619 _ => RedisValue::Null, // Not an array
1620 });
1621 }
1622 if need_notify {
1623 redis_key.apply_changes(ctx, "json.arrpop")?;
1624 }
1625 Ok(res.into())
1626 }
1627
json_arr_pop_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, index: i64, ) -> RedisResult where M: Manager,1628 fn json_arr_pop_legacy<M>(
1629 redis_key: &mut M::WriteHolder,
1630 ctx: &Context,
1631 path: &str,
1632 index: i64,
1633 ) -> RedisResult
1634 where
1635 M: Manager,
1636 {
1637 let root = redis_key
1638 .get_value()?
1639 .ok_or_else(RedisError::nonexistent_key)?;
1640
1641 let paths = find_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1642 if !paths.is_empty() {
1643 let mut res = None;
1644 for p in paths {
1645 res = Some(redis_key.arr_pop(p, index)?);
1646 }
1647 match res.unwrap() {
1648 Some(r) => {
1649 redis_key.apply_changes(ctx, "json.arrpop")?;
1650 Ok(r.into())
1651 }
1652 None => Ok(().into()),
1653 }
1654 } else {
1655 Err(RedisError::String(
1656 err_msg_json_path_doesnt_exist_with_param_or(path, "not an array"),
1657 ))
1658 }
1659 }
1660
command_json_arr_trim<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1661 pub fn command_json_arr_trim<M: Manager>(
1662 manager: M,
1663 ctx: &Context,
1664 args: Vec<RedisString>,
1665 ) -> RedisResult {
1666 let mut args = args.into_iter().skip(1);
1667
1668 let key = args.next_arg()?;
1669 let path = Path::new(args.next_str()?);
1670 let start = args.next_i64()?;
1671 let stop = args.next_i64()?;
1672
1673 let mut redis_key = manager.open_key_write(ctx, key)?;
1674
1675 if !path.is_legacy() {
1676 json_arr_trim::<M>(&mut redis_key, ctx, path.get_path(), start, stop)
1677 } else {
1678 json_arr_trim_legacy::<M>(&mut redis_key, ctx, path.get_path(), start, stop)
1679 }
1680 }
json_arr_trim<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, start: i64, stop: i64, ) -> RedisResult where M: Manager,1681 fn json_arr_trim<M>(
1682 redis_key: &mut M::WriteHolder,
1683 ctx: &Context,
1684 path: &str,
1685 start: i64,
1686 stop: i64,
1687 ) -> RedisResult
1688 where
1689 M: Manager,
1690 {
1691 let root = redis_key
1692 .get_value()?
1693 .ok_or_else(RedisError::nonexistent_key)?;
1694
1695 let paths = find_all_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1696 let mut res: Vec<RedisValue> = vec![];
1697 let mut need_notify = false;
1698 for p in paths {
1699 res.push(match p {
1700 Some(p) => {
1701 need_notify = true;
1702 (redis_key.arr_trim(p, start, stop)?).into()
1703 }
1704 _ => RedisValue::Null,
1705 });
1706 }
1707 if need_notify {
1708 redis_key.apply_changes(ctx, "json.arrtrim")?;
1709 }
1710 Ok(res.into())
1711 }
1712
json_arr_trim_legacy<M>( redis_key: &mut M::WriteHolder, ctx: &Context, path: &str, start: i64, stop: i64, ) -> RedisResult where M: Manager,1713 fn json_arr_trim_legacy<M>(
1714 redis_key: &mut M::WriteHolder,
1715 ctx: &Context,
1716 path: &str,
1717 start: i64,
1718 stop: i64,
1719 ) -> RedisResult
1720 where
1721 M: Manager,
1722 {
1723 let root = redis_key
1724 .get_value()?
1725 .ok_or_else(RedisError::nonexistent_key)?;
1726
1727 let paths = find_paths(path, root, |v| v.get_type() == SelectValueType::Array)?;
1728 if !paths.is_empty() {
1729 let mut res = None;
1730 for p in paths {
1731 res = Some(redis_key.arr_trim(p, start, stop)?);
1732 }
1733 redis_key.apply_changes(ctx, "json.arrtrim")?;
1734 Ok(res.unwrap().into())
1735 } else {
1736 Err(RedisError::String(
1737 err_msg_json_path_doesnt_exist_with_param_or(path, "not an array"),
1738 ))
1739 }
1740 }
1741
command_json_obj_keys<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1742 pub fn command_json_obj_keys<M: Manager>(
1743 manager: M,
1744 ctx: &Context,
1745 args: Vec<RedisString>,
1746 ) -> RedisResult {
1747 let mut args = args.into_iter().skip(1);
1748 let key = args.next_arg()?;
1749 let path = Path::new(args.next_str().unwrap_or(JSON_ROOT_PATH_LEGACY));
1750
1751 let mut key = manager.open_key_read(ctx, &key)?;
1752 if !path.is_legacy() {
1753 json_obj_keys::<M>(&mut key, path.get_path())
1754 } else {
1755 json_obj_keys_legacy::<M>(&mut key, path.get_path())
1756 }
1757 }
1758
json_obj_keys<M>(redis_key: &mut M::ReadHolder, path: &str) -> RedisResult where M: Manager,1759 fn json_obj_keys<M>(redis_key: &mut M::ReadHolder, path: &str) -> RedisResult
1760 where
1761 M: Manager,
1762 {
1763 let root = redis_key
1764 .get_value()?
1765 .ok_or_else(RedisError::nonexistent_key)?;
1766 let res: RedisValue = {
1767 let values = find_all_values(path, root, |v| v.get_type() == SelectValueType::Object)?;
1768 let mut res: Vec<RedisValue> = vec![];
1769 for v in values {
1770 res.push(match v {
1771 Some(v) => v.keys().unwrap().collect::<Vec<&str>>().into(),
1772 _ => RedisValue::Null,
1773 });
1774 }
1775 res.into()
1776 };
1777 Ok(res.into())
1778 }
1779
json_obj_keys_legacy<M>(redis_key: &mut M::ReadHolder, path: &str) -> RedisResult where M: Manager,1780 fn json_obj_keys_legacy<M>(redis_key: &mut M::ReadHolder, path: &str) -> RedisResult
1781 where
1782 M: Manager,
1783 {
1784 let root = match redis_key.get_value()? {
1785 Some(v) => v,
1786 _ => return Ok(RedisValue::Null),
1787 };
1788 let value = match KeyValue::new(root).get_first(path) {
1789 Ok(v) => match v.get_type() {
1790 SelectValueType::Object => v.keys().unwrap().collect::<Vec<&str>>().into(),
1791 _ => {
1792 return Err(RedisError::String(
1793 err_msg_json_path_doesnt_exist_with_param_or(path, "not an object"),
1794 ))
1795 }
1796 },
1797 _ => RedisValue::Null,
1798 };
1799 Ok(value)
1800 }
1801
command_json_obj_len<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1802 pub fn command_json_obj_len<M: Manager>(
1803 manager: M,
1804 ctx: &Context,
1805 args: Vec<RedisString>,
1806 ) -> RedisResult {
1807 let mut args = args.into_iter().skip(1);
1808 let key = args.next_arg()?;
1809 let path = Path::new(args.next_str().unwrap_or(JSON_ROOT_PATH_LEGACY));
1810
1811 let key = manager.open_key_read(ctx, &key)?;
1812 if !path.is_legacy() {
1813 json_obj_len::<M>(&key, path.get_path())
1814 } else {
1815 json_obj_len_legacy::<M>(&key, path.get_path())
1816 }
1817 }
1818
json_obj_len<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult where M: Manager,1819 fn json_obj_len<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult
1820 where
1821 M: Manager,
1822 {
1823 let root = redis_key.get_value()?;
1824 let res = match root {
1825 Some(root) => find_all_values(path, root, |v| v.get_type() == SelectValueType::Object)?
1826 .iter()
1827 .map(|v| match *v {
1828 Some(v) => RedisValue::Integer(v.len().unwrap() as i64),
1829 None => RedisValue::Null,
1830 })
1831 .collect::<Vec<RedisValue>>()
1832 .into(),
1833 None => {
1834 return Err(RedisError::String(
1835 err_msg_json_path_doesnt_exist_with_param_or(path, "not an object"),
1836 ))
1837 }
1838 };
1839 Ok(res)
1840 }
1841
json_obj_len_legacy<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult where M: Manager,1842 fn json_obj_len_legacy<M>(redis_key: &M::ReadHolder, path: &str) -> RedisResult
1843 where
1844 M: Manager,
1845 {
1846 match redis_key.get_value()? {
1847 Some(doc) => match KeyValue::new(doc).obj_len(path)? {
1848 ObjectLen::Len(l) => Ok(RedisValue::Integer(l as i64)),
1849 _ => Ok(RedisValue::Null),
1850 },
1851 None => Ok(RedisValue::Null),
1852 }
1853 }
1854
command_json_clear<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1855 pub fn command_json_clear<M: Manager>(
1856 manager: M,
1857 ctx: &Context,
1858 args: Vec<RedisString>,
1859 ) -> RedisResult {
1860 let mut args = args.into_iter().skip(1);
1861 let key = args.next_arg()?;
1862 let paths = args.try_fold::<_, _, Result<Vec<Path>, RedisError>>(
1863 Vec::with_capacity(args.len()),
1864 |mut acc, arg| {
1865 let s = arg.try_as_str()?;
1866 acc.push(Path::new(s));
1867 Ok(acc)
1868 },
1869 )?;
1870
1871 let paths = if paths.is_empty() {
1872 vec![Path::new(JSON_ROOT_PATH)]
1873 } else {
1874 paths
1875 };
1876
1877 let path = paths.first().unwrap().get_path();
1878
1879 let mut redis_key = manager.open_key_write(ctx, key)?;
1880
1881 let root = redis_key
1882 .get_value()?
1883 .ok_or_else(RedisError::nonexistent_key)?;
1884
1885 let paths = find_paths(path, root, |v| {
1886 v.get_type() == SelectValueType::Array || v.get_type() == SelectValueType::Object
1887 })?;
1888 let mut cleared = 0;
1889 if !paths.is_empty() {
1890 for p in paths {
1891 cleared += redis_key.clear(p)?;
1892 }
1893 }
1894 if cleared > 0 {
1895 redis_key.apply_changes(ctx, "json.clear")?;
1896 }
1897 Ok(cleared.into())
1898 }
1899
command_json_debug<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1900 pub fn command_json_debug<M: Manager>(
1901 manager: M,
1902 ctx: &Context,
1903 args: Vec<RedisString>,
1904 ) -> RedisResult {
1905 let mut args = args.into_iter().skip(1);
1906 match args.next_str()?.to_uppercase().as_str() {
1907 "MEMORY" => {
1908 let key = args.next_arg()?;
1909 let path = Path::new(args.next_str().unwrap_or(JSON_ROOT_PATH_LEGACY));
1910
1911 let key = manager.open_key_read(ctx, &key)?;
1912 if path.is_legacy() {
1913 Ok(match key.get_value()? {
1914 Some(doc) => {
1915 manager.get_memory(KeyValue::new(doc).get_first(path.get_path())?)?
1916 }
1917 None => 0,
1918 }
1919 .into())
1920 } else {
1921 Ok(match key.get_value()? {
1922 Some(doc) => KeyValue::new(doc)
1923 .get_values(path.get_path())?
1924 .iter()
1925 .map(|v| manager.get_memory(v).unwrap())
1926 .collect::<Vec<usize>>(),
1927 None => vec![],
1928 }
1929 .into())
1930 }
1931 }
1932 "HELP" => {
1933 let results = vec![
1934 "MEMORY <key> [path] - reports memory usage",
1935 "HELP - this message",
1936 ];
1937 Ok(results.into())
1938 }
1939 _ => Err(RedisError::Str(
1940 "ERR unknown subcommand - try `JSON.DEBUG HELP`",
1941 )),
1942 }
1943 }
1944
command_json_resp<M: Manager>( manager: M, ctx: &Context, args: Vec<RedisString>, ) -> RedisResult1945 pub fn command_json_resp<M: Manager>(
1946 manager: M,
1947 ctx: &Context,
1948 args: Vec<RedisString>,
1949 ) -> RedisResult {
1950 let mut args = args.into_iter().skip(1);
1951
1952 let key = args.next_arg()?;
1953 let path = match args.next() {
1954 None => Path::new(JSON_ROOT_PATH_LEGACY),
1955 Some(s) => Path::new(s.try_as_str()?),
1956 };
1957
1958 let key = manager.open_key_read(ctx, &key)?;
1959 match key.get_value()? {
1960 Some(doc) => KeyValue::new(doc).resp_serialize(path),
1961 None => Ok(RedisValue::Null),
1962 }
1963 }
1964
command_json_cache_info<M: Manager>( _manager: M, _ctx: &Context, _args: Vec<RedisString>, ) -> RedisResult1965 pub fn command_json_cache_info<M: Manager>(
1966 _manager: M,
1967 _ctx: &Context,
1968 _args: Vec<RedisString>,
1969 ) -> RedisResult {
1970 Err(RedisError::Str("Command was not implemented"))
1971 }
1972
command_json_cache_init<M: Manager>( _manager: M, _ctx: &Context, _args: Vec<RedisString>, ) -> RedisResult1973 pub fn command_json_cache_init<M: Manager>(
1974 _manager: M,
1975 _ctx: &Context,
1976 _args: Vec<RedisString>,
1977 ) -> RedisResult {
1978 Err(RedisError::Str("Command was not implemented"))
1979 }
1980