2929package com .redislabs .modules .rejson ;
3030
3131import java .util .ArrayList ;
32- import java .util .Collections ;
32+ import java .util .Arrays ;
3333import java .util .List ;
3434import java .util .stream .Collectors ;
3535import java .util .stream .Stream ;
3838
3939import redis .clients .jedis .Jedis ;
4040import redis .clients .jedis .JedisPool ;
41+ import redis .clients .jedis .Protocol ;
4142import redis .clients .jedis .commands .ProtocolCommand ;
4243import redis .clients .jedis .util .Pool ;
4344import redis .clients .jedis .util .SafeEncoder ;
@@ -54,7 +55,15 @@ private enum Command implements ProtocolCommand {
5455 GET ("JSON.GET" ),
5556 MGET ("JSON.MGET" ),
5657 SET ("JSON.SET" ),
57- TYPE ("JSON.TYPE" );
58+ TYPE ("JSON.TYPE" ),
59+ STRAPPEND ("JSON.STRAPPEND" ),
60+ STRLEN ("JSON.STRLEN" ),
61+ ARRAPPEND ("JSON.ARRAPPEND" ),
62+ ARRINDEX ("JSON.ARRINDEX" ),
63+ ARRINSERT ("JSON.ARRINSERT" ),
64+ ARRLEN ("JSON.ARRLEN" ),
65+ ARRPOP ("JSON.ARRPOP" ),
66+ ARRTRIM ("JSON.ARRTRIM" );
5867 private final byte [] raw ;
5968
6069 Command (String alt ) {
@@ -192,6 +201,7 @@ public <T> T get(String key) {
192201 * @return the requested object
193202 * @deprecated use {@link #get(String, Class, Path...)} instead
194203 */
204+ @ SuppressWarnings ("unchecked" )
195205 @ Deprecated
196206 public <T > T get (String key , Path ... paths ) {
197207 return (T )this .get (key , Object .class , paths );
@@ -224,7 +234,7 @@ public <T> T get(String key, Class<T> clazz, Path... paths) {
224234 /**
225235 * Returns the documents from multiple keys. Non-existing keys are reported as
226236 * null.
227- *
237+ *
228238 * @param <T> target class to serialize results
229239 * @param clazz target class to serialize results
230240 * @param keys keys for the JSON documents
@@ -237,7 +247,7 @@ public <T> List<T> mget(Class<T> clazz, String... keys) {
237247 /**
238248 * Returns the values at path from multiple keys. Non-existing keys and
239249 * non-existing paths are reported as null.
240- *
250+ *
241251 * @param path common path across all documents to root the results on
242252 * @param <T> target class to serialize results
243253 * @param clazz target class to serialize results
@@ -368,7 +378,6 @@ public Class<?> type(String key, Path path) {
368378 }
369379 }
370380
371-
372381 /**
373382 * Deletes a path
374383 * @param conn the Jedis connection
@@ -508,4 +517,252 @@ public static Class<?> type(Jedis conn, String key, Path... path) {
508517 private Jedis getConnection () {
509518 return this .client .getResource ();
510519 }
520+
521+ /**
522+ * Append the value(s) the string at path.
523+ *
524+ * Returns the string's new size.
525+ *
526+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonstrappend}</a>.
527+ *
528+ * @param key the key of the value
529+ * @param path the path of the value
530+ * @param objects objects One or more elements to be added to the array
531+ * @return the size of the modified string
532+ */
533+ public Long strAppend (String key , Path path , Object ... objects ) {
534+ List <byte []> args = new ArrayList <>();
535+ args .add (SafeEncoder .encode (key ));
536+ args .add (SafeEncoder .encode (getSingleOptionalPath (path ).toString ()));
537+
538+ args .addAll (Arrays .stream (objects ) //
539+ .map (object -> SafeEncoder .encode (gson .toJson (object ))) //
540+ .collect (Collectors .toList ()));
541+
542+ try (Jedis conn = getConnection ()) {
543+ conn .getClient ().sendCommand (Command .STRAPPEND , args .toArray (new byte [args .size ()][]));
544+ return conn .getClient ().getIntegerReply ();
545+ }
546+ }
547+
548+ /**
549+ * Report the length of the JSON String at path in key.
550+ * Path defaults to root if not provided.
551+ *
552+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonstrlen}</a>.
553+ *
554+ * @param key the key of the value
555+ * @param path the path of the value
556+ * @return the size of string at path. If the key or path do not exist, null is returned.
557+ */
558+ public Long strLen (String key , Path path ) {
559+ byte [][] args = new byte [2 ][];
560+ args [0 ] = SafeEncoder .encode (key );
561+ args [1 ] = SafeEncoder .encode (path .toString ());
562+
563+ try (Jedis conn = getConnection ()) {
564+ conn .getClient ().sendCommand (Command .STRLEN , args );
565+ return conn .getClient ().getIntegerReply ();
566+ }
567+ }
568+
569+ /**
570+ * Appends elements into the array at path.
571+ *
572+ * Returns the array's new size.
573+ *
574+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrappend}</a>.
575+ *
576+ * @param key the key of the value
577+ * @param path the path of the value
578+ * @param objects one or more elements to be added to the array
579+ * @return the size of the modified array
580+ */
581+ public Long arrAppend (String key , Path path , Object ... objects ) {
582+ List <byte []> args = new ArrayList <>();
583+ args .add (SafeEncoder .encode (key ));
584+ args .add (SafeEncoder .encode (getSingleOptionalPath (path ).toString ()));
585+
586+ args .addAll (Arrays .stream (objects ) //
587+ .map (object -> SafeEncoder .encode (gson .toJson (object ))) //
588+ .collect (Collectors .toList ()));
589+
590+ try (Jedis conn = getConnection ()) {
591+ conn .getClient ().sendCommand (Command .ARRAPPEND , args .toArray (new byte [args .size ()][]));
592+ return conn .getClient ().getIntegerReply ();
593+ }
594+ }
595+
596+ /**
597+ * Finds the index of the first occurrence of a scalar JSON value in the array
598+ * at the given path.
599+ *
600+ * If the item is not found, it returns -1. If called on a key path that is not
601+ * an array, it throws an error.
602+ *
603+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrindex}</a>.
604+ *
605+ * @param key the key of the value
606+ * @param path the path of the value
607+ * @param scalar the JSON scalar to search for
608+ * @return the index of the element if found, -1 if not found
609+ */
610+ public Long arrIndex (String key , Path path , Object scalar ) {
611+ byte [][] args = new byte [3 ][];
612+ args [0 ] = SafeEncoder .encode (key );
613+ args [1 ] = SafeEncoder .encode (path .toString ());
614+ args [2 ] = SafeEncoder .encode (gson .toJson (scalar ));
615+
616+ try (Jedis conn = getConnection ()) {
617+ conn .getClient ().sendCommand (Command .ARRINDEX , args );
618+ return conn .getClient ().getIntegerReply ();
619+ }
620+ }
621+
622+ /**
623+ * Insert element(s) into the array at path before the index (shifts to the right).
624+ * The index must be in the array's range. Inserting at index 0 prepends to the array.
625+ * Negative index values are interpreted as starting from the end.
626+ *
627+ * Returns the array's new size.
628+ *
629+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrinsert}</a>.
630+ *
631+ * @param key the key of the value
632+ * @param path the path of the value
633+ * @param index position in the array to insert the value(s)
634+ * @param objects one or more elements to be added to the array
635+ * @return the size of the modified array
636+ */
637+ public Long arrInsert (String key , Path path , Long index , Object ... objects ) {
638+ List <byte []> args = new ArrayList <>();
639+ args .add (SafeEncoder .encode (key ));
640+ args .add (SafeEncoder .encode (getSingleOptionalPath (path ).toString ()));
641+ args .add (Protocol .toByteArray (index ));
642+
643+ args .addAll (Arrays .stream (objects ) //
644+ .map (object -> SafeEncoder .encode (gson .toJson (object ))) //
645+ .collect (Collectors .toList ()));
646+
647+ try (Jedis conn = getConnection ()) {
648+ conn .getClient ().sendCommand (Command .ARRINSERT , args .toArray (new byte [args .size ()][]));
649+ return conn .getClient ().getIntegerReply ();
650+ }
651+ }
652+
653+ /**
654+ * Get the number of elements for an array field (for a given path)
655+ *
656+ * If called on a key path that is not an array, it will throw an error.
657+ *
658+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrlen}</a>.
659+ *
660+ * @param key the key of the value
661+ * @param path the path of the value
662+ * @return the size of array at path
663+ */
664+ public Long arrLen (String key , Path path ) {
665+ byte [][] args = new byte [2 ][];
666+ args [0 ] = SafeEncoder .encode (key );
667+ args [1 ] = SafeEncoder .encode (path .toString ());
668+
669+ try (Jedis conn = getConnection ()) {
670+ conn .getClient ().sendCommand (Command .ARRLEN , args );
671+ return conn .getClient ().getIntegerReply ();
672+ }
673+ }
674+
675+ /**
676+ * Remove and return element from the index in the array.
677+ *
678+ * path defaults to root if not provided. index is the position in the array to start
679+ * popping from (defaults to -1, meaning the last element). Out of range indices are
680+ * rounded to their respective array ends. Popping an empty array yields null.
681+ *
682+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrpop}</a>.
683+ *
684+ * @param key the key of the value
685+ * @param clazz target class to serialize results
686+ * @param path the path of the value
687+ * @param index the position in the array to start popping from
688+ * @return the popped JSON value.
689+ */
690+ public <T > T arrPop (String key , Class <T > clazz , Path path , Long index ) {
691+ List <byte []> args = new ArrayList <>();
692+ args .add (SafeEncoder .encode (key ));
693+ args .add (SafeEncoder .encode (path != null ? path .toString () :Path .ROOT_PATH .toString ()));
694+ args .add (Protocol .toByteArray (index != null ? index : -1 ));
695+
696+ String rep ;
697+ try (Jedis conn = getConnection ()) {
698+ conn .getClient ().sendCommand (Command .ARRPOP , args .toArray (new byte [args .size ()][]));
699+ rep = conn .getClient ().getBulkReply ();
700+ }
701+ assertReplyNotError (rep );
702+ return gson .fromJson (rep , clazz );
703+ }
704+
705+ /**
706+ * Remove and return element from the index in the array.
707+ *
708+ * path defaults to root if not provided. index is the position in the array to start
709+ * popping from (defaults to -1, meaning the last element). Out of range indices are
710+ * rounded to their respective array ends. Popping an empty array yields null.
711+ *
712+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrpop}</a>.
713+ *
714+ * @param key the key of the value
715+ * @param clazz target class to serialize results
716+ * @param path the path of the value
717+ * @return the popped JSON value.
718+ */
719+ public <T > T arrPop (String key , Class <T > clazz , Path path ) {
720+ return arrPop (key , clazz , path , null );
721+ }
722+
723+ /**
724+ * Remove and return element from the index in the array.
725+ *
726+ * path defaults to root if not provided. index is the position in the array to start
727+ * popping from (defaults to -1, meaning the last element). Out of range indices are
728+ * rounded to their respective array ends. Popping an empty array yields null.
729+ *
730+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrpop}</a>.
731+ *
732+ * @param key the key of the value
733+ * @param clazz target class to serialize results
734+ * @return the popped JSON value.
735+ */
736+ public <T > T arrPop (String key , Class <T > clazz ) {
737+ return arrPop (key , clazz , null , null );
738+ }
739+
740+ /**
741+ * Trim an array so that it contains only the specified inclusive range of elements.
742+ *
743+ * This command is extremely forgiving and using it with out of range indexes will not
744+ * produce an error. If start is larger than the array's size or start > stop , the result
745+ * will be an empty array. If start is < 0 then it will be treated as 0. If stop is larger
746+ * than the end of the array, it will be treated like the last element in it.
747+ *
748+ * See <a href="#{@link}">{@link https://oss.redislabs.com/redisjson/commands/#jsonarrtrim}</a>.
749+ *
750+ * @param key the key of the value
751+ * @param path the path of the value
752+ * @param start the start of the range
753+ * @param stop the end of the range
754+ * @return the array's new size
755+ */
756+ public Long arrTrim (String key , Path path , Long start , Long stop ) {
757+ List <byte []> args = new ArrayList <>();
758+ args .add (SafeEncoder .encode (key ));
759+ args .add (SafeEncoder .encode (getSingleOptionalPath (path ).toString ()));
760+ args .add (Protocol .toByteArray (start ));
761+ args .add (Protocol .toByteArray (stop ));
762+
763+ try (Jedis conn = getConnection ()) {
764+ conn .getClient ().sendCommand (Command .ARRTRIM , args .toArray (new byte [args .size ()][]));
765+ return conn .getClient ().getIntegerReply ();
766+ }
767+ }
511768}
0 commit comments