Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support JSON.MERGE Command #3429

Merged
merged 28 commits into from
May 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b1188fc
Support JSON.MERGE Command
shacharPash May 18, 2023
10d860f
add comment
shacharPash May 21, 2023
c747d54
add Merge test to JsonV1Test
shacharPash May 21, 2023
f7a7a77
add test to V2 + fixes
shacharPash May 21, 2023
791893e
fix tests
shacharPash May 21, 2023
2e6fd25
change to new Path("$")
shacharPash May 21, 2023
6ed1c7c
wip
shacharPash May 21, 2023
b612b32
Merge branch 'master' into SP/Jedis/SupportJSON.MERGE
shacharPash May 21, 2023
bf2013b
Support JSON.MERGE Command
shacharPash May 18, 2023
8cf2166
add comment
shacharPash May 21, 2023
584d2b1
add Merge test to JsonV1Test
shacharPash May 21, 2023
cebfb50
add test to V2 + fixes
shacharPash May 21, 2023
8abf0eb
fix tests
shacharPash May 21, 2023
71e96e9
change to new Path("$")
shacharPash May 21, 2023
451191d
wip
shacharPash May 21, 2023
c4cf743
uncommend V2 test and delete tostrings
shacharPash May 21, 2023
6f862fe
Merge branch 'master' into SP/Jedis/SupportJSON.MERGE
shacharPash May 21, 2023
5a3a03a
Merge branch 'SP/Jedis/SupportJSON.MERGE' of https://github.com/shach…
shacharPash May 21, 2023
a4d8431
complete merge
shacharPash May 22, 2023
9a78369
merge after set
shacharPash May 22, 2023
58d227c
fix V1 tests
shacharPash May 22, 2023
3d01e35
tring to fix test
shacharPash May 24, 2023
6d88699
review
shacharPash May 28, 2023
6226297
Merge branch 'master' into SP/Jedis/SupportJSON.MERGE
shacharPash May 28, 2023
155a033
add jsonMerge to PipelineBase
shacharPash May 28, 2023
6eb7f63
undo formatting white spaces
sazzad16 May 28, 2023
916749f
empty line
sazzad16 May 28, 2023
6b56d90
empty line
sazzad16 May 28, 2023
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
9 changes: 9 additions & 0 deletions src/main/java/redis/clients/jedis/CommandObjects.java
Original file line number Diff line number Diff line change
Expand Up @@ -3401,6 +3401,15 @@ public final CommandObject<String> jsonSet(String key, Path path, Object pojo, J
getJsonObjectMapper().toJson(pojo)).addParams(params), BuilderFactory.STRING);
}

public final CommandObject<String> jsonMerge(String key, Path2 path, Object object) {
return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(object), BuilderFactory.STRING);
}

public final CommandObject<String> jsonMerge(String key, Path path, Object pojo) {
return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(
getJsonObjectMapper().toJson(pojo)), BuilderFactory.STRING);
}

public final CommandObject<Object> jsonGet(String key) {
return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), new JsonObjectBuilder<>(Object.class));
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/redis/clients/jedis/PipelineBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -3458,6 +3458,16 @@ public Response<String> jsonSet(String key, Path path, Object object, JsonSetPar
return appendCommand(commandObjects.jsonSet(key, path, object, params));
}

@Override
public Response<String> jsonMerge(String key, Path2 path, Object object) {
return appendCommand(commandObjects.jsonMerge(key, path, object));
}

@Override
public Response<String> jsonMerge(String key, Path path, Object object) {
return appendCommand(commandObjects.jsonMerge(key, path, object));
}

@Override
public Response<Object> jsonGet(String key) {
return appendCommand(commandObjects.jsonGet(key));
Expand Down
12 changes: 11 additions & 1 deletion src/main/java/redis/clients/jedis/TransactionBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public abstract class TransactionBase implements PipelineCommands, PipelineBinar

/**
* Creates a new transaction.
*
*
* A MULTI command will be added to be sent to server. WATCH/UNWATCH/MULTI commands must not be
* called with this object.
* @param connection connection
Expand Down Expand Up @@ -3626,6 +3626,16 @@ public Response<String> jsonSet(String key, Path path, Object object, JsonSetPar
return appendCommand(commandObjects.jsonSet(key, path, object, params));
}

@Override
public Response<String> jsonMerge(String key, Path2 path, Object object) {
return appendCommand(commandObjects.jsonMerge(key, path, object));
}

@Override
public Response<String> jsonMerge(String key, Path path, Object object) {
return appendCommand(commandObjects.jsonMerge(key, path, object));
}

@Override
public Response<Object> jsonGet(String key) {
return appendCommand(commandObjects.jsonGet(key));
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/redis/clients/jedis/UnifiedJedis.java
Original file line number Diff line number Diff line change
Expand Up @@ -3902,6 +3902,16 @@ public String jsonSet(String key, Path path, Object pojo, JsonSetParams params)
return executeCommand(commandObjects.jsonSet(key, path, pojo, params));
}

@Override
public String jsonMerge(String key, Path2 path, Object object) {
return executeCommand(commandObjects.jsonMerge(key, path, object));
}

@Override
public String jsonMerge(String key, Path path, Object pojo) {
return executeCommand(commandObjects.jsonMerge(key, path, pojo));
}

@Override
public Object jsonGet(String key) {
return executeCommand(commandObjects.jsonGet(key));
Expand Down
1 change: 1 addition & 0 deletions src/main/java/redis/clients/jedis/json/JsonProtocol.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum JsonCommand implements ProtocolCommand {
DEL("JSON.DEL"),
GET("JSON.GET"),
MGET("JSON.MGET"),
MERGE("JSON.MERGE"),
SET("JSON.SET"),
TYPE("JSON.TYPE"),
STRAPPEND("JSON.STRAPPEND"),
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/redis/clients/jedis/json/RedisJsonCommands.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ default String jsonSetLegacy(String key, Object pojo, JsonSetParams params) {

String jsonSet(String key, Path path, Object pojo, JsonSetParams params);

String jsonMerge(String key, Path2 path, Object object);

String jsonMerge(String key, Path path, Object pojo);

Object jsonGet(String key);

<T> T jsonGet(String key, Class<T> clazz);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ default Response<String> jsonSetLegacy(String key, Object pojo, JsonSetParams pa

Response<String> jsonSet(String key, Path path, Object pojo, JsonSetParams params);

Response<String> jsonMerge(String key, Path2 path, Object object);

Response<String> jsonMerge(String key, Path path, Object pojo);

Response<Object> jsonGet(String key);

<T> Response<T> jsonGet(String key, Class<T> clazz);
Expand Down
43 changes: 42 additions & 1 deletion src/test/java/redis/clients/jedis/modules/json/JsonObjects.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package redis.clients.jedis.modules.json;

import java.time.Instant;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public class JsonObjects {
Expand Down Expand Up @@ -102,15 +104,54 @@ public boolean equals(Object o) {
}

public static class Person {
public String name;
public int age;
public String address;
public String phone;
public List<String> childrens;

public Person(String name, int age, String address, String phone, List<String> childrens) {
this.name = name;
this.age = age;
this.address = address;
this.phone = phone;
this.childrens = childrens;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
// if (getClass() != o.getClass()) {
// return false;
// }
Person other = (Person) o;

return Objects.equals(name, other.name)
&& Objects.equals(age, other.age)
&& Objects.equals(address, other.address)
&& Objects.equals(phone, other.phone)
&& Objects.equals(childrens, other.childrens);
}
}

public static class Tick {
private final String id;
private final Instant created;
public Person(String id, Instant created) {

public Tick(String id, Instant created) {
this.id = id;
this.created = created;
}

public String getId() {
return id;
}

public Instant getCreated() {
return created;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.google.gson.JsonObject;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -186,6 +187,25 @@ public void typeChecksShouldSucceed() {
assertNull(client.jsonType("foobar", Path.of(".fooErr")));
}

@Test
public void testJsonMerge() {
// create data
List<String> childrens = new ArrayList<>();
childrens.add("Child 1");
Person person = new Person("John Doe", 25, "123 Main Street", "123-456-7890", childrens);
assertEquals("OK", client.jsonSet("test_merge", ROOT_PATH, person));

// After 5 years:
person.age = 30;
person.childrens.add("Child 2");
person.childrens.add("Child 3");

// merge the new data
assertEquals("OK", client.jsonMerge("test_merge", Path.of((".childrens")), person.childrens));
assertEquals("OK", client.jsonMerge("test_merge", Path.of((".age")), person.age));
assertEquals(person, client.jsonGet("test_merge", Person.class));
}

@Test
public void mgetWithPathWithAllKeysExist() {
Baz baz1 = new Baz("quuz1", "grault1", "waldo1");
Expand Down Expand Up @@ -501,7 +521,7 @@ public void resp() {

@Test
public void testJsonGsonParser() {
Person person = new Person("foo", Instant.now());
Tick person = new Tick("foo", Instant.now());

// setting the custom json gson parser
client.setJsonObjectMapper(JsonObjectMapperTestUtil.getCustomGsonObjectMapper());
Expand All @@ -514,7 +534,7 @@ public void testJsonGsonParser() {

@Test
public void testDefaultJsonGsonParserStringsMustBeDifferent() {
Person person = new Person("foo", Instant.now());
Tick person = new Tick("foo", Instant.now());

// using the default json gson parser which is automatically configured

Expand All @@ -526,7 +546,7 @@ public void testDefaultJsonGsonParserStringsMustBeDifferent() {

@Test
public void testJsonJacksonParser() {
Person person = new Person("foo", Instant.now());
Tick person = new Tick("foo", Instant.now());

// setting the custom json jackson parser
client.setJsonObjectMapper(JsonObjectMapperTestUtil.getCustomJacksonObjectMapper());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,57 @@ public void typeChecksShouldSucceed() {
assertEquals(Collections.emptyList(), client.jsonType("foobar", Path2.of(".fooErr")));
}

@Test
public void testJsonMerge() {
shacharPash marked this conversation as resolved.
Show resolved Hide resolved
// Test with root path
JSONObject json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"age\":25,\"address\":{\"home\":\"123 Main Street\"},\"phone\":\"123-456-7890\"}}");
assertEquals("OK", client.jsonSet("test_merge", json));

json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"age\":30,\"address\":{\"home\":\"123 Main Street\"},\"phone\":\"123-456-7890\"}}");
assertEquals("OK", client.jsonMerge("test_merge", Path2.of("$"), "{\"person\":{\"age\":30}}"));

assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge", Path2.of("$")));

// Test with root path path $.a.b
assertEquals("OK", client.jsonMerge("test_merge", Path2.of("$.person.address"), "{\"work\":\"Redis office\"}"));
json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"age\":30,\"address\":{\"home\":\"123 Main Street\",\"work\":\"Redis office\"},\"phone\":\"123-456-7890\"}}");
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge", Path2.of("$")));

// Test with null value to delete a value
assertEquals("OK", client.jsonMerge("test_merge", Path2.of("$.person"), "{\"age\":null}"));
json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"address\":{\"home\":\"123 Main Street\",\"work\":\"Redis office\"},\"phone\":\"123-456-7890\"}}");
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge", Path2.of("$")));

// cleanup
assertEquals(1L, client.del("test_merge"));
}

@Test
public void testJsonMergeArray()
{
// Test merge on an array
JSONObject json = new JSONObject("{\"a\":{\"b\":{\"c\":[\"d\",\"e\"]}}}");
assertEquals("OK", (client.jsonSet("test_merge_array", Path2.of("$"), json)));
assertEquals("OK", (client.jsonMerge("test_merge_array", Path2.of("$.a.b.c"), "[\"f\"]")));

json = new JSONObject("{\"a\":{\"b\":{\"c\":[\"f\"]}}}");
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge_array", Path2.of("$")));

// assertEquals("{{a={b={c=[f]}}}", client.jsonGet("test_merge_array", Path2.of("$")));

// Test merge an array on a value
assertEquals("OK", (client.jsonSet("test_merge_array", Path2.of("$"), "{\"a\":{\"b\":{\"c\":\"d\"}}}")));
assertEquals("OK", (client.jsonMerge("test_merge_array", Path2.of("$.a.b.c"), "[\"f\"]")));
json = new JSONObject("{\"a\":{\"b\":{\"c\":[\"f\"]}}}");
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge_array", Path2.of("$")));

// Test with null value to delete an array value
assertEquals("OK", (client.jsonSet("test_merge_array", Path2.of("$"), "{\"a\":{\"b\":{\"c\":[\"d\",\"e\"]}}}")));
assertEquals("OK", (client.jsonMerge("test_merge_array", Path2.of("$.a.b"), "{\"c\":null}")));
json = new JSONObject("{\"a\":{\"b\":{}}}");
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge_array", Path2.of("$")));
}

@Test
public void mgetWithPathWithAllKeysExist() {
Baz baz1 = new Baz("quuz1", "grault1", "waldo1");
Expand Down