diff --git a/content/develop/data-types/json/path.md b/content/develop/data-types/json/path.md index b2a2ca64be..78e04c9ffc 100644 --- a/content/develop/data-types/json/path.md +++ b/content/develop/data-types/json/path.md @@ -71,18 +71,18 @@ Beginning with Redis 8.10, the JSON data type supports a richer JSONPath syntax, - [`in` and `nin`](#membership-in-and-nin) operators: membership test on an array and nodelist - [Operators on numbers](#arithmetic-operators): binary `-`, `+`, `*`, `/`, `%`, and unary `-` and `+` - Operator on object: [`~`](#get-keys-operator-) -- `length()` function on array, object, and string -- Functions on number: `abs()`, `ceiling()`, `floor()` -- Functions on string: `match()`, `search()` -- Strings concatenation with `concat()` -- Functions on array: `first()`, `last()`, `index()`, `append()` -- Aggregation functions on array: `min()`, `max()`, `avg()`, `sum()`, `stddev()` -- Function on object: `keys()` -- Function on nodelist: `count()` -- Function on nodelist with exactly one node: `value()` +- [`length()`](#length) function on array, object, and string +- Functions on number: [`abs()`, `ceiling()`, `floor()`](#abs-ceiling-and-floor) +- Functions on string: [`match()`, `search()`](#match-and-search) +- Strings concatenation with [`concat()`](#concat) +- Functions on array: [`first()`, `last()`, `index()`](#first-last-and-index), [`append()`](#append) +- Aggregation functions on array: [`min()`, `max()`, `avg()`, `sum()`, `stddev()`](#min-max-avg-sum-and-stddev) +- Function on object: [`keys()`](#keys) +- Function on nodelist: [`count()`](#count) +- Function on nodelist with exactly one node: [`value()`](#value) - Relations functions on array and nodelist: [`subsetof()`, `anyof()`, `noneof()`](#set-relations-subsetof-anyof-and-noneof) -These operators can be used within a filter expression (`?()`). +These operators can be used within a filter expression (`?()`). Functions can appear inside filter expressions and, when they return a value, as top-level [projection expressions](#projection-expressions). A function can be written in prefix form, `length($.arr)`, or in postfix (method) form, `$.arr.length()`. A path segment immediately followed by `(` is a method call, so `$.arr.length()` is a function call while `$.arr.length` is a reference to a field named `length`. {{< warning >}} Beginning with Redis 8.10, two changes to path parsing may affect existing queries: @@ -101,144 +101,6 @@ The following rules apply to the operators and functions described below: - **Arithmetic operators must be surrounded by spaces.** `@.a + 1` is addition, but `@.a+1` is a reference to a field literally named `a+1`, because the field-name character set includes characters such as `+`, `-`, `/`, `%`, `$`, `^`, `:`, and `_`. - **Functions are arity-checked.** Calling a function with the wrong number of arguments produces *Nothing* rather than silently using a subset of the arguments. -## Functions - -Functions can appear inside filter expressions and, when they return a value, as top-level [projection expressions](#projection-expressions). A function can be written in prefix form, `length($.arr)`, or in postfix (method) form, `$.arr.length()`. A path segment immediately followed by `(` is a method call, so `$.arr.length()` is a function call while `$.arr.length` is a reference to a field named `length`. - -### `length()` - -Returns the number of characters in a string, elements in an array, or members in an object. Any other type produces *Nothing*. - -``` -> JSON.SET doc $ '{"a":[[1,2,3],[1],"abcd","x"]}' -OK -> JSON.GET doc '$.a[?length(@) > 2]' -"[[1,2,3],\"abcd\"]" -``` - -### `count()` - -Returns the number of nodes selected by a query. An absent path counts as `0`; a single node counts as `1`. - -``` -> JSON.SET doc $ '[{"a":1,"b":2,"c":3},{"a":1}]' -OK -> JSON.GET doc '$[?count(@.*) == 3]' -"[{\"a\":1,\"b\":2,\"c\":3}]" -``` - -### `value()` - -Returns the value of a query that selects exactly one node. A query that selects zero or more than one node produces *Nothing*. - -``` -> JSON.SET doc $ '[{"a":1},{"a":2}]' -OK -> JSON.GET doc '$[?value(@.a) == 1]' -"[{\"a\":1}]" -``` - -### `keys()` - -Returns the member names of an object as a list of strings, like the `~` operator. Unlike `~`, `keys()` is composable and can be chained with other functions. - -``` -> JSON.SET doc $ '{"obj":{"x":1,"y":2}}' -OK -> JSON.GET doc '$.obj.keys()' -"[\"x\",\"y\"]" -> JSON.GET doc '$.obj.keys().count()' -"[2]" -``` - -### `match()` and `search()` - -Both test a string against a regular expression pattern ([RFC 9485](https://datatracker.ietf.org/doc/rfc9485/) I-Regexp). `match()` requires the whole string to match (anchored), while `search()` matches any substring (the same behavior as the `=~` operator). An invalid pattern produces no match. - -``` -> JSON.SET doc $ '{"a":["abc","xabc","a","b"]}' -OK -> JSON.GET doc '$.a[?match(@, "a.*")]' -"[\"abc\",\"a\"]" -> JSON.SET doc $ '{"a":["abc","xyz","b"]}' -OK -> JSON.GET doc '$.a[?search(@, "b")]' -"[\"abc\",\"b\"]" -``` - -### `concat()` - -Concatenates its string arguments into a single string. It requires at least one argument, and any non-string argument produces *Nothing*. - -``` -> JSON.SET doc $ '{"a":[{"x":"a","y":"b"},{"x":"a","y":"c"}]}' -OK -> JSON.GET doc '$.a[?concat(@.x, @.y) == "ab"]' -"[{\"x\":\"a\",\"y\":\"b\"}]" -``` - -### `abs()`, `ceiling()`, and `floor()` - -Operate on a number: `abs()` returns the absolute value, `ceiling()` rounds up to the nearest integer, and `floor()` rounds down. An integer argument stays an integer and a floating-point argument stays a float. A result that overflows the signed 64-bit integer range produces *Nothing*. - -``` -> JSON.SET doc $ '{"a":[2.1,3.9,1.0]}' -OK -> JSON.GET doc '$.a[?ceiling(@) == 3]' -"[2.1]" -> JSON.SET doc $ '{"a":[2.1,2.9,3.5]}' -OK -> JSON.GET doc '$.a[?floor(@) == 2]' -"[2.1,2.9]" -> JSON.SET doc $ '{"a":[{"n":-5},{"n":5},{"n":-3}]}' -OK -> JSON.GET doc '$.a[?abs(@.n) == 5]' -"[{\"n\":-5},{\"n\":5}]" -``` - -### `first()`, `last()`, and `index()` - -`first(array)` and `last(array)` return the first and last element of an array. `index(array, n)` returns the element at index `n`; a negative `n` counts from the end, a fractional `n` is truncated toward zero, and an out-of-range index produces *Nothing*. - -``` -> JSON.SET doc $ '{"a":[{"n":[1,2]},{"n":[9,8]}]}' -OK -> JSON.GET doc '$.a[?first(@.n) == 1]' -"[{\"n\":[1,2]}]" -> JSON.GET doc '$.a[?last(@.n) == 8]' -"[{\"n\":[9,8]}]" -> JSON.GET doc '$.a[?index(@.n, -1) == 2]' -"[{\"n\":[1,2]}]" -``` - -### `min()`, `max()`, `avg()`, `sum()`, and `stddev()` - -These aggregation functions operate on an array of numbers. `stddev()` returns the *population* standard deviation (dividing by N). The functions are strict: an array that contains any non-numeric element, or an empty array, produces *Nothing* — elements are never silently skipped. - -``` -> JSON.SET doc $ '{"a":[{"n":[3,1,2]},{"n":[5,6]}]}' -OK -> JSON.GET doc '$.a[?sum(@.n) == 6]' -"[{\"n\":[3,1,2]}]" -> JSON.GET doc '$.a[?avg(@.n) == 2]' -"[{\"n\":[3,1,2]}]" -``` - -### `append()` - -`append(value, ...)` returns the matched array with the given value or values added after its elements. It is a read-only query-time projection and does not modify the stored document — to mutate an array in place, use the [`JSON.ARRAPPEND`]({{< relref "commands/json.arrappend/" >}}) command instead. A multiple-value argument is added as a single element (it is not spread), and a *Nothing* argument makes the whole result *Nothing*. - -``` -> JSON.SET doc $ '{"arr":[1,2,3]}' -OK -> JSON.GET doc '$.arr.append(9)' -"[1,2,3,9]" -> JSON.SET doc $ '{"books":[{"t":"a","price":30},{"t":"b","price":5}]}' -OK -> JSON.GET doc '$.books[?(@.price >= 10)].append({"t":"X"})' -"[{\"t\":\"a\",\"price\":30},{\"t\":\"X\"}]" -``` - ## JSONPath examples The following examples use this JSON document, which stores details about items in a store's inventory: @@ -516,6 +378,142 @@ OK "[]" {{< /clients-example >}} +Functions can appear inside filter expressions and, when they return a value, as top-level [projection expressions](#projection-expressions). Beginning with Redis 8.10, JSONPath supports the following functions. + +#### `length()` + +Returns the number of characters in a string, elements in an array, or members in an object. Any other type produces *Nothing*. + +{{< clients-example set="json_path_ops" step="func_length" description="Length function: Use length() to get the number of characters in a string, elements in an array, or members in an object" difficulty="advanced" >}} +> JSON.SET doc $ '{"a":[[1,2,3],[1],"abcd","x"]}' +OK +> JSON.GET doc '$.a[?length(@) > 2]' +"[[1,2,3],\"abcd\"]" +{{< /clients-example >}} + +#### `count()` + +Returns the number of nodes selected by a query. An absent path counts as `0`; a single node counts as `1`. + +{{< clients-example set="json_path_ops" step="func_count" description="Count function: Use count() to get the number of nodes selected by a query" difficulty="advanced" >}} +> JSON.SET doc $ '[{"a":1,"b":2,"c":3},{"a":1}]' +OK +> JSON.GET doc '$[?count(@.*) == 3]' +"[{\"a\":1,\"b\":2,\"c\":3}]" +{{< /clients-example >}} + +#### `value()` + +Returns the value of a query that selects exactly one node. A query that selects zero or more than one node produces *Nothing*. + +{{< clients-example set="json_path_ops" step="func_value" description="Value function: Use value() to get the value of a query that selects exactly one node" difficulty="advanced" >}} +> JSON.SET doc $ '[{"a":1},{"a":2}]' +OK +> JSON.GET doc '$[?value(@.a) == 1]' +"[{\"a\":1}]" +{{< /clients-example >}} + +#### `keys()` + +Returns the member names of an object as a list of strings, like the `~` operator. Unlike `~`, `keys()` is composable and can be chained with other functions. + +{{< clients-example set="json_path_ops" step="func_keys" description="Keys function: Use keys() to get an object's member names as a composable, chainable list of strings" difficulty="advanced" >}} +> JSON.SET doc $ '{"obj":{"x":1,"y":2}}' +OK +> JSON.GET doc '$.obj.keys()' +"[\"x\",\"y\"]" +> JSON.GET doc '$.obj.keys().count()' +"[2]" +{{< /clients-example >}} + +#### `match()` and `search()` + +Both test a string against a regular expression pattern ([RFC 9485](https://datatracker.ietf.org/doc/rfc9485/) I-Regexp). `match()` requires the whole string to match (anchored), while `search()` matches any substring (the same behavior as the `=~` operator). An invalid pattern produces no match. + +{{< clients-example set="json_path_ops" step="func_match_search" description="Regex functions: Use match() for an anchored (whole-string) regular expression match and search() for a partial match" difficulty="advanced" >}} +> JSON.SET doc $ '{"a":["abc","xabc","a","b"]}' +OK +> JSON.GET doc '$.a[?match(@, "a.*")]' +"[\"abc\",\"a\"]" +> JSON.SET doc $ '{"a":["abc","xyz","b"]}' +OK +> JSON.GET doc '$.a[?search(@, "b")]' +"[\"abc\",\"b\"]" +{{< /clients-example >}} + +#### `concat()` + +Concatenates its string arguments into a single string. It requires at least one argument, and any non-string argument produces *Nothing*. + +{{< clients-example set="json_path_ops" step="func_concat" description="Concat function: Use concat() to join string arguments into a single string for comparison in a filter" difficulty="advanced" >}} +> JSON.SET doc $ '{"a":[{"x":"a","y":"b"},{"x":"a","y":"c"}]}' +OK +> JSON.GET doc '$.a[?concat(@.x, @.y) == "ab"]' +"[{\"x\":\"a\",\"y\":\"b\"}]" +{{< /clients-example >}} + +#### `abs()`, `ceiling()`, and `floor()` + +Operate on a number: `abs()` returns the absolute value, `ceiling()` rounds up to the nearest integer, and `floor()` rounds down. An integer argument stays an integer and a floating-point argument stays a float. A result that overflows the signed 64-bit integer range produces *Nothing*. + +{{< clients-example set="json_path_ops" step="func_math" description="Numeric functions: Use abs(), ceiling(), and floor() to transform a number before comparing it in a filter" difficulty="advanced" >}} +> JSON.SET doc $ '{"a":[2.1,3.9,1.0]}' +OK +> JSON.GET doc '$.a[?ceiling(@) == 3]' +"[2.1]" +> JSON.SET doc $ '{"a":[2.1,2.9,3.5]}' +OK +> JSON.GET doc '$.a[?floor(@) == 2]' +"[2.1,2.9]" +> JSON.SET doc $ '{"a":[{"n":-5},{"n":5},{"n":-3}]}' +OK +> JSON.GET doc '$.a[?abs(@.n) == 5]' +"[{\"n\":-5},{\"n\":5}]" +{{< /clients-example >}} + +#### `first()`, `last()`, and `index()` + +`first(array)` and `last(array)` return the first and last element of an array. `index(array, n)` returns the element at index `n`; a negative `n` counts from the end, a fractional `n` is truncated toward zero, and an out-of-range index produces *Nothing*. + +{{< clients-example set="json_path_ops" step="func_array_access" description="Array access functions: Use first(), last(), and index() to pick a single element out of an array before comparing it" difficulty="advanced" >}} +> JSON.SET doc $ '{"a":[{"n":[1,2]},{"n":[9,8]}]}' +OK +> JSON.GET doc '$.a[?first(@.n) == 1]' +"[{\"n\":[1,2]}]" +> JSON.GET doc '$.a[?last(@.n) == 8]' +"[{\"n\":[9,8]}]" +> JSON.GET doc '$.a[?index(@.n, -1) == 2]' +"[{\"n\":[1,2]}]" +{{< /clients-example >}} + +#### `min()`, `max()`, `avg()`, `sum()`, and `stddev()` + +These aggregation functions operate on an array of numbers. `stddev()` returns the *population* standard deviation (dividing by N). The functions are strict: an array that contains any non-numeric element, or an empty array, produces *Nothing* — elements are never silently skipped. + +{{< clients-example set="json_path_ops" step="func_aggregate" description="Aggregation functions: Use sum(), avg(), min(), max(), or stddev() to reduce an array of numbers to a single value in a filter" difficulty="advanced" >}} +> JSON.SET doc $ '{"a":[{"n":[3,1,2]},{"n":[5,6]}]}' +OK +> JSON.GET doc '$.a[?sum(@.n) == 6]' +"[{\"n\":[3,1,2]}]" +> JSON.GET doc '$.a[?avg(@.n) == 2]' +"[{\"n\":[3,1,2]}]" +{{< /clients-example >}} + +#### `append()` + +`append(value, ...)` returns the matched array with the given value or values added after its elements. It is a read-only query-time projection and does not modify the stored document — to mutate an array in place, use the [`JSON.ARRAPPEND`]({{< relref "commands/json.arrappend/" >}}) command instead. A multiple-value argument is added as a single element (it is not spread), and a *Nothing* argument makes the whole result *Nothing*. + +{{< clients-example set="json_path_ops" step="func_append" description="Append function: Use append() as a read-only, query-time projection that adds a value after an array's elements without modifying the stored document" difficulty="advanced" >}} +> JSON.SET doc $ '{"arr":[1,2,3]}' +OK +> JSON.GET doc '$.arr.append(9)' +"[1,2,3,9]" +> JSON.SET doc $ '{"books":[{"t":"a","price":30},{"t":"b","price":5}]}' +OK +> JSON.GET doc '$.books[?(@.price >= 10)].append({"t":"X"})' +"[{\"t\":\"a\",\"price\":30},{\"t\":\"X\"}]" +{{< /clients-example >}} + ### Update examples You can also use JSONPath queries when you want to update specific sections of a JSON document. diff --git a/local_examples/json_path_ops/go-redis/json_path_ops_test.go b/local_examples/json_path_ops/go-redis/json_path_ops_test.go index 658d67f1e6..dccdb409e1 100644 --- a/local_examples/json_path_ops/go-redis/json_path_ops_test.go +++ b/local_examples/json_path_ops/go-redis/json_path_ops_test.go @@ -442,3 +442,509 @@ func ExampleClient_json_path_ops_filter_getkeys() { // ["obj","books"] // [] } + +func ExampleClient_json_path_ops_func_length() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_length + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[[1,2,3],[1],"abcd","x"]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.a[?length(@) > 2]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [[1,2,3],"abcd"] + // STEP_END + + // Output: + // OK + // [[1,2,3],"abcd"] +} + +func ExampleClient_json_path_ops_func_count() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_count + res1, err := rdb.JSONSet(ctx, "doc", "$", + `[{"a":1,"b":2,"c":3},{"a":1}]`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$[?count(@.*) == 3]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [{"a":1,"b":2,"c":3}] + // STEP_END + + // Output: + // OK + // [{"a":1,"b":2,"c":3}] +} + +func ExampleClient_json_path_ops_func_value() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_value + res1, err := rdb.JSONSet(ctx, "doc", "$", + `[{"a":1},{"a":2}]`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$[?value(@.a) == 1]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [{"a":1}] + // STEP_END + + // Output: + // OK + // [{"a":1}] +} + +func ExampleClient_json_path_ops_func_keys() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_keys + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"obj":{"x":1,"y":2}}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.obj.keys()`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> ["x","y"] + + res3, err := rdb.JSONGet(ctx, "doc", `$.obj.keys().count()`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res3) // >>> [2] + // STEP_END + + // Output: + // OK + // ["x","y"] + // [2] +} + +func ExampleClient_json_path_ops_func_match_search() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_match_search + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":["abc","xabc","a","b"]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.a[?match(@, "a.*")]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> ["abc","a"] + + res3, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":["abc","xyz","b"]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res3) // >>> OK + + res4, err := rdb.JSONGet(ctx, "doc", `$.a[?search(@, "b")]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res4) // >>> ["abc","b"] + // STEP_END + + // Output: + // OK + // ["abc","a"] + // OK + // ["abc","b"] +} + +func ExampleClient_json_path_ops_func_concat() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_concat + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[{"x":"a","y":"b"},{"x":"a","y":"c"}]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.a[?concat(@.x, @.y) == "ab"]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [{"x":"a","y":"b"}] + // STEP_END + + // Output: + // OK + // [{"x":"a","y":"b"}] +} + +func ExampleClient_json_path_ops_func_math() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_math + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[2.1,3.9,1.0]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.a[?ceiling(@) == 3]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [2.1] + + res3, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[2.1,2.9,3.5]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res3) // >>> OK + + res4, err := rdb.JSONGet(ctx, "doc", `$.a[?floor(@) == 2]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res4) // >>> [2.1,2.9] + + res5, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[{"n":-5},{"n":5},{"n":-3}]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res5) // >>> OK + + res6, err := rdb.JSONGet(ctx, "doc", `$.a[?abs(@.n) == 5]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res6) // >>> [{"n":-5},{"n":5}] + // STEP_END + + // Output: + // OK + // [2.1] + // OK + // [2.1,2.9] + // OK + // [{"n":-5},{"n":5}] +} + +func ExampleClient_json_path_ops_func_array_access() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_array_access + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[{"n":[1,2]},{"n":[9,8]}]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.a[?first(@.n) == 1]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [{"n":[1,2]}] + + res3, err := rdb.JSONGet(ctx, "doc", `$.a[?last(@.n) == 8]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res3) // >>> [{"n":[9,8]}] + + res4, err := rdb.JSONGet(ctx, "doc", `$.a[?index(@.n, -1) == 2]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res4) // >>> [{"n":[1,2]}] + // STEP_END + + // Output: + // OK + // [{"n":[1,2]}] + // [{"n":[9,8]}] + // [{"n":[1,2]}] +} + +func ExampleClient_json_path_ops_func_aggregate() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_aggregate + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"a":[{"n":[3,1,2]},{"n":[5,6]}]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.a[?sum(@.n) == 6]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [{"n":[3,1,2]}] + + res3, err := rdb.JSONGet(ctx, "doc", `$.a[?avg(@.n) == 2]`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res3) // >>> [{"n":[3,1,2]}] + // STEP_END + + // Output: + // OK + // [{"n":[3,1,2]}] + // [{"n":[3,1,2]}] +} + +func ExampleClient_json_path_ops_func_append() { + ctx := context.Background() + + rdb := redis.NewClient(&redis.Options{ + Addr: "localhost:6379", + Password: "", // no password docs + DB: 0, // use default DB + }) + + // REMOVE_START + rdb.FlushDB(ctx) + rdb.Del(ctx, "doc") + // REMOVE_END + + // STEP_START func_append + res1, err := rdb.JSONSet(ctx, "doc", "$", + `{"arr":[1,2,3]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res1) // >>> OK + + res2, err := rdb.JSONGet(ctx, "doc", `$.arr.append(9)`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res2) // >>> [1,2,3,9] + + res3, err := rdb.JSONSet(ctx, "doc", "$", + `{"books":[{"t":"a","price":30},{"t":"b","price":5}]}`, + ).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res3) // >>> OK + + res4, err := rdb.JSONGet(ctx, "doc", `$.books[?(@.price >= 10)].append({"t":"X"})`).Result() + + if err != nil { + panic(err) + } + + fmt.Println(res4) // >>> [{"t":"a","price":30},{"t":"X"}] + // STEP_END + + // Output: + // OK + // [1,2,3,9] + // OK + // [{"t":"a","price":30},{"t":"X"}] +} diff --git a/local_examples/json_path_ops/jedis/JsonPathOpsExample.java b/local_examples/json_path_ops/jedis/JsonPathOpsExample.java index d99c364d81..6f35bc61ee 100644 --- a/local_examples/json_path_ops/jedis/JsonPathOpsExample.java +++ b/local_examples/json_path_ops/jedis/JsonPathOpsExample.java @@ -184,6 +184,170 @@ public void run() { jedis.del("doc"); // REMOVE_END + // STEP_START func_length + String res32 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[[1,2,3],[1],\"abcd\",\"x\"]}"); + System.out.println(res32); // >>> OK + + Object res33 = jedis.jsonGet("doc", new Path2("$.a[?length(@) > 2]")); + System.out.println(res33); // >>> [[1,2,3],"abcd"] + // STEP_END + // REMOVE_START + assertEquals("[[1,2,3],\"abcd\"]", res33.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_count + String res34 = jedis.jsonSet("doc", new Path2("$"), "[{\"a\":1,\"b\":2,\"c\":3},{\"a\":1}]"); + System.out.println(res34); // >>> OK + + Object res35 = jedis.jsonGet("doc", new Path2("$[?count(@.*) == 3]")); + System.out.println(res35); // >>> [{"a":1,"b":2,"c":3}] + // STEP_END + // REMOVE_START + assertEquals("[{\"a\":1,\"b\":2,\"c\":3}]", res35.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_value + String res36 = jedis.jsonSet("doc", new Path2("$"), "[{\"a\":1},{\"a\":2}]"); + System.out.println(res36); // >>> OK + + Object res37 = jedis.jsonGet("doc", new Path2("$[?value(@.a) == 1]")); + System.out.println(res37); // >>> [{"a":1}] + // STEP_END + // REMOVE_START + assertEquals("[{\"a\":1}]", res37.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_keys + String res38 = jedis.jsonSet("doc", new Path2("$"), "{\"obj\":{\"x\":1,\"y\":2}}"); + System.out.println(res38); // >>> OK + + Object res39 = jedis.jsonGet("doc", new Path2("$.obj.keys()")); + System.out.println(res39); // >>> ["x","y"] + + Object res40 = jedis.jsonGet("doc", new Path2("$.obj.keys().count()")); + System.out.println(res40); // >>> [2] + // STEP_END + // REMOVE_START + assertEquals("[\"x\",\"y\"]", res39.toString()); + assertEquals("[2]", res40.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_match_search + String res41 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[\"abc\",\"xabc\",\"a\",\"b\"]}"); + System.out.println(res41); // >>> OK + + Object res42 = jedis.jsonGet("doc", new Path2("$.a[?match(@, \"a.*\")]")); + System.out.println(res42); // >>> ["abc","a"] + + String res43 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[\"abc\",\"xyz\",\"b\"]}"); + System.out.println(res43); // >>> OK + + Object res44 = jedis.jsonGet("doc", new Path2("$.a[?search(@, \"b\")]")); + System.out.println(res44); // >>> ["abc","b"] + // STEP_END + // REMOVE_START + assertEquals("[\"abc\",\"a\"]", res42.toString()); + assertEquals("[\"abc\",\"b\"]", res44.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_concat + String res45 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[{\"x\":\"a\",\"y\":\"b\"},{\"x\":\"a\",\"y\":\"c\"}]}"); + System.out.println(res45); // >>> OK + + Object res46 = jedis.jsonGet("doc", new Path2("$.a[?concat(@.x, @.y) == \"ab\"]")); + System.out.println(res46); // >>> [{"x":"a","y":"b"}] + // STEP_END + // REMOVE_START + assertEquals("[{\"x\":\"a\",\"y\":\"b\"}]", res46.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_math + String res47 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[2.1,3.9,1.0]}"); + System.out.println(res47); // >>> OK + + Object res48 = jedis.jsonGet("doc", new Path2("$.a[?ceiling(@) == 3]")); + System.out.println(res48); // >>> [2.1] + + String res49 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[2.1,2.9,3.5]}"); + System.out.println(res49); // >>> OK + + Object res50 = jedis.jsonGet("doc", new Path2("$.a[?floor(@) == 2]")); + System.out.println(res50); // >>> [2.1,2.9] + + String res51 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[{\"n\":-5},{\"n\":5},{\"n\":-3}]}"); + System.out.println(res51); // >>> OK + + Object res52 = jedis.jsonGet("doc", new Path2("$.a[?abs(@.n) == 5]")); + System.out.println(res52); // >>> [{"n":-5},{"n":5}] + // STEP_END + // REMOVE_START + assertEquals("[2.1]", res48.toString()); + assertEquals("[2.1,2.9]", res50.toString()); + assertEquals("[{\"n\":-5},{\"n\":5}]", res52.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_array_access + String res53 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[{\"n\":[1,2]},{\"n\":[9,8]}]}"); + System.out.println(res53); // >>> OK + + Object res54 = jedis.jsonGet("doc", new Path2("$.a[?first(@.n) == 1]")); + System.out.println(res54); // >>> [{"n":[1,2]}] + + Object res55 = jedis.jsonGet("doc", new Path2("$.a[?last(@.n) == 8]")); + System.out.println(res55); // >>> [{"n":[9,8]}] + + Object res56 = jedis.jsonGet("doc", new Path2("$.a[?index(@.n, -1) == 2]")); + System.out.println(res56); // >>> [{"n":[1,2]}] + // STEP_END + // REMOVE_START + assertEquals("[{\"n\":[1,2]}]", res54.toString()); + assertEquals("[{\"n\":[9,8]}]", res55.toString()); + assertEquals("[{\"n\":[1,2]}]", res56.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_aggregate + String res57 = jedis.jsonSet("doc", new Path2("$"), "{\"a\":[{\"n\":[3,1,2]},{\"n\":[5,6]}]}"); + System.out.println(res57); // >>> OK + + Object res58 = jedis.jsonGet("doc", new Path2("$.a[?sum(@.n) == 6]")); + System.out.println(res58); // >>> [{"n":[3,1,2]}] + + Object res59 = jedis.jsonGet("doc", new Path2("$.a[?avg(@.n) == 2]")); + System.out.println(res59); // >>> [{"n":[3,1,2]}] + // STEP_END + // REMOVE_START + assertEquals("[{\"n\":[3,1,2]}]", res58.toString()); + assertEquals("[{\"n\":[3,1,2]}]", res59.toString()); + jedis.del("doc"); + // REMOVE_END + + // STEP_START func_append + String res60 = jedis.jsonSet("doc", new Path2("$"), "{\"arr\":[1,2,3]}"); + System.out.println(res60); // >>> OK + + Object res61 = jedis.jsonGet("doc", new Path2("$.arr.append(9)")); + System.out.println(res61); // >>> [1,2,3,9] + + String res62 = jedis.jsonSet("doc", new Path2("$"), "{\"books\":[{\"t\":\"a\",\"price\":30},{\"t\":\"b\",\"price\":5}]}"); + System.out.println(res62); // >>> OK + + Object res63 = jedis.jsonGet("doc", new Path2("$.books[?(@.price >= 10)].append({\"t\":\"X\"})")); + System.out.println(res63); // >>> [{"t":"a","price":30},{"t":"X"}] + // STEP_END + // REMOVE_START + assertEquals("[1,2,3,9]", res61.toString()); + assertEquals("[{\"t\":\"a\",\"price\":30},{\"t\":\"X\"}]", res63.toString()); + jedis.del("doc"); + // REMOVE_END + // HIDE_START jedis.close(); diff --git a/local_examples/json_path_ops/lettuce-async/JsonPathOpsExample.java b/local_examples/json_path_ops/lettuce-async/JsonPathOpsExample.java index e6655c35f3..a08a956303 100644 --- a/local_examples/json_path_ops/lettuce-async/JsonPathOpsExample.java +++ b/local_examples/json_path_ops/lettuce-async/JsonPathOpsExample.java @@ -299,6 +299,310 @@ public void run() { asyncCommands.del("doc").toCompletableFuture().join(); // REMOVE_END + // STEP_START func_length + CompletableFuture funcLengthExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[[1,2,3],[1],\"abcd\",\"x\"]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?length(@) > 2]")); + }).thenAccept(res2 -> { + System.out.println(res2); // >>> [[[1,2,3],"abcd"]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[[1,2,3],\"abcd\"]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcLengthExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_count + CompletableFuture funcCountExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("[{\"a\":1,\"b\":2,\"c\":3},{\"a\":1}]")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$[?count(@.*) == 3]")); + }).thenAccept(res2 -> { + System.out.println(res2); // >>> [[{"a":1,"b":2,"c":3}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"a\":1,\"b\":2,\"c\":3}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcCountExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_value + CompletableFuture funcValueExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("[{\"a\":1},{\"a\":2}]")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$[?value(@.a) == 1]")); + }).thenAccept(res2 -> { + System.out.println(res2); // >>> [[{"a":1}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"a\":1}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcValueExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_keys + CompletableFuture funcKeysExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"obj\":{\"x\":1,\"y\":2}}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.obj.keys()")); + }).thenCompose(res2 -> { + System.out.println(res2); // >>> [["x","y"]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[\"x\",\"y\"]]"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.obj.keys().count()")); + }).thenAccept(res3 -> { + System.out.println(res3); // >>> [[2]] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[[2]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcKeysExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_match_search + CompletableFuture funcMatchSearchExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[\"abc\",\"xabc\",\"a\",\"b\"]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?match(@, \"a.*\")]")); + }).thenCompose(res2 -> { + System.out.println(res2); // >>> [["abc","a"]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[\"abc\",\"a\"]]"); + // REMOVE_END + return asyncCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[\"abc\",\"xyz\",\"b\"]}")); + }).thenCompose(res3 -> { + System.out.println(res3); // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?search(@, \"b\")]")); + }).thenAccept(res4 -> { + System.out.println(res4); // >>> [["abc","b"]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[\"abc\",\"b\"]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcMatchSearchExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_concat + CompletableFuture funcConcatExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"x\":\"a\",\"y\":\"b\"},{\"x\":\"a\",\"y\":\"c\"}]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?concat(@.x, @.y) == \"ab\"]")); + }).thenAccept(res2 -> { + System.out.println(res2); // >>> [[{"x":"a","y":"b"}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"x\":\"a\",\"y\":\"b\"}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcConcatExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_math + CompletableFuture funcMathExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"a\":[2.1,3.9,1.0]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?ceiling(@) == 3]")); + }).thenCompose(res2 -> { + System.out.println(res2); // >>> [[2.1]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[2.1]]"); + // REMOVE_END + return asyncCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[2.1,2.9,3.5]}")); + }).thenCompose(res3 -> { + System.out.println(res3); // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?floor(@) == 2]")); + }).thenCompose(res4 -> { + System.out.println(res4); // >>> [[2.1,2.9]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[2.1,2.9]]"); + // REMOVE_END + return asyncCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"n\":-5},{\"n\":5},{\"n\":-3}]}")); + }).thenCompose(res5 -> { + System.out.println(res5); // >>> OK + // REMOVE_START + assertThat(res5).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?abs(@.n) == 5]")); + }).thenAccept(res6 -> { + System.out.println(res6); // >>> [[{"n":-5},{"n":5}]] + // REMOVE_START + assertThat(res6.toString()).isEqualTo("[[{\"n\":-5},{\"n\":5}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcMathExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_array_access + CompletableFuture funcArrayAccessExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"n\":[1,2]},{\"n\":[9,8]}]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?first(@.n) == 1]")); + }).thenCompose(res2 -> { + System.out.println(res2); // >>> [[{"n":[1,2]}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"n\":[1,2]}]]"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?last(@.n) == 8]")); + }).thenCompose(res3 -> { + System.out.println(res3); // >>> [[{"n":[9,8]}]] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[[{\"n\":[9,8]}]]"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?index(@.n, -1) == 2]")); + }).thenAccept(res4 -> { + System.out.println(res4); // >>> [[{"n":[1,2]}]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[{\"n\":[1,2]}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcArrayAccessExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_aggregate + CompletableFuture funcAggregateExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"n\":[3,1,2]},{\"n\":[5,6]}]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?sum(@.n) == 6]")); + }).thenCompose(res2 -> { + System.out.println(res2); // >>> [[{"n":[3,1,2]}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"n\":[3,1,2]}]]"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.a[?avg(@.n) == 2]")); + }).thenAccept(res3 -> { + System.out.println(res3); // >>> [[{"n":[3,1,2]}]] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[[{\"n\":[3,1,2]}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcAggregateExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + + // STEP_START func_append + CompletableFuture funcAppendExample = asyncCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"arr\":[1,2,3]}")) + .thenCompose(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", JsonPath.of("$.arr.append(9)")); + }).thenCompose(res2 -> { + System.out.println(res2); // >>> [[1,2,3,9]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[1,2,3,9]]"); + // REMOVE_END + return asyncCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue( + "{\"books\":[{\"t\":\"a\",\"price\":30},{\"t\":\"b\",\"price\":5}]}")); + }).thenCompose(res3 -> { + System.out.println(res3); // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + return asyncCommands.jsonGet("doc", + JsonPath.of("$.books[?(@.price >= 10)].append({\"t\":\"X\"})")); + }).thenAccept(res4 -> { + System.out.println(res4); // >>> [[{"t":"a","price":30},{"t":"X"}]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[{\"t\":\"a\",\"price\":30},{\"t\":\"X\"}]]"); + // REMOVE_END + }).toCompletableFuture(); + // STEP_END + + funcAppendExample.join(); + // REMOVE_START + asyncCommands.del("doc").toCompletableFuture().join(); + // REMOVE_END + } finally { redisClient.shutdown(); } diff --git a/local_examples/json_path_ops/lettuce-reactive/JsonPathOpsExample.java b/local_examples/json_path_ops/lettuce-reactive/JsonPathOpsExample.java index 4c5d74ad52..bf017f949b 100644 --- a/local_examples/json_path_ops/lettuce-reactive/JsonPathOpsExample.java +++ b/local_examples/json_path_ops/lettuce-reactive/JsonPathOpsExample.java @@ -325,6 +325,341 @@ public void run() { reactiveCommands.del("doc").block(); // REMOVE_END + // STEP_START func_length + Mono funcLengthExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[[1,2,3],[1],\"abcd\",\"x\"]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?length(@) > 2]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[[1,2,3],"abcd"]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[[1,2,3],\"abcd\"]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcLengthExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_count + Mono funcCountExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("[{\"a\":1,\"b\":2,\"c\":3},{\"a\":1}]")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$[?count(@.*) == 3]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[{"a":1,"b":2,"c":3}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"a\":1,\"b\":2,\"c\":3}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcCountExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_value + Mono funcValueExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("[{\"a\":1},{\"a\":2}]")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$[?value(@.a) == 1]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[{"a":1}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"a\":1}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcValueExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_keys + Mono funcKeysExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"obj\":{\"x\":1,\"y\":2}}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.obj.keys()")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [["x","y"]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[\"x\",\"y\"]]"); + // REMOVE_END + }) + .flatMap(res2 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.obj.keys().count()")).collectList()) + .doOnNext(res3 -> { + System.out.println(res3); // >>> [[2]] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[[2]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcKeysExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_match_search + Mono funcMatchSearchExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"a\":[\"abc\",\"xabc\",\"a\",\"b\"]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?match(@, \"a.*\")]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [["abc","a"]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[\"abc\",\"a\"]]"); + // REMOVE_END + }) + .flatMap(res2 -> reactiveCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[\"abc\",\"xyz\",\"b\"]}"))) + .doOnNext(res3 -> { + System.out.println(res3); // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res3 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?search(@, \"b\")]")).collectList()) + .doOnNext(res4 -> { + System.out.println(res4); // >>> [["abc","b"]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[\"abc\",\"b\"]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcMatchSearchExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_concat + Mono funcConcatExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"x\":\"a\",\"y\":\"b\"},{\"x\":\"a\",\"y\":\"c\"}]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?concat(@.x, @.y) == \"ab\"]")) + .collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[{"x":"a","y":"b"}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"x\":\"a\",\"y\":\"b\"}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcConcatExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_math + Mono funcMathExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"a\":[2.1,3.9,1.0]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?ceiling(@) == 3]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[2.1]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[2.1]]"); + // REMOVE_END + }) + .flatMap(res2 -> reactiveCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[2.1,2.9,3.5]}"))) + .doOnNext(res3 -> { + System.out.println(res3); // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res3 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?floor(@) == 2]")).collectList()) + .doOnNext(res4 -> { + System.out.println(res4); // >>> [[2.1,2.9]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[2.1,2.9]]"); + // REMOVE_END + }) + .flatMap(res4 -> reactiveCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"n\":-5},{\"n\":5},{\"n\":-3}]}"))) + .doOnNext(res5 -> { + System.out.println(res5); // >>> OK + // REMOVE_START + assertThat(res5).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res5 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?abs(@.n) == 5]")).collectList()) + .doOnNext(res6 -> { + System.out.println(res6); // >>> [[{"n":-5},{"n":5}]] + // REMOVE_START + assertThat(res6.toString()).isEqualTo("[[{\"n\":-5},{\"n\":5}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcMathExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_array_access + Mono funcArrayAccessExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"a\":[{\"n\":[1,2]},{\"n\":[9,8]}]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?first(@.n) == 1]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[{"n":[1,2]}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"n\":[1,2]}]]"); + // REMOVE_END + }) + .flatMap(res2 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?last(@.n) == 8]")).collectList()) + .doOnNext(res3 -> { + System.out.println(res3); // >>> [[{"n":[9,8]}]] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[[{\"n\":[9,8]}]]"); + // REMOVE_END + }) + .flatMap(res3 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?index(@.n, -1) == 2]")).collectList()) + .doOnNext(res4 -> { + System.out.println(res4); // >>> [[{"n":[1,2]}]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[{\"n\":[1,2]}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcArrayAccessExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_aggregate + Mono funcAggregateExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue("{\"a\":[{\"n\":[3,1,2]},{\"n\":[5,6]}]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?sum(@.n) == 6]")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[{"n":[3,1,2]}]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[{\"n\":[3,1,2]}]]"); + // REMOVE_END + }) + .flatMap(res2 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.a[?avg(@.n) == 2]")).collectList()) + .doOnNext(res3 -> { + System.out.println(res3); // >>> [[{"n":[3,1,2]}]] + // REMOVE_START + assertThat(res3.toString()).isEqualTo("[[{\"n\":[3,1,2]}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcAggregateExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + + // STEP_START func_append + Mono funcAppendExample = reactiveCommands + .jsonSet("doc", JsonPath.ROOT_PATH, parser.createJsonValue("{\"arr\":[1,2,3]}")) + .doOnNext(res1 -> { + System.out.println(res1); // >>> OK + // REMOVE_START + assertThat(res1).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res1 -> reactiveCommands.jsonGet("doc", JsonPath.of("$.arr.append(9)")).collectList()) + .doOnNext(res2 -> { + System.out.println(res2); // >>> [[1,2,3,9]] + // REMOVE_START + assertThat(res2.toString()).isEqualTo("[[1,2,3,9]]"); + // REMOVE_END + }) + .flatMap(res2 -> reactiveCommands.jsonSet("doc", JsonPath.ROOT_PATH, + parser.createJsonValue( + "{\"books\":[{\"t\":\"a\",\"price\":30},{\"t\":\"b\",\"price\":5}]}"))) + .doOnNext(res3 -> { + System.out.println(res3); // >>> OK + // REMOVE_START + assertThat(res3).isEqualTo("OK"); + // REMOVE_END + }) + .flatMap(res3 -> reactiveCommands + .jsonGet("doc", JsonPath.of("$.books[?(@.price >= 10)].append({\"t\":\"X\"})")) + .collectList()) + .doOnNext(res4 -> { + System.out.println(res4); // >>> [[{"t":"a","price":30},{"t":"X"}]] + // REMOVE_START + assertThat(res4.toString()).isEqualTo("[[{\"t\":\"a\",\"price\":30},{\"t\":\"X\"}]]"); + // REMOVE_END + }) + .then(); + // STEP_END + + funcAppendExample.block(); + // REMOVE_START + reactiveCommands.del("doc").block(); + // REMOVE_END + } finally { redisClient.shutdown(); } diff --git a/local_examples/json_path_ops/node-redis/json-path-ops.js b/local_examples/json_path_ops/node-redis/json-path-ops.js index 30702f9c39..a98795481a 100644 --- a/local_examples/json_path_ops/node-redis/json-path-ops.js +++ b/local_examples/json_path_ops/node-redis/json-path-ops.js @@ -173,6 +173,182 @@ assert.deepEqual(res31, []); await client.del('doc'); // REMOVE_END +// STEP_START func_length +const res32 = await client.json.set('doc', '$', { a: [[1, 2, 3], [1], 'abcd', 'x'] }); +console.log(res32); // >>> OK + +const res33 = await client.json.get('doc', { path: '$.a[?length(@) > 2]' }); +console.log(res33); // >>> [ [ 1, 2, 3 ], 'abcd' ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res33, [[1, 2, 3], 'abcd']); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_count +const res34 = await client.json.set('doc', '$', [{ a: 1, b: 2, c: 3 }, { a: 1 }]); +console.log(res34); // >>> OK + +const res35 = await client.json.get('doc', { path: '$[?count(@.*) == 3]' }); +console.log(res35); // >>> [ { a: 1, b: 2, c: 3 } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res35, [{ a: 1, b: 2, c: 3 }]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_value +const res36 = await client.json.set('doc', '$', [{ a: 1 }, { a: 2 }]); +console.log(res36); // >>> OK + +const res37 = await client.json.get('doc', { path: '$[?value(@.a) == 1]' }); +console.log(res37); // >>> [ { a: 1 } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res37, [{ a: 1 }]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_keys +const res38 = await client.json.set('doc', '$', { obj: { x: 1, y: 2 } }); +console.log(res38); // >>> OK + +const res39 = await client.json.get('doc', { path: '$.obj.keys()' }); +console.log(res39); // >>> [ 'x', 'y' ] + +const res40 = await client.json.get('doc', { path: '$.obj.keys().count()' }); +console.log(res40); // >>> [ 2 ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res39, ['x', 'y']); +assert.deepEqual(res40, [2]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_match_search +const res41 = await client.json.set('doc', '$', { a: ['abc', 'xabc', 'a', 'b'] }); +console.log(res41); // >>> OK + +const res42 = await client.json.get('doc', { path: '$.a[?match(@, "a.*")]' }); +console.log(res42); // >>> [ 'abc', 'a' ] + +const res43 = await client.json.set('doc', '$', { a: ['abc', 'xyz', 'b'] }); +console.log(res43); // >>> OK + +const res44 = await client.json.get('doc', { path: '$.a[?search(@, "b")]' }); +console.log(res44); // >>> [ 'abc', 'b' ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res42, ['abc', 'a']); +assert.deepEqual(res44, ['abc', 'b']); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_concat +const res45 = await client.json.set('doc', '$', { a: [{ x: 'a', y: 'b' }, { x: 'a', y: 'c' }] }); +console.log(res45); // >>> OK + +const res46 = await client.json.get('doc', { path: '$.a[?concat(@.x, @.y) == "ab"]' }); +console.log(res46); // >>> [ { x: 'a', y: 'b' } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res46, [{ x: 'a', y: 'b' }]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_math +const res47 = await client.json.set('doc', '$', { a: [2.1, 3.9, 1.0] }); +console.log(res47); // >>> OK + +const res48 = await client.json.get('doc', { path: '$.a[?ceiling(@) == 3]' }); +console.log(res48); // >>> [ 2.1 ] + +const res49 = await client.json.set('doc', '$', { a: [2.1, 2.9, 3.5] }); +console.log(res49); // >>> OK + +const res50 = await client.json.get('doc', { path: '$.a[?floor(@) == 2]' }); +console.log(res50); // >>> [ 2.1, 2.9 ] + +const res51 = await client.json.set('doc', '$', { a: [{ n: -5 }, { n: 5 }, { n: -3 }] }); +console.log(res51); // >>> OK + +const res52 = await client.json.get('doc', { path: '$.a[?abs(@.n) == 5]' }); +console.log(res52); // >>> [ { n: -5 }, { n: 5 } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res48, [2.1]); +assert.deepEqual(res50, [2.1, 2.9]); +assert.deepEqual(res52, [{ n: -5 }, { n: 5 }]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_array_access +const res53 = await client.json.set('doc', '$', { a: [{ n: [1, 2] }, { n: [9, 8] }] }); +console.log(res53); // >>> OK + +const res54 = await client.json.get('doc', { path: '$.a[?first(@.n) == 1]' }); +console.log(res54); // >>> [ { n: [ 1, 2 ] } ] + +const res55 = await client.json.get('doc', { path: '$.a[?last(@.n) == 8]' }); +console.log(res55); // >>> [ { n: [ 9, 8 ] } ] + +const res56 = await client.json.get('doc', { path: '$.a[?index(@.n, -1) == 2]' }); +console.log(res56); // >>> [ { n: [ 1, 2 ] } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res54, [{ n: [1, 2] }]); +assert.deepEqual(res55, [{ n: [9, 8] }]); +assert.deepEqual(res56, [{ n: [1, 2] }]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_aggregate +const res57 = await client.json.set('doc', '$', { a: [{ n: [3, 1, 2] }, { n: [5, 6] }] }); +console.log(res57); // >>> OK + +const res58 = await client.json.get('doc', { path: '$.a[?sum(@.n) == 6]' }); +console.log(res58); // >>> [ { n: [ 3, 1, 2 ] } ] + +const res59 = await client.json.get('doc', { path: '$.a[?avg(@.n) == 2]' }); +console.log(res59); // >>> [ { n: [ 3, 1, 2 ] } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res58, [{ n: [3, 1, 2] }]); +assert.deepEqual(res59, [{ n: [3, 1, 2] }]); +await client.del('doc'); +// REMOVE_END + +// STEP_START func_append +const res60 = await client.json.set('doc', '$', { arr: [1, 2, 3] }); +console.log(res60); // >>> OK + +const res61 = await client.json.get('doc', { path: '$.arr.append(9)' }); +console.log(res61); // >>> [ 1, 2, 3, 9 ] + +const res62 = await client.json.set('doc', '$', { + books: [{ t: 'a', price: 30 }, { t: 'b', price: 5 }] +}); +console.log(res62); // >>> OK + +const res63 = await client.json.get('doc', { path: '$.books[?(@.price >= 10)].append({"t":"X"})' }); +console.log(res63); // >>> [ { t: 'a', price: 30 }, { t: 'X' } ] +// STEP_END + +// REMOVE_START +assert.deepEqual(res61, [1, 2, 3, 9]); +assert.deepEqual(res63, [{ t: 'a', price: 30 }, { t: 'X' }]); +await client.del('doc'); +// REMOVE_END + // HIDE_START await client.close(); diff --git a/local_examples/json_path_ops/nredisstack/JsonPathOpsExample.cs b/local_examples/json_path_ops/nredisstack/JsonPathOpsExample.cs index 6e19daeb46..1d5f404cae 100644 --- a/local_examples/json_path_ops/nredisstack/JsonPathOpsExample.cs +++ b/local_examples/json_path_ops/nredisstack/JsonPathOpsExample.cs @@ -215,6 +215,194 @@ public void Run() db.KeyDelete("doc"); // REMOVE_END + // STEP_START func_length + bool res32 = db.JSON().Set("doc", "$", "{\"a\":[[1,2,3],[1],\"abcd\",\"x\"]}"); + Console.WriteLine(res32); // >>> True + + RedisResult res33 = db.JSON().Get("doc", path: "$.a[?length(@) > 2]"); + Console.WriteLine(res33); // >>> [[1,2,3],"abcd"] + // STEP_END + + // REMOVE_START + Assert.True(res32); + Assert.Equal("[[1,2,3],\"abcd\"]", (string?)res33); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_count + bool res34 = db.JSON().Set("doc", "$", "[{\"a\":1,\"b\":2,\"c\":3},{\"a\":1}]"); + Console.WriteLine(res34); // >>> True + + RedisResult res35 = db.JSON().Get("doc", path: "$[?count(@.*) == 3]"); + Console.WriteLine(res35); // >>> [{"a":1,"b":2,"c":3}] + // STEP_END + + // REMOVE_START + Assert.True(res34); + Assert.Equal("[{\"a\":1,\"b\":2,\"c\":3}]", (string?)res35); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_value + bool res36 = db.JSON().Set("doc", "$", "[{\"a\":1},{\"a\":2}]"); + Console.WriteLine(res36); // >>> True + + RedisResult res37 = db.JSON().Get("doc", path: "$[?value(@.a) == 1]"); + Console.WriteLine(res37); // >>> [{"a":1}] + // STEP_END + + // REMOVE_START + Assert.True(res36); + Assert.Equal("[{\"a\":1}]", (string?)res37); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_keys + bool res38 = db.JSON().Set("doc", "$", "{\"obj\":{\"x\":1,\"y\":2}}"); + Console.WriteLine(res38); // >>> True + + RedisResult res39 = db.JSON().Get("doc", path: "$.obj.keys()"); + Console.WriteLine(res39); // >>> ["x","y"] + + RedisResult res40 = db.JSON().Get("doc", path: "$.obj.keys().count()"); + Console.WriteLine(res40); // >>> [2] + // STEP_END + + // REMOVE_START + Assert.True(res38); + Assert.Equal("[\"x\",\"y\"]", (string?)res39); + Assert.Equal("[2]", (string?)res40); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_match_search + bool res41 = db.JSON().Set("doc", "$", "{\"a\":[\"abc\",\"xabc\",\"a\",\"b\"]}"); + Console.WriteLine(res41); // >>> True + + RedisResult res42 = db.JSON().Get("doc", path: "$.a[?match(@, \"a.*\")]"); + Console.WriteLine(res42); // >>> ["abc","a"] + + bool res43 = db.JSON().Set("doc", "$", "{\"a\":[\"abc\",\"xyz\",\"b\"]}"); + Console.WriteLine(res43); // >>> True + + RedisResult res44 = db.JSON().Get("doc", path: "$.a[?search(@, \"b\")]"); + Console.WriteLine(res44); // >>> ["abc","b"] + // STEP_END + + // REMOVE_START + Assert.True(res41); + Assert.Equal("[\"abc\",\"a\"]", (string?)res42); + Assert.True(res43); + Assert.Equal("[\"abc\",\"b\"]", (string?)res44); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_concat + bool res45 = db.JSON().Set("doc", "$", "{\"a\":[{\"x\":\"a\",\"y\":\"b\"},{\"x\":\"a\",\"y\":\"c\"}]}"); + Console.WriteLine(res45); // >>> True + + RedisResult res46 = db.JSON().Get("doc", path: "$.a[?concat(@.x, @.y) == \"ab\"]"); + Console.WriteLine(res46); // >>> [{"x":"a","y":"b"}] + // STEP_END + + // REMOVE_START + Assert.True(res45); + Assert.Equal("[{\"x\":\"a\",\"y\":\"b\"}]", (string?)res46); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_math + bool res47 = db.JSON().Set("doc", "$", "{\"a\":[2.1,3.9,1.0]}"); + Console.WriteLine(res47); // >>> True + + RedisResult res48 = db.JSON().Get("doc", path: "$.a[?ceiling(@) == 3]"); + Console.WriteLine(res48); // >>> [2.1] + + bool res49 = db.JSON().Set("doc", "$", "{\"a\":[2.1,2.9,3.5]}"); + Console.WriteLine(res49); // >>> True + + RedisResult res50 = db.JSON().Get("doc", path: "$.a[?floor(@) == 2]"); + Console.WriteLine(res50); // >>> [2.1,2.9] + + bool res51 = db.JSON().Set("doc", "$", "{\"a\":[{\"n\":-5},{\"n\":5},{\"n\":-3}]}"); + Console.WriteLine(res51); // >>> True + + RedisResult res52 = db.JSON().Get("doc", path: "$.a[?abs(@.n) == 5]"); + Console.WriteLine(res52); // >>> [{"n":-5},{"n":5}] + // STEP_END + + // REMOVE_START + Assert.True(res47); + Assert.Equal("[2.1]", (string?)res48); + Assert.True(res49); + Assert.Equal("[2.1,2.9]", (string?)res50); + Assert.True(res51); + Assert.Equal("[{\"n\":-5},{\"n\":5}]", (string?)res52); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_array_access + bool res53 = db.JSON().Set("doc", "$", "{\"a\":[{\"n\":[1,2]},{\"n\":[9,8]}]}"); + Console.WriteLine(res53); // >>> True + + RedisResult res54 = db.JSON().Get("doc", path: "$.a[?first(@.n) == 1]"); + Console.WriteLine(res54); // >>> [{"n":[1,2]}] + + RedisResult res55 = db.JSON().Get("doc", path: "$.a[?last(@.n) == 8]"); + Console.WriteLine(res55); // >>> [{"n":[9,8]}] + + RedisResult res56 = db.JSON().Get("doc", path: "$.a[?index(@.n, -1) == 2]"); + Console.WriteLine(res56); // >>> [{"n":[1,2]}] + // STEP_END + + // REMOVE_START + Assert.True(res53); + Assert.Equal("[{\"n\":[1,2]}]", (string?)res54); + Assert.Equal("[{\"n\":[9,8]}]", (string?)res55); + Assert.Equal("[{\"n\":[1,2]}]", (string?)res56); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_aggregate + bool res57 = db.JSON().Set("doc", "$", "{\"a\":[{\"n\":[3,1,2]},{\"n\":[5,6]}]}"); + Console.WriteLine(res57); // >>> True + + RedisResult res58 = db.JSON().Get("doc", path: "$.a[?sum(@.n) == 6]"); + Console.WriteLine(res58); // >>> [{"n":[3,1,2]}] + + RedisResult res59 = db.JSON().Get("doc", path: "$.a[?avg(@.n) == 2]"); + Console.WriteLine(res59); // >>> [{"n":[3,1,2]}] + // STEP_END + + // REMOVE_START + Assert.True(res57); + Assert.Equal("[{\"n\":[3,1,2]}]", (string?)res58); + Assert.Equal("[{\"n\":[3,1,2]}]", (string?)res59); + db.KeyDelete("doc"); + // REMOVE_END + + // STEP_START func_append + bool res60 = db.JSON().Set("doc", "$", "{\"arr\":[1,2,3]}"); + Console.WriteLine(res60); // >>> True + + RedisResult res61 = db.JSON().Get("doc", path: "$.arr.append(9)"); + Console.WriteLine(res61); // >>> [1,2,3,9] + + bool res62 = db.JSON().Set("doc", "$", "{\"books\":[{\"t\":\"a\",\"price\":30},{\"t\":\"b\",\"price\":5}]}"); + Console.WriteLine(res62); // >>> True + + RedisResult res63 = db.JSON().Get("doc", path: "$.books[?(@.price >= 10)].append({\"t\":\"X\"})"); + Console.WriteLine(res63); // >>> [{"t":"a","price":30},{"t":"X"}] + // STEP_END + + // REMOVE_START + Assert.True(res60); + Assert.Equal("[1,2,3,9]", (string?)res61); + Assert.True(res62); + Assert.Equal("[{\"t\":\"a\",\"price\":30},{\"t\":\"X\"}]", (string?)res63); + db.KeyDelete("doc"); + // REMOVE_END + // HIDE_START } diff --git a/local_examples/json_path_ops/predis/JsonPathOpsTest.php b/local_examples/json_path_ops/predis/JsonPathOpsTest.php index 1afecbc588..1d17071aa4 100644 --- a/local_examples/json_path_ops/predis/JsonPathOpsTest.php +++ b/local_examples/json_path_ops/predis/JsonPathOpsTest.php @@ -212,6 +212,222 @@ public function testJsonPathOps(): void $this->redis->del('doc'); // REMOVE_END + // STEP_START func_length + $res32 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [[1, 2, 3], [1], "abcd", "x"]] + )); + echo $res32 . PHP_EOL; // >>> OK + + $res33 = $this->redis->jsonget('doc', '', '', '', '$.a[?length(@) > 2]'); + echo $res33 . PHP_EOL; // >>> [[1,2,3],"abcd"] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res32); + $this->assertEquals('[[1,2,3],"abcd"]', $res33); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_count + $res34 = $this->redis->jsonset('doc', '$', json_encode( + [["a" => 1, "b" => 2, "c" => 3], ["a" => 1]] + )); + echo $res34 . PHP_EOL; // >>> OK + + $res35 = $this->redis->jsonget('doc', '', '', '', '$[?count(@.*) == 3]'); + echo $res35 . PHP_EOL; // >>> [{"a":1,"b":2,"c":3}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res34); + $this->assertEquals('[{"a":1,"b":2,"c":3}]', $res35); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_value + $res36 = $this->redis->jsonset('doc', '$', json_encode( + [["a" => 1], ["a" => 2]] + )); + echo $res36 . PHP_EOL; // >>> OK + + $res37 = $this->redis->jsonget('doc', '', '', '', '$[?value(@.a) == 1]'); + echo $res37 . PHP_EOL; // >>> [{"a":1}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res36); + $this->assertEquals('[{"a":1}]', $res37); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_keys + $res38 = $this->redis->jsonset('doc', '$', json_encode( + ["obj" => ["x" => 1, "y" => 2]] + )); + echo $res38 . PHP_EOL; // >>> OK + + $res39 = $this->redis->jsonget('doc', '', '', '', '$.obj.keys()'); + echo $res39 . PHP_EOL; // >>> ["x","y"] + + $res40 = $this->redis->jsonget('doc', '', '', '', '$.obj.keys().count()'); + echo $res40 . PHP_EOL; // >>> [2] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res38); + $this->assertEquals('["x","y"]', $res39); + $this->assertEquals('[2]', $res40); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_match_search + $res41 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => ["abc", "xabc", "a", "b"]] + )); + echo $res41 . PHP_EOL; // >>> OK + + $res42 = $this->redis->jsonget('doc', '', '', '', '$.a[?match(@, "a.*")]'); + echo $res42 . PHP_EOL; // >>> ["abc","a"] + + $res43 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => ["abc", "xyz", "b"]] + )); + echo $res43 . PHP_EOL; // >>> OK + + $res44 = $this->redis->jsonget('doc', '', '', '', '$.a[?search(@, "b")]'); + echo $res44 . PHP_EOL; // >>> ["abc","b"] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res41); + $this->assertEquals('["abc","a"]', $res42); + $this->assertEquals('OK', $res43); + $this->assertEquals('["abc","b"]', $res44); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_concat + $res45 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [["x" => "a", "y" => "b"], ["x" => "a", "y" => "c"]]] + )); + echo $res45 . PHP_EOL; // >>> OK + + $res46 = $this->redis->jsonget('doc', '', '', '', '$.a[?concat(@.x, @.y) == "ab"]'); + echo $res46 . PHP_EOL; // >>> [{"x":"a","y":"b"}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res45); + $this->assertEquals('[{"x":"a","y":"b"}]', $res46); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_math + $res47 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [2.1, 3.9, 1.0]] + )); + echo $res47 . PHP_EOL; // >>> OK + + $res48 = $this->redis->jsonget('doc', '', '', '', '$.a[?ceiling(@) == 3]'); + echo $res48 . PHP_EOL; // >>> [2.1] + + $res49 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [2.1, 2.9, 3.5]] + )); + echo $res49 . PHP_EOL; // >>> OK + + $res50 = $this->redis->jsonget('doc', '', '', '', '$.a[?floor(@) == 2]'); + echo $res50 . PHP_EOL; // >>> [2.1,2.9] + + $res51 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [["n" => -5], ["n" => 5], ["n" => -3]]] + )); + echo $res51 . PHP_EOL; // >>> OK + + $res52 = $this->redis->jsonget('doc', '', '', '', '$.a[?abs(@.n) == 5]'); + echo $res52 . PHP_EOL; // >>> [{"n":-5},{"n":5}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res47); + $this->assertEquals('[2.1]', $res48); + $this->assertEquals('OK', $res49); + $this->assertEquals('[2.1,2.9]', $res50); + $this->assertEquals('OK', $res51); + $this->assertEquals('[{"n":-5},{"n":5}]', $res52); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_array_access + $res53 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [["n" => [1, 2]], ["n" => [9, 8]]]] + )); + echo $res53 . PHP_EOL; // >>> OK + + $res54 = $this->redis->jsonget('doc', '', '', '', '$.a[?first(@.n) == 1]'); + echo $res54 . PHP_EOL; // >>> [{"n":[1,2]}] + + $res55 = $this->redis->jsonget('doc', '', '', '', '$.a[?last(@.n) == 8]'); + echo $res55 . PHP_EOL; // >>> [{"n":[9,8]}] + + $res56 = $this->redis->jsonget('doc', '', '', '', '$.a[?index(@.n, -1) == 2]'); + echo $res56 . PHP_EOL; // >>> [{"n":[1,2]}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res53); + $this->assertEquals('[{"n":[1,2]}]', $res54); + $this->assertEquals('[{"n":[9,8]}]', $res55); + $this->assertEquals('[{"n":[1,2]}]', $res56); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_aggregate + $res57 = $this->redis->jsonset('doc', '$', json_encode( + ["a" => [["n" => [3, 1, 2]], ["n" => [5, 6]]]] + )); + echo $res57 . PHP_EOL; // >>> OK + + $res58 = $this->redis->jsonget('doc', '', '', '', '$.a[?sum(@.n) == 6]'); + echo $res58 . PHP_EOL; // >>> [{"n":[3,1,2]}] + + $res59 = $this->redis->jsonget('doc', '', '', '', '$.a[?avg(@.n) == 2]'); + echo $res59 . PHP_EOL; // >>> [{"n":[3,1,2]}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res57); + $this->assertEquals('[{"n":[3,1,2]}]', $res58); + $this->assertEquals('[{"n":[3,1,2]}]', $res59); + $this->redis->del('doc'); + // REMOVE_END + + // STEP_START func_append + $res60 = $this->redis->jsonset('doc', '$', json_encode( + ["arr" => [1, 2, 3]] + )); + echo $res60 . PHP_EOL; // >>> OK + + $res61 = $this->redis->jsonget('doc', '', '', '', '$.arr.append(9)'); + echo $res61 . PHP_EOL; // >>> [1,2,3,9] + + $res62 = $this->redis->jsonset('doc', '$', json_encode( + ["books" => [["t" => "a", "price" => 30], ["t" => "b", "price" => 5]]] + )); + echo $res62 . PHP_EOL; // >>> OK + + $res63 = $this->redis->jsonget('doc', '', '', '', '$.books[?(@.price >= 10)].append({"t":"X"})'); + echo $res63 . PHP_EOL; // >>> [{"t":"a","price":30},{"t":"X"}] + // STEP_END + + // REMOVE_START + $this->assertEquals('OK', $res60); + $this->assertEquals('[1,2,3,9]', $res61); + $this->assertEquals('OK', $res62); + $this->assertEquals('[{"t":"a","price":30},{"t":"X"}]', $res63); + $this->redis->del('doc'); + // REMOVE_END + } protected function tearDown(): void diff --git a/local_examples/json_path_ops/redis-py/json_path_ops.py b/local_examples/json_path_ops/redis-py/json_path_ops.py index 430ed2b265..d007ce31da 100644 --- a/local_examples/json_path_ops/redis-py/json_path_ops.py +++ b/local_examples/json_path_ops/redis-py/json_path_ops.py @@ -199,3 +199,209 @@ assert res4 == [] r.delete("doc") # REMOVE_END + +# STEP_START func_length +res1 = r.json().set("doc", "$", {"a": [[1, 2, 3], [1], "abcd", "x"]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$.a[?length(@) > 2]") +print(res2) +# >>> [[1, 2, 3], 'abcd'] +# STEP_END + +# REMOVE_START +assert res2 == [[1, 2, 3], "abcd"] +r.delete("doc") +# REMOVE_END + +# STEP_START func_count +res1 = r.json().set("doc", "$", [{"a": 1, "b": 2, "c": 3}, {"a": 1}]) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$[?count(@.*) == 3]") +print(res2) +# >>> [{'a': 1, 'b': 2, 'c': 3}] +# STEP_END + +# REMOVE_START +assert res2 == [{"a": 1, "b": 2, "c": 3}] +r.delete("doc") +# REMOVE_END + +# STEP_START func_value +res1 = r.json().set("doc", "$", [{"a": 1}, {"a": 2}]) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$[?value(@.a) == 1]") +print(res2) +# >>> [{'a': 1}] +# STEP_END + +# REMOVE_START +assert res2 == [{"a": 1}] +r.delete("doc") +# REMOVE_END + +# STEP_START func_keys +res1 = r.json().set("doc", "$", {"obj": {"x": 1, "y": 2}}) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$.obj.keys()") +print(res2) +# >>> ['x', 'y'] + +res3 = r.json().get("doc", "$.obj.keys().count()") +print(res3) +# >>> [2] +# STEP_END + +# REMOVE_START +assert res2 == ["x", "y"] +assert res3 == [2] +r.delete("doc") +# REMOVE_END + +# STEP_START func_match_search +res1 = r.json().set("doc", "$", {"a": ["abc", "xabc", "a", "b"]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", '$.a[?match(@, "a.*")]') +print(res2) +# >>> ['abc', 'a'] + +res3 = r.json().set("doc", "$", {"a": ["abc", "xyz", "b"]}) +print(res3) +# >>> True + +res4 = r.json().get("doc", '$.a[?search(@, "b")]') +print(res4) +# >>> ['abc', 'b'] +# STEP_END + +# REMOVE_START +assert res2 == ["abc", "a"] +assert res4 == ["abc", "b"] +r.delete("doc") +# REMOVE_END + +# STEP_START func_concat +res1 = r.json().set("doc", "$", {"a": [{"x": "a", "y": "b"}, {"x": "a", "y": "c"}]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", '$.a[?concat(@.x, @.y) == "ab"]') +print(res2) +# >>> [{'x': 'a', 'y': 'b'}] +# STEP_END + +# REMOVE_START +assert res2 == [{"x": "a", "y": "b"}] +r.delete("doc") +# REMOVE_END + +# STEP_START func_math +res1 = r.json().set("doc", "$", {"a": [2.1, 3.9, 1.0]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$.a[?ceiling(@) == 3]") +print(res2) +# >>> [2.1] + +res3 = r.json().set("doc", "$", {"a": [2.1, 2.9, 3.5]}) +print(res3) +# >>> True + +res4 = r.json().get("doc", "$.a[?floor(@) == 2]") +print(res4) +# >>> [2.1, 2.9] + +res5 = r.json().set("doc", "$", {"a": [{"n": -5}, {"n": 5}, {"n": -3}]}) +print(res5) +# >>> True + +res6 = r.json().get("doc", "$.a[?abs(@.n) == 5]") +print(res6) +# >>> [{'n': -5}, {'n': 5}] +# STEP_END + +# REMOVE_START +assert res2 == [2.1] +assert res4 == [2.1, 2.9] +assert res6 == [{"n": -5}, {"n": 5}] +r.delete("doc") +# REMOVE_END + +# STEP_START func_array_access +res1 = r.json().set("doc", "$", {"a": [{"n": [1, 2]}, {"n": [9, 8]}]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$.a[?first(@.n) == 1]") +print(res2) +# >>> [{'n': [1, 2]}] + +res3 = r.json().get("doc", "$.a[?last(@.n) == 8]") +print(res3) +# >>> [{'n': [9, 8]}] + +res4 = r.json().get("doc", "$.a[?index(@.n, -1) == 2]") +print(res4) +# >>> [{'n': [1, 2]}] +# STEP_END + +# REMOVE_START +assert res2 == [{"n": [1, 2]}] +assert res3 == [{"n": [9, 8]}] +assert res4 == [{"n": [1, 2]}] +r.delete("doc") +# REMOVE_END + +# STEP_START func_aggregate +res1 = r.json().set("doc", "$", {"a": [{"n": [3, 1, 2]}, {"n": [5, 6]}]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$.a[?sum(@.n) == 6]") +print(res2) +# >>> [{'n': [3, 1, 2]}] + +res3 = r.json().get("doc", "$.a[?avg(@.n) == 2]") +print(res3) +# >>> [{'n': [3, 1, 2]}] +# STEP_END + +# REMOVE_START +assert res2 == [{"n": [3, 1, 2]}] +assert res3 == [{"n": [3, 1, 2]}] +r.delete("doc") +# REMOVE_END + +# STEP_START func_append +res1 = r.json().set("doc", "$", {"arr": [1, 2, 3]}) +print(res1) +# >>> True + +res2 = r.json().get("doc", "$.arr.append(9)") +print(res2) +# >>> [1, 2, 3, 9] + +res3 = r.json().set("doc", "$", {"books": [{"t": "a", "price": 30}, {"t": "b", "price": 5}]}) +print(res3) +# >>> True + +res4 = r.json().get("doc", '$.books[?(@.price >= 10)].append({"t":"X"})') +print(res4) +# >>> [{'t': 'a', 'price': 30}, {'t': 'X'}] +# STEP_END + +# REMOVE_START +assert res2 == [1, 2, 3, 9] +assert res4 == [{"t": "a", "price": 30}, {"t": "X"}] +r.delete("doc") +# REMOVE_END diff --git a/local_examples/json_path_ops/ruby/json_path_ops.rb b/local_examples/json_path_ops/ruby/json_path_ops.rb index 717377fe3d..7b73d4b205 100644 --- a/local_examples/json_path_ops/ruby/json_path_ops.rb +++ b/local_examples/json_path_ops/ruby/json_path_ops.rb @@ -170,5 +170,179 @@ def assert_equal(expected, actual) assert_equal(%w[obj books], res3) assert_equal([], res4) r.del('doc') +# REMOVE_END + +# STEP_START func_length +res1 = r.json_set('doc', '$', { 'a' => [[1, 2, 3], [1], 'abcd', 'x'] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.a[?length(@) > 2]') +p res2 # >>> [[1, 2, 3], "abcd"] +# STEP_END + +# REMOVE_START +assert_equal([[1, 2, 3], 'abcd'], res2) +r.del('doc') +# REMOVE_END + +# STEP_START func_count +res1 = r.json_set('doc', '$', [{ 'a' => 1, 'b' => 2, 'c' => 3 }, { 'a' => 1 }]) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$[?count(@.*) == 3]') +p res2 # >>> [{"a"=>1, "b"=>2, "c"=>3}] +# STEP_END + +# REMOVE_START +assert_equal([{ 'a' => 1, 'b' => 2, 'c' => 3 }], res2) +r.del('doc') +# REMOVE_END + +# STEP_START func_value +res1 = r.json_set('doc', '$', [{ 'a' => 1 }, { 'a' => 2 }]) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$[?value(@.a) == 1]') +p res2 # >>> [{"a"=>1}] +# STEP_END + +# REMOVE_START +assert_equal([{ 'a' => 1 }], res2) +r.del('doc') +# REMOVE_END + +# STEP_START func_keys +res1 = r.json_set('doc', '$', { 'obj' => { 'x' => 1, 'y' => 2 } }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.obj.keys()') +p res2 # >>> ["x", "y"] + +res3 = r.json_get('doc', '$.obj.keys().count()') +p res3 # >>> [2] +# STEP_END + +# REMOVE_START +assert_equal(%w[x y], res2) +assert_equal([2], res3) +r.del('doc') +# REMOVE_END + +# STEP_START func_match_search +res1 = r.json_set('doc', '$', { 'a' => ['abc', 'xabc', 'a', 'b'] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.a[?match(@, "a.*")]') +p res2 # >>> ["abc", "a"] + +res3 = r.json_set('doc', '$', { 'a' => ['abc', 'xyz', 'b'] }) +puts res3 # >>> OK + +res4 = r.json_get('doc', '$.a[?search(@, "b")]') +p res4 # >>> ["abc", "b"] +# STEP_END + +# REMOVE_START +assert_equal(%w[abc a], res2) +assert_equal(%w[abc b], res4) +r.del('doc') +# REMOVE_END + +# STEP_START func_concat +res1 = r.json_set('doc', '$', { 'a' => [{ 'x' => 'a', 'y' => 'b' }, { 'x' => 'a', 'y' => 'c' }] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.a[?concat(@.x, @.y) == "ab"]') +p res2 # >>> [{"x"=>"a", "y"=>"b"}] +# STEP_END + +# REMOVE_START +assert_equal([{ 'x' => 'a', 'y' => 'b' }], res2) +r.del('doc') +# REMOVE_END + +# STEP_START func_math +res1 = r.json_set('doc', '$', { 'a' => [2.1, 3.9, 1.0] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.a[?ceiling(@) == 3]') +p res2 # >>> [2.1] + +res3 = r.json_set('doc', '$', { 'a' => [2.1, 2.9, 3.5] }) +puts res3 # >>> OK + +res4 = r.json_get('doc', '$.a[?floor(@) == 2]') +p res4 # >>> [2.1, 2.9] + +res5 = r.json_set('doc', '$', { 'a' => [{ 'n' => -5 }, { 'n' => 5 }, { 'n' => -3 }] }) +puts res5 # >>> OK + +res6 = r.json_get('doc', '$.a[?abs(@.n) == 5]') +p res6 # >>> [{"n"=>-5}, {"n"=>5}] +# STEP_END + +# REMOVE_START +assert_equal([2.1], res2) +assert_equal([2.1, 2.9], res4) +assert_equal([{ 'n' => -5 }, { 'n' => 5 }], res6) +r.del('doc') +# REMOVE_END + +# STEP_START func_array_access +res1 = r.json_set('doc', '$', { 'a' => [{ 'n' => [1, 2] }, { 'n' => [9, 8] }] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.a[?first(@.n) == 1]') +p res2 # >>> [{"n"=>[1, 2]}] + +res3 = r.json_get('doc', '$.a[?last(@.n) == 8]') +p res3 # >>> [{"n"=>[9, 8]}] + +res4 = r.json_get('doc', '$.a[?index(@.n, -1) == 2]') +p res4 # >>> [{"n"=>[1, 2]}] +# STEP_END + +# REMOVE_START +assert_equal([{ 'n' => [1, 2] }], res2) +assert_equal([{ 'n' => [9, 8] }], res3) +assert_equal([{ 'n' => [1, 2] }], res4) +r.del('doc') +# REMOVE_END + +# STEP_START func_aggregate +res1 = r.json_set('doc', '$', { 'a' => [{ 'n' => [3, 1, 2] }, { 'n' => [5, 6] }] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.a[?sum(@.n) == 6]') +p res2 # >>> [{"n"=>[3, 1, 2]}] + +res3 = r.json_get('doc', '$.a[?avg(@.n) == 2]') +p res3 # >>> [{"n"=>[3, 1, 2]}] +# STEP_END + +# REMOVE_START +assert_equal([{ 'n' => [3, 1, 2] }], res2) +assert_equal([{ 'n' => [3, 1, 2] }], res3) +r.del('doc') +# REMOVE_END + +# STEP_START func_append +res1 = r.json_set('doc', '$', { 'arr' => [1, 2, 3] }) +puts res1 # >>> OK + +res2 = r.json_get('doc', '$.arr.append(9)') +p res2 # >>> [1, 2, 3, 9] + +res3 = r.json_set('doc', '$', { 'books' => [{ 't' => 'a', 'price' => 30 }, { 't' => 'b', 'price' => 5 }] }) +puts res3 # >>> OK + +res4 = r.json_get('doc', '$.books[?(@.price >= 10)].append({"t":"X"})') +p res4 # >>> [{"t"=>"a", "price"=>30}, {"t"=>"X"}] +# STEP_END + +# REMOVE_START +assert_equal([1, 2, 3, 9], res2) +assert_equal([{ 't' => 'a', 'price' => 30 }, { 't' => 'X' }], res4) +r.del('doc') r.close # REMOVE_END diff --git a/local_examples/json_path_ops/rust-async/json_path_ops.rs b/local_examples/json_path_ops/rust-async/json_path_ops.rs index 92a637ab23..0a9ae19aa3 100644 --- a/local_examples/json_path_ops/rust-async/json_path_ops.rs +++ b/local_examples/json_path_ops/rust-async/json_path_ops.rs @@ -449,5 +449,449 @@ mod json_path_ops_tests { // REMOVE_END // STEP_END + // STEP_START func_length + let _: bool = match r.json_set("doc", "$", &json!({"a":[[1,2,3],[1],"abcd","x"]})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.a[?length(@) > 2]").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [[1,2,3],"abcd"] + // REMOVE_START + assert_eq!(res1, r#"[[1,2,3],"abcd"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_count + let _: bool = match r.json_set("doc", "$", &json!([{"a":1,"b":2,"c":3},{"a":1}])).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$[?count(@.*) == 3]").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [{"a":1,"b":2,"c":3}] + // REMOVE_START + assert_eq!(res1, r#"[{"a":1,"b":2,"c":3}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_value + let _: bool = match r.json_set("doc", "$", &json!([{"a":1},{"a":2}])).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$[?value(@.a) == 1]").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [{"a":1}] + // REMOVE_START + assert_eq!(res1, r#"[{"a":1}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_keys + let _: bool = match r.json_set("doc", "$", &json!({"obj":{"x":1,"y":2}})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.obj.keys()").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> ["x","y"] + // REMOVE_START + assert_eq!(res1, r#"["x","y"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.obj.keys().count()").await { + Ok(res2) => { + let res2: String = res2; + println!("{res2}"); // >>> [2] + // REMOVE_START + assert_eq!(res2, "[2]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_match_search + let _: bool = match r.json_set("doc", "$", &json!({"a":["abc","xabc","a","b"]})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", r#"$.a[?match(@, "a.*")]"#).await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> ["abc","a"] + // REMOVE_START + assert_eq!(res1, r#"["abc","a"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + let _: bool = match r.json_set("doc", "$", &json!({"a":["abc","xyz","b"]})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", r#"$.a[?search(@, "b")]"#).await { + Ok(res2) => { + let res2: String = res2; + println!("{res2}"); // >>> ["abc","b"] + // REMOVE_START + assert_eq!(res2, r#"["abc","b"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_concat + let _: bool = match r.json_set( + "doc", + "$", + &json!({"a":[{"x":"a","y":"b"},{"x":"a","y":"c"}]}), + ).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", r#"$.a[?concat(@.x, @.y) == "ab"]"#).await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [{"x":"a","y":"b"}] + // REMOVE_START + assert_eq!(res1, r#"[{"x":"a","y":"b"}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_math + let _: bool = match r.json_set("doc", "$", &json!({"a":[2.1,3.9,1.0]})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.a[?ceiling(@) == 3]").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [2.1] + // REMOVE_START + assert_eq!(res1, "[2.1]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + let _: bool = match r.json_set("doc", "$", &json!({"a":[2.1,2.9,3.5]})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.a[?floor(@) == 2]").await { + Ok(res2) => { + let res2: String = res2; + println!("{res2}"); // >>> [2.1,2.9] + // REMOVE_START + assert_eq!(res2, "[2.1,2.9]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + let _: bool = match r.json_set( + "doc", + "$", + &json!({"a":[{"n":-5},{"n":5},{"n":-3}]}), + ).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.a[?abs(@.n) == 5]").await { + Ok(res3) => { + let res3: String = res3; + println!("{res3}"); // >>> [{"n":-5},{"n":5}] + // REMOVE_START + assert_eq!(res3, r#"[{"n":-5},{"n":5}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_array_access + let _: bool = match r.json_set( + "doc", + "$", + &json!({"a":[{"n":[1,2]},{"n":[9,8]}]}), + ).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.a[?first(@.n) == 1]").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [{"n":[1,2]}] + // REMOVE_START + assert_eq!(res1, r#"[{"n":[1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?last(@.n) == 8]").await { + Ok(res2) => { + let res2: String = res2; + println!("{res2}"); // >>> [{"n":[9,8]}] + // REMOVE_START + assert_eq!(res2, r#"[{"n":[9,8]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?index(@.n, -1) == 2]").await { + Ok(res3) => { + let res3: String = res3; + println!("{res3}"); // >>> [{"n":[1,2]}] + // REMOVE_START + assert_eq!(res3, r#"[{"n":[1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_aggregate + let _: bool = match r.json_set( + "doc", + "$", + &json!({"a":[{"n":[3,1,2]},{"n":[5,6]}]}), + ).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.a[?sum(@.n) == 6]").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [{"n":[3,1,2]}] + // REMOVE_START + assert_eq!(res1, r#"[{"n":[3,1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?avg(@.n) == 2]").await { + Ok(res2) => { + let res2: String = res2; + println!("{res2}"); // >>> [{"n":[3,1,2]}] + // REMOVE_START + assert_eq!(res2, r#"[{"n":[3,1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + + // STEP_START func_append + let _: bool = match r.json_set("doc", "$", &json!({"arr":[1,2,3]})).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", "$.arr.append(9)").await { + Ok(res1) => { + let res1: String = res1; + println!("{res1}"); // >>> [1,2,3,9] + // REMOVE_START + assert_eq!(res1, "[1,2,3,9]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + let _: bool = match r.json_set( + "doc", + "$", + &json!({"books":[{"t":"a","price":30},{"t":"b","price":5}]}), + ).await { + Ok(v) => v, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + }; + + match r.json_get("doc", r#"$.books[?(@.price >= 10)].append({"t":"X"})"#).await { + Ok(res2) => { + let res2: String = res2; + println!("{res2}"); // >>> [{"t":"a","price":30},{"t":"X"}] + // REMOVE_START + assert_eq!(res2, r#"[{"t":"a","price":30},{"t":"X"}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc").await; + // REMOVE_END + // STEP_END + } } diff --git a/local_examples/json_path_ops/rust-sync/json_path_ops.rs b/local_examples/json_path_ops/rust-sync/json_path_ops.rs index b9e38ebdef..d1bded0e14 100644 --- a/local_examples/json_path_ops/rust-sync/json_path_ops.rs +++ b/local_examples/json_path_ops/rust-sync/json_path_ops.rs @@ -509,5 +509,513 @@ mod json_path_ops_tests { // REMOVE_END // STEP_END + // STEP_START func_length + match r.json_set("doc", "$", &json!({"a":[[1,2,3],[1],"abcd","x"]})) { + Ok(res32) => { + let res32: bool = res32; + println!("{}", if res32 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res32); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?length(@) > 2]") { + Ok(res33) => { + let res33: String = res33; + println!("{res33}"); // >>> [[1,2,3],"abcd"] + // REMOVE_START + assert_eq!(res33, r#"[[1,2,3],"abcd"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_count + match r.json_set("doc", "$", &json!([{"a":1,"b":2,"c":3},{"a":1}])) { + Ok(res34) => { + let res34: bool = res34; + println!("{}", if res34 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res34); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$[?count(@.*) == 3]") { + Ok(res35) => { + let res35: String = res35; + println!("{res35}"); // >>> [{"a":1,"b":2,"c":3}] + // REMOVE_START + assert_eq!(res35, r#"[{"a":1,"b":2,"c":3}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_value + match r.json_set("doc", "$", &json!([{"a":1},{"a":2}])) { + Ok(res36) => { + let res36: bool = res36; + println!("{}", if res36 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res36); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$[?value(@.a) == 1]") { + Ok(res37) => { + let res37: String = res37; + println!("{res37}"); // >>> [{"a":1}] + // REMOVE_START + assert_eq!(res37, r#"[{"a":1}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_keys + match r.json_set("doc", "$", &json!({"obj":{"x":1,"y":2}})) { + Ok(res38) => { + let res38: bool = res38; + println!("{}", if res38 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res38); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.obj.keys()") { + Ok(res39) => { + let res39: String = res39; + println!("{res39}"); // >>> ["x","y"] + // REMOVE_START + assert_eq!(res39, r#"["x","y"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.obj.keys().count()") { + Ok(res40) => { + let res40: String = res40; + println!("{res40}"); // >>> [2] + // REMOVE_START + assert_eq!(res40, "[2]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_match_search + match r.json_set("doc", "$", &json!({"a":["abc","xabc","a","b"]})) { + Ok(res41) => { + let res41: bool = res41; + println!("{}", if res41 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res41); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", r#"$.a[?match(@, "a.*")]"#) { + Ok(res42) => { + let res42: String = res42; + println!("{res42}"); // >>> ["abc","a"] + // REMOVE_START + assert_eq!(res42, r#"["abc","a"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_set("doc", "$", &json!({"a":["abc","xyz","b"]})) { + Ok(res43) => { + let res43: bool = res43; + println!("{}", if res43 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res43); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", r#"$.a[?search(@, "b")]"#) { + Ok(res44) => { + let res44: String = res44; + println!("{res44}"); // >>> ["abc","b"] + // REMOVE_START + assert_eq!(res44, r#"["abc","b"]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_concat + match r.json_set("doc", "$", &json!({"a":[{"x":"a","y":"b"},{"x":"a","y":"c"}]})) { + Ok(res45) => { + let res45: bool = res45; + println!("{}", if res45 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res45); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", r#"$.a[?concat(@.x, @.y) == "ab"]"#) { + Ok(res46) => { + let res46: String = res46; + println!("{res46}"); // >>> [{"x":"a","y":"b"}] + // REMOVE_START + assert_eq!(res46, r#"[{"x":"a","y":"b"}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_math + match r.json_set("doc", "$", &json!({"a":[2.1,3.9,1.0]})) { + Ok(res47) => { + let res47: bool = res47; + println!("{}", if res47 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res47); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?ceiling(@) == 3]") { + Ok(res48) => { + let res48: String = res48; + println!("{res48}"); // >>> [2.1] + // REMOVE_START + assert_eq!(res48, "[2.1]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_set("doc", "$", &json!({"a":[2.1,2.9,3.5]})) { + Ok(res49) => { + let res49: bool = res49; + println!("{}", if res49 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res49); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?floor(@) == 2]") { + Ok(res50) => { + let res50: String = res50; + println!("{res50}"); // >>> [2.1,2.9] + // REMOVE_START + assert_eq!(res50, "[2.1,2.9]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_set("doc", "$", &json!({"a":[{"n":-5},{"n":5},{"n":-3}]})) { + Ok(res51) => { + let res51: bool = res51; + println!("{}", if res51 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res51); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?abs(@.n) == 5]") { + Ok(res52) => { + let res52: String = res52; + println!("{res52}"); // >>> [{"n":-5},{"n":5}] + // REMOVE_START + assert_eq!(res52, r#"[{"n":-5},{"n":5}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_array_access + match r.json_set("doc", "$", &json!({"a":[{"n":[1,2]},{"n":[9,8]}]})) { + Ok(res53) => { + let res53: bool = res53; + println!("{}", if res53 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res53); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?first(@.n) == 1]") { + Ok(res54) => { + let res54: String = res54; + println!("{res54}"); // >>> [{"n":[1,2]}] + // REMOVE_START + assert_eq!(res54, r#"[{"n":[1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?last(@.n) == 8]") { + Ok(res55) => { + let res55: String = res55; + println!("{res55}"); // >>> [{"n":[9,8]}] + // REMOVE_START + assert_eq!(res55, r#"[{"n":[9,8]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?index(@.n, -1) == 2]") { + Ok(res56) => { + let res56: String = res56; + println!("{res56}"); // >>> [{"n":[1,2]}] + // REMOVE_START + assert_eq!(res56, r#"[{"n":[1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_aggregate + match r.json_set("doc", "$", &json!({"a":[{"n":[3,1,2]},{"n":[5,6]}]})) { + Ok(res57) => { + let res57: bool = res57; + println!("{}", if res57 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res57); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?sum(@.n) == 6]") { + Ok(res58) => { + let res58: String = res58; + println!("{res58}"); // >>> [{"n":[3,1,2]}] + // REMOVE_START + assert_eq!(res58, r#"[{"n":[3,1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.a[?avg(@.n) == 2]") { + Ok(res59) => { + let res59: String = res59; + println!("{res59}"); // >>> [{"n":[3,1,2]}] + // REMOVE_START + assert_eq!(res59, r#"[{"n":[3,1,2]}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + + // STEP_START func_append + match r.json_set("doc", "$", &json!({"arr":[1,2,3]})) { + Ok(res60) => { + let res60: bool = res60; + println!("{}", if res60 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res60); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", "$.arr.append(9)") { + Ok(res61) => { + let res61: String = res61; + println!("{res61}"); // >>> [1,2,3,9] + // REMOVE_START + assert_eq!(res61, "[1,2,3,9]"); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + match r.json_set("doc", "$", &json!({"books":[{"t":"a","price":30},{"t":"b","price":5}]})) { + Ok(res62) => { + let res62: bool = res62; + println!("{}", if res62 { "OK" } else { "(nil)" }); // >>> OK + // REMOVE_START + assert!(res62); + // REMOVE_END + }, + Err(e) => { + println!("Error setting doc: {e}"); + return; + } + } + + match r.json_get("doc", r#"$.books[?(@.price >= 10)].append({"t":"X"})"#) { + Ok(res63) => { + let res63: String = res63; + println!("{res63}"); // >>> [{"t":"a","price":30},{"t":"X"}] + // REMOVE_START + assert_eq!(res63, r#"[{"t":"a","price":30},{"t":"X"}]"#); + // REMOVE_END + }, + Err(e) => { + println!("Error getting doc: {e}"); + return; + } + } + + // REMOVE_START + let _: Result = r.del("doc"); + // REMOVE_END + // STEP_END + } }