Futriix JSON
Futriix-json is a C++ Futriix-Module that provides native JSON (JavaScript Object Notation) support for Futriix. The implementation complies with RFC7159 and ECMA-404 JSON data interchange standards. Users can natively store, query, and modify JSON data structures using the JSONPath query language. The query expressions support advanced capabilities including wildcard selections, filter expressions, array slices, union operations, and recursive searches.
Futriix-json leverages RapidJSON, a high-performance JSON parser and generator for C++, chosen for its small footprint and exceptional performance and memory efficiency. As a header-only library with no external dependencies, RapidJSON provides robust Unicode support while maintaining a compact memory profile of just 16 bytes per JSON value on most 32/64-bit machines.
Building and Testing
To build the module and run tests
# Build valkey-server (unstable) and run integration tests
./build.sh
The default valkey version is "unstable". To override it, do:
# Build valkey-server (8.0) and run integration tests
SERVER_VERSION=8.0 ./build.sh
Custom compiler flags can be passed to the build script via environment variable CFLAGS. For example:
CFLAGS="-O0 -Wno-unused-function" ./build.sh
To build the module with ASAN and run tests
export ASAN_BUILD=true
./build.sh
To build just the module
mkdir build
cd build
cmake ..
make
The default valkey version is "unstable". To override it, do:
mkdir build
cd build
cmake .. -DVALKEY_VERSION=8.0
make
Custom compiler flags can be passed to cmake via variable CFLAGS. For example:
mkdir build
cd build
cmake .. -DCFLAGS="-O0 -Wno-unused-function"
make
To run all unit tests:
cd build
make -j unit
To run all integration tests:
make -j test
To run one integration test:
TEST_PATTERN=<test-function-or-file> make -j test
e.g.,
TEST_PATTERN=test_sanity make -j test
TEST_PATTERN=test_rdb.py make -j test
Load the Module
To test the module with a Valkey, you can load the module using any of the following ways:
Using valkey.conf:
1. Add the following to valkey.conf:
loadmodule /path/to/libjson.so
2. Start valkey-server:
valkey-server /path/to/valkey.conf
Starting valkey with --loadmodule option:
valkey-server --loadmodule /path/to/libjson.so
Using Valkey command MODULE LOAD:
1. Connect to a running Valkey instance using valkey-cli
2. Execute Valkey command:
MODULE LOAD /path/to/libjson.so
Usage Example
The first JSON command to try is JSON.SET, which sets a Redis key with a JSON value. JSON.SET accepts all JSON value types. This example creates a JSON string:
> JSON.SET bike $ '"Hyperion"'
OK
> JSON.GET bike $
"[\"Hyperion\"]"
> JSON.TYPE bike $
1) "string"
Note how the commands include the dollar sign character $. This is the path to the value in the JSON document (in this case it just means the root).
Here are a few more string operations. JSON.STRLEN tells you the length of the string, and you can append another string to it with JSON.STRAPPEND.
JSON.STRLEN bike $
- (integer) 8
JSON.STRAPPEND bike $ '" (Enduro bikes)"'
- (integer) 23
JSON.GET bike $ "["Hyperion (Enduro bikes)"]"
Numbers can be incremented and multiplied:
> JSON.SET crashes $ 0
OK
> JSON.NUMINCRBY crashes $ 1
"[1]"
> JSON.NUMINCRBY crashes $ 1.5
"[2.5]"
> JSON.NUMINCRBY crashes $ -0.75
"[1.75]"
> JSON.NUMMULTBY crashes $ 24
"[42]"
Here's a more interesting example that includes JSON arrays and objects:
> JSON.SET newbike $ '["Deimos", {"crashes": 0}, null]'
OK
> JSON.GET newbike $
"[[\"Deimos\",{\"crashes\":0},null]]"
> JSON.GET newbike $[1].crashes
"[0]"
> JSON.DEL newbike $[-1]
(integer) 1
> JSON.GET newbike $
"[[\"Deimos\",{\"crashes\":0}]]"
The JSON.DEL command deletes any JSON value you specify with the path parameter.
You can manipulate arrays with a dedicated subset of JSON commands:
> JSON.SET riders $ []
OK
> JSON.ARRAPPEND riders $ '"Norem"'
1) (integer) 1
> JSON.GET riders $
"[[\"Norem\"]]"
> JSON.ARRINSERT riders $ 1 '"Prickett"' '"Royce"' '"Castilla"'
1) (integer) 4
> JSON.GET riders $
"[[\"Norem\",\"Prickett\",\"Royce\",\"Castilla\"]]"
> JSON.ARRTRIM riders $ 1 1
1) (integer) 1
> JSON.GET riders $
"[[\"Prickett\"]]"
> JSON.ARRPOP riders $
1) "\"Prickett\""
> JSON.ARRPOP riders $
1) (nil)
JSON objects also have their own commands:
> JSON.SET bike:1 $ '{"model": "Deimos", "brand": "Ergonom", "price": 4972}'
OK
> JSON.OBJLEN bike:1 $
1) (integer) 3
> JSON.OBJKEYS bike:1 $
1) 1) "model"
2) "brand"
3) "price"
Format Cli Output
$ valkey-cli --raw
> JSON.GET obj INDENT "\t" NEWLINE "\n" SPACE " " $
[
{
"name": "Leonard Cohen",
"lastSeen": 1478476800,
"loggedOut": true
}
]
Supported Module Commands
JSON.ARRAPPEND
JSON.ARRINDEX
JSON.ARRINSERT
JSON.ARRLEN
JSON.ARRPOP
JSON.ARRTRIM
JSON.CLEAR
JSON.DEBUG
JSON.DEL
JSON.FORGET
JSON.GET
JSON.MGET
JSON.MSET (#16)
JSON.NUMINCRBY
JSON.NUMMULTBY
JSON.OBJLEN
JSON.OBJKEYS
JSON.RESP
JSON.SET
JSON.STRAPPEND
JSON.STRLEN
JSON.TOGGLE
JSON.TYPE