Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "redisjson"
version = "2.0.3"
version = "2.0.4"
authors = ["Gavrie Philipson <[email protected]>"]
edition = "2018"

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[![GitHub issues](https://img.shields.io/github/release/RedisJSON/RedisJSON.svg)](https://github.com/RedisJSON/RedisJSON/releases/latest)
[![CircleCI](https://circleci.com/gh/RedisJSON/RedisJSON/tree/master.svg?style=svg)](https://circleci.com/gh/RedisJSON/RedisJSON/tree/master)
[![macos](https://github.com/RedisJSON/RedisJSON/workflows/macos/badge.svg)](https://github.com/RedisJSON/RedisJSON/actions?query=workflow%3Amacos)
[![Docker Cloud Build Status](https://img.shields.io/docker/cloud/build/redislabs/rejson.svg)](https://hub.docker.com/r/redislabs/rejson/builds/)
[![Dockerhub](https://img.shields.io/badge/dockerhub-redislabs%2Frejson-blue)](https://hub.docker.com/r/redislabs/rejson/tags/)
[![Total alerts](https://img.shields.io/lgtm/alerts/g/RedisJSON/RedisJSON.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/RedisJSON/RedisJSON/alerts/)

# RedisJSON
[![Forum](https://img.shields.io/badge/Forum-RedisJSON-blue)](https://forum.redislabs.com/c/modules/redisjson)
[![Discord](https://img.shields.io/discord/697882427875393627?style=flat-square)](https://discord.gg/QUkjSsk)

# RedisJSON

RedisJSON is a [Redis](https://redis.io/) module that implements [ECMA-404 The JSON Data Interchange Standard](https://json.org/) as a native data type. It allows storing, updating and fetching JSON values from Redis keys (documents).

Expand Down
53 changes: 50 additions & 3 deletions commands.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
},
{
"name": "path",
"type": "json path string",
"type": "string",
"optional": true
}
],
Expand Down Expand Up @@ -49,11 +49,58 @@
},
{
"name": "paths",
"type": "json path string",
"type": "string",
"optional": true
}
],
"since": "1.0.0",
"group": "json"
},
"JSON.SET": {
"summary": "Sets the JSON value at path in key",
"complexity": "O(M+N), where M is the size of the original value (if it exists) and N is the size of the new value",
"arguments": [
{
"name": "key",
"type": "key"
},
{
"name": "path",
"type": "string"
},
{
"name": "json",
"type": "string"
},
{
"name": "condition",
"type": "enum",
"enum": [
"NX",
"XX"
],
"optional": true
}
],
"since": "1.0.0",
"group": "json"
},
"JSON.OBJLEN": {
"summary": "Report the number of keys in the JSON Object at path in key",
"complexity": "O(1)",
"arguments": [
{
"name": "key",
"type": "key"
},
{
"name": "path",
"type": "string",
"optional": true
}
],
"since": "1.0.0",
"group": "json"
}
}

}
63 changes: 33 additions & 30 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::redisjson::SetOptions;
use serde_json::{Number, Value};

use itertools::FoldWhile::{Continue, Done};
use itertools::Itertools;
use itertools::{EitherOrBoth, Itertools};
use serde::{Serialize, Serializer};
use std::collections::HashMap;

Expand Down Expand Up @@ -758,40 +758,43 @@ where
.collect::<Vec<Value>>()
}

/// Sort the paths so higher indices precede lower indices on the same on the same array
/// And objects with higher hierarchy (closer to the top-level) preceded objects with deeper hierarchy
/// Sort the paths so higher indices precede lower indices on the same array,
/// 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
fn prepare_paths_for_deletion(paths: &mut Vec<Vec<String>>) {
paths.sort_by(|v1, v2| match (v1.len(), v2.len()) {
(l1, l2) if l1 < l2 => Ordering::Less, // Shorter paths before longer paths
(l1, l2) if l1 > l2 => Ordering::Greater, // Shorter paths before longer paths
_ => v1
.iter()
.zip(v2.iter())
.fold_while(Ordering::Equal, |_acc, (p1, p2)| {
let i1 = p1.parse::<usize>();
let i2 = p2.parse::<usize>();
match (i1, i2) {
(Err(_), Err(_)) => match p1.cmp(p2) {
// String compare
Ordering::Less => Done(Ordering::Less),
Ordering::Equal => Continue(Ordering::Equal),
Ordering::Greater => Done(Ordering::Greater),
},
(Ok(_), Err(_)) => Done(Ordering::Greater), //String before Numeric
(Err(_), Ok(_)) => Done(Ordering::Less), //String before Numeric
(Ok(i1), Ok(i2)) => {
// Numeric compare - higher indices before lower ones
if i1 < i2 {
Done(Ordering::Greater)
} else if i2 < i1 {
Done(Ordering::Less)
} else {
Continue(Ordering::Equal)
paths.sort_by(|v1, v2| {
v1.iter()
.zip_longest(v2.iter())
.fold_while(Ordering::Equal, |_acc, v| {
match v {
EitherOrBoth::Left(_) => Done(Ordering::Greater), // Shorter paths before longer paths
EitherOrBoth::Right(_) => Done(Ordering::Less), // Shorter paths before longer paths
EitherOrBoth::Both(p1, p2) => {
let i1 = p1.parse::<usize>();
let i2 = p2.parse::<usize>();
match (i1, i2) {
(Err(_), Err(_)) => match p1.cmp(p2) {
// String compare
Ordering::Less => Done(Ordering::Less),
Ordering::Equal => Continue(Ordering::Equal),
Ordering::Greater => Done(Ordering::Greater),
},
(Ok(_), Err(_)) => Done(Ordering::Greater), //String before Numeric
(Err(_), Ok(_)) => Done(Ordering::Less), //String before Numeric
(Ok(i1), Ok(i2)) => {
// Numeric compare - higher indices before lower ones
if i1 < i2 {
Done(Ordering::Greater)
} else if i2 < i1 {
Done(Ordering::Less)
} else {
Continue(Ordering::Equal)
}
}
}
}
}
})
.into_inner(),
.into_inner()
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,6 @@ redis_json_module_create! {
data_types: [REDIS_JSON_TYPE],
pre_command_function: pre_command,
get_manage: Some(manager::RedisJsonKeyManager{phantom:PhantomData}),
version: 02_00_03,
version: 02_00_04,
init: dummy_init,
}
12 changes: 12 additions & 0 deletions tests/pytest/test_multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ def testDelCommand(env):
res = r.execute_command('JSON.DEL', 'doc2', '$[2,1,0]')
r.assertEqual(res, 3)

r.assertOk(r.execute_command('JSON.SET', 'doc2', '$', '[1, 2, 3]'))
res = r.execute_command('JSON.DEL', 'doc2', '$[1,2,0]')
r.assertEqual(res, 3)

r.assertOk(r.execute_command('JSON.SET', 'doc2', '$', '{"b": [1,2,3], "a": {"b": [1, 2, 3], "c": [1, 2, 3]}, "x": {"b": [1, 2, 3], "c": [1, 2, 3]}}'))
res = r.execute_command('JSON.DEL', 'doc2', '$..x.b[*]')
r.assertEqual(res, 3)
Expand All @@ -88,6 +92,14 @@ def testDelCommand(env):
res = r.execute_command('JSON.GET', 'doc2', '$')
r.assertEqual(json.loads(res), [[True, {"answer": 42}]])

def testDelCommand_issue529(env):
r = env
r.assertOk(r.execute_command('JSON.SET', 'doc1', '$', '[{"a00": [{"a00": "a00_00"}, {"a01": "a00_01"}, {"a02": "a00_02"}, {"a03": "a00_03"}]}, {"a01": [{"a00": "a01_00"}, {"a01": "a01_01"}, {"a02": "a01_02"}, {"a03": "a01_03"}]}, {"a02": [{"a00": "a02_00"}, {"a01": "a02_01"}, {"a02": "a02_02"}, {"a03": "a02_03"}]}, {"a03": [{"a00": "a03_00"}, {"a01": "a03_01"}, {"a02": "a03_02"}, {"a03": "a03_03"}]}]'))
res = r.execute_command('JSON.DEL', 'doc1', '$..[2]')
r.assertEqual(res, 4)
res = r.execute_command('JSON.ARRLEN', 'doc1', '$.*[*]')
r.assertEqual(res, [3, 3, 3])


def testForgetCommand(env):
"""Test REJSON.FORGET command"""
Expand Down