Skip to content

Commit a6ec2b9

Browse files
Support JSON.MERGE Command (#3429)
Co-authored-by: M Sazzadul Hoque <7600764+sazzad16@users.noreply.github.com>
1 parent d0a89d4 commit a6ec2b9

File tree

10 files changed

+165
-5
lines changed

10 files changed

+165
-5
lines changed

src/main/java/redis/clients/jedis/CommandObjects.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3401,6 +3401,15 @@ public final CommandObject<String> jsonSet(String key, Path path, Object pojo, J
34013401
getJsonObjectMapper().toJson(pojo)).addParams(params), BuilderFactory.STRING);
34023402
}
34033403

3404+
public final CommandObject<String> jsonMerge(String key, Path2 path, Object object) {
3405+
return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(object), BuilderFactory.STRING);
3406+
}
3407+
3408+
public final CommandObject<String> jsonMerge(String key, Path path, Object pojo) {
3409+
return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(
3410+
getJsonObjectMapper().toJson(pojo)), BuilderFactory.STRING);
3411+
}
3412+
34043413
public final CommandObject<Object> jsonGet(String key) {
34053414
return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), new JsonObjectBuilder<>(Object.class));
34063415
}

src/main/java/redis/clients/jedis/PipelineBase.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3458,6 +3458,16 @@ public Response<String> jsonSet(String key, Path path, Object object, JsonSetPar
34583458
return appendCommand(commandObjects.jsonSet(key, path, object, params));
34593459
}
34603460

3461+
@Override
3462+
public Response<String> jsonMerge(String key, Path2 path, Object object) {
3463+
return appendCommand(commandObjects.jsonMerge(key, path, object));
3464+
}
3465+
3466+
@Override
3467+
public Response<String> jsonMerge(String key, Path path, Object object) {
3468+
return appendCommand(commandObjects.jsonMerge(key, path, object));
3469+
}
3470+
34613471
@Override
34623472
public Response<Object> jsonGet(String key) {
34633473
return appendCommand(commandObjects.jsonGet(key));

src/main/java/redis/clients/jedis/TransactionBase.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public abstract class TransactionBase implements PipelineCommands, PipelineBinar
5353

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

3629+
@Override
3630+
public Response<String> jsonMerge(String key, Path2 path, Object object) {
3631+
return appendCommand(commandObjects.jsonMerge(key, path, object));
3632+
}
3633+
3634+
@Override
3635+
public Response<String> jsonMerge(String key, Path path, Object object) {
3636+
return appendCommand(commandObjects.jsonMerge(key, path, object));
3637+
}
3638+
36293639
@Override
36303640
public Response<Object> jsonGet(String key) {
36313641
return appendCommand(commandObjects.jsonGet(key));

src/main/java/redis/clients/jedis/UnifiedJedis.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3902,6 +3902,16 @@ public String jsonSet(String key, Path path, Object pojo, JsonSetParams params)
39023902
return executeCommand(commandObjects.jsonSet(key, path, pojo, params));
39033903
}
39043904

3905+
@Override
3906+
public String jsonMerge(String key, Path2 path, Object object) {
3907+
return executeCommand(commandObjects.jsonMerge(key, path, object));
3908+
}
3909+
3910+
@Override
3911+
public String jsonMerge(String key, Path path, Object pojo) {
3912+
return executeCommand(commandObjects.jsonMerge(key, path, pojo));
3913+
}
3914+
39053915
@Override
39063916
public Object jsonGet(String key) {
39073917
return executeCommand(commandObjects.jsonGet(key));

src/main/java/redis/clients/jedis/json/JsonProtocol.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public enum JsonCommand implements ProtocolCommand {
99
DEL("JSON.DEL"),
1010
GET("JSON.GET"),
1111
MGET("JSON.MGET"),
12+
MERGE("JSON.MERGE"),
1213
SET("JSON.SET"),
1314
TYPE("JSON.TYPE"),
1415
STRAPPEND("JSON.STRAPPEND"),

src/main/java/redis/clients/jedis/json/RedisJsonCommands.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ default String jsonSetLegacy(String key, Object pojo, JsonSetParams params) {
4343

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

46+
String jsonMerge(String key, Path2 path, Object object);
47+
48+
String jsonMerge(String key, Path path, Object pojo);
49+
4650
Object jsonGet(String key);
4751

4852
<T> T jsonGet(String key, Class<T> clazz);

src/main/java/redis/clients/jedis/json/RedisJsonPipelineCommands.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ default Response<String> jsonSetLegacy(String key, Object pojo, JsonSetParams pa
4747

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

50+
Response<String> jsonMerge(String key, Path2 path, Object object);
51+
52+
Response<String> jsonMerge(String key, Path path, Object pojo);
53+
5054
Response<Object> jsonGet(String key);
5155

5256
<T> Response<T> jsonGet(String key, Class<T> clazz);

src/test/java/redis/clients/jedis/modules/json/JsonObjects.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package redis.clients.jedis.modules.json;
22

33
import java.time.Instant;
4+
import java.util.List;
5+
import java.util.Map;
46
import java.util.Objects;
57

68
public class JsonObjects {
@@ -102,15 +104,54 @@ public boolean equals(Object o) {
102104
}
103105

104106
public static class Person {
107+
public String name;
108+
public int age;
109+
public String address;
110+
public String phone;
111+
public List<String> childrens;
112+
113+
public Person(String name, int age, String address, String phone, List<String> childrens) {
114+
this.name = name;
115+
this.age = age;
116+
this.address = address;
117+
this.phone = phone;
118+
this.childrens = childrens;
119+
}
120+
121+
@Override
122+
public boolean equals(Object o) {
123+
if (this == o) {
124+
return true;
125+
}
126+
if (o == null) {
127+
return false;
128+
}
129+
// if (getClass() != o.getClass()) {
130+
// return false;
131+
// }
132+
Person other = (Person) o;
133+
134+
return Objects.equals(name, other.name)
135+
&& Objects.equals(age, other.age)
136+
&& Objects.equals(address, other.address)
137+
&& Objects.equals(phone, other.phone)
138+
&& Objects.equals(childrens, other.childrens);
139+
}
140+
}
141+
142+
public static class Tick {
105143
private final String id;
106144
private final Instant created;
107-
public Person(String id, Instant created) {
145+
146+
public Tick(String id, Instant created) {
108147
this.id = id;
109148
this.created = created;
110149
}
150+
111151
public String getId() {
112152
return id;
113153
}
154+
114155
public Instant getCreated() {
115156
return created;
116157
}

src/test/java/redis/clients/jedis/modules/json/RedisJsonV1Test.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.google.gson.JsonObject;
1010

1111
import java.time.Instant;
12+
import java.util.ArrayList;
1213
import java.util.Arrays;
1314
import java.util.Collections;
1415
import java.util.List;
@@ -186,6 +187,25 @@ public void typeChecksShouldSucceed() {
186187
assertNull(client.jsonType("foobar", Path.of(".fooErr")));
187188
}
188189

190+
@Test
191+
public void testJsonMerge() {
192+
// create data
193+
List<String> childrens = new ArrayList<>();
194+
childrens.add("Child 1");
195+
Person person = new Person("John Doe", 25, "123 Main Street", "123-456-7890", childrens);
196+
assertEquals("OK", client.jsonSet("test_merge", ROOT_PATH, person));
197+
198+
// After 5 years:
199+
person.age = 30;
200+
person.childrens.add("Child 2");
201+
person.childrens.add("Child 3");
202+
203+
// merge the new data
204+
assertEquals("OK", client.jsonMerge("test_merge", Path.of((".childrens")), person.childrens));
205+
assertEquals("OK", client.jsonMerge("test_merge", Path.of((".age")), person.age));
206+
assertEquals(person, client.jsonGet("test_merge", Person.class));
207+
}
208+
189209
@Test
190210
public void mgetWithPathWithAllKeysExist() {
191211
Baz baz1 = new Baz("quuz1", "grault1", "waldo1");
@@ -501,7 +521,7 @@ public void resp() {
501521

502522
@Test
503523
public void testJsonGsonParser() {
504-
Person person = new Person("foo", Instant.now());
524+
Tick person = new Tick("foo", Instant.now());
505525

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

515535
@Test
516536
public void testDefaultJsonGsonParserStringsMustBeDifferent() {
517-
Person person = new Person("foo", Instant.now());
537+
Tick person = new Tick("foo", Instant.now());
518538

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

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

527547
@Test
528548
public void testJsonJacksonParser() {
529-
Person person = new Person("foo", Instant.now());
549+
Tick person = new Tick("foo", Instant.now());
530550

531551
// setting the custom json jackson parser
532552
client.setJsonObjectMapper(JsonObjectMapperTestUtil.getCustomJacksonObjectMapper());

src/test/java/redis/clients/jedis/modules/json/RedisJsonV2Test.java

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,57 @@ public void typeChecksShouldSucceed() {
181181
assertEquals(Collections.emptyList(), client.jsonType("foobar", Path2.of(".fooErr")));
182182
}
183183

184+
@Test
185+
public void testJsonMerge() {
186+
// Test with root path
187+
JSONObject json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"age\":25,\"address\":{\"home\":\"123 Main Street\"},\"phone\":\"123-456-7890\"}}");
188+
assertEquals("OK", client.jsonSet("test_merge", json));
189+
190+
json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"age\":30,\"address\":{\"home\":\"123 Main Street\"},\"phone\":\"123-456-7890\"}}");
191+
assertEquals("OK", client.jsonMerge("test_merge", Path2.of("$"), "{\"person\":{\"age\":30}}"));
192+
193+
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge", Path2.of("$")));
194+
195+
// Test with root path path $.a.b
196+
assertEquals("OK", client.jsonMerge("test_merge", Path2.of("$.person.address"), "{\"work\":\"Redis office\"}"));
197+
json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"age\":30,\"address\":{\"home\":\"123 Main Street\",\"work\":\"Redis office\"},\"phone\":\"123-456-7890\"}}");
198+
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge", Path2.of("$")));
199+
200+
// Test with null value to delete a value
201+
assertEquals("OK", client.jsonMerge("test_merge", Path2.of("$.person"), "{\"age\":null}"));
202+
json = new JSONObject("{\"person\":{\"name\":\"John Doe\",\"address\":{\"home\":\"123 Main Street\",\"work\":\"Redis office\"},\"phone\":\"123-456-7890\"}}");
203+
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge", Path2.of("$")));
204+
205+
// cleanup
206+
assertEquals(1L, client.del("test_merge"));
207+
}
208+
209+
@Test
210+
public void testJsonMergeArray()
211+
{
212+
// Test merge on an array
213+
JSONObject json = new JSONObject("{\"a\":{\"b\":{\"c\":[\"d\",\"e\"]}}}");
214+
assertEquals("OK", (client.jsonSet("test_merge_array", Path2.of("$"), json)));
215+
assertEquals("OK", (client.jsonMerge("test_merge_array", Path2.of("$.a.b.c"), "[\"f\"]")));
216+
217+
json = new JSONObject("{\"a\":{\"b\":{\"c\":[\"f\"]}}}");
218+
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge_array", Path2.of("$")));
219+
220+
// assertEquals("{{a={b={c=[f]}}}", client.jsonGet("test_merge_array", Path2.of("$")));
221+
222+
// Test merge an array on a value
223+
assertEquals("OK", (client.jsonSet("test_merge_array", Path2.of("$"), "{\"a\":{\"b\":{\"c\":\"d\"}}}")));
224+
assertEquals("OK", (client.jsonMerge("test_merge_array", Path2.of("$.a.b.c"), "[\"f\"]")));
225+
json = new JSONObject("{\"a\":{\"b\":{\"c\":[\"f\"]}}}");
226+
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge_array", Path2.of("$")));
227+
228+
// Test with null value to delete an array value
229+
assertEquals("OK", (client.jsonSet("test_merge_array", Path2.of("$"), "{\"a\":{\"b\":{\"c\":[\"d\",\"e\"]}}}")));
230+
assertEquals("OK", (client.jsonMerge("test_merge_array", Path2.of("$.a.b"), "{\"c\":null}")));
231+
json = new JSONObject("{\"a\":{\"b\":{}}}");
232+
assertJsonArrayEquals(jsonArray(json), client.jsonGet("test_merge_array", Path2.of("$")));
233+
}
234+
184235
@Test
185236
public void mgetWithPathWithAllKeysExist() {
186237
Baz baz1 = new Baz("quuz1", "grault1", "waldo1");

0 commit comments

Comments
 (0)