diff --git a/Makefile b/Makefile index 41432e024..9e44d0bad 100644 --- a/Makefile +++ b/Makefile @@ -29,12 +29,16 @@ build: ## generate the dicedb binary for the current OS and architecture @echo "Building for $(GOOS)/$(GOARCH)" CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o ./dicedb +build-debug: ## generate the dicedb binary for the current OS and architecture + @echo "Building for $(GOOS)/$(GOARCH)" + CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -gcflags="all=-N -l" -o ./dicedb + ##@ Testing # Changing the parallel package count to 1 due to a possible race condition which causes the tests to get stuck. # TODO: Fix the tests to run in parallel, and remove the -p=1 flag. test: ## run the integration tests - go test -v -race -count=1 -p=1 ./integration_tests/... + go test -race -count=1 -p=1 ./integration_tests/... test-one: ## run a single integration test function by name (e.g. make test-one TEST_FUNC=TestSetGet) go test -v -race -count=1 --run $(TEST_FUNC) ./integration_tests/... diff --git a/README.md b/README.md index c3845f361..2335c52bb 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ Although DiceDB is a drop-in replacement of Redis, which means almost no learnin The easiest way to get started with DiceDB is using [Docker](https://www.docker.com/) by running the following command. ```bash -docker run -p 7379:7379 dicedb/dicedb --enable-multithreading --enable-watch +docker run -p 7379:7379 dicedb/dicedb --enable-watch ``` The above command will start the DiceDB server running locally on the port `7379` and you can connect @@ -60,10 +60,10 @@ To run DiceDB for local development or running from source, you will need ```bash git clone https://github.com/dicedb/dice cd dice -go run main.go --enable-multithreading --enable-watch +go run main.go --enable-watch ``` -You can skip passing the two flags if you are not working with multi-threading or `.WATCH` features. +You can skip passing the flag if you are not working with `.WATCH` feature. 1. Install GoLangCI diff --git a/docs/src/content/docs/commands/JSON.OBJKEYS.md b/docs/src/content/docs/commands/JSON.OBJKEYS.md index 8a72b3364..dfe28679b 100644 --- a/docs/src/content/docs/commands/JSON.OBJKEYS.md +++ b/docs/src/content/docs/commands/JSON.OBJKEYS.md @@ -1,6 +1,6 @@ --- title: JSON.OBJKEYS -description: The `JSON.OBJKEYS` command command in DiceDB retrieves the keys of a JSON object located at a specified path within the document stored under the given key. This command is useful when you want to list the fields within a JSON object stored in a database. +description: The `JSON.OBJKEYS` command in DiceDB retrieves the keys of a JSON object located at a specified path within the document stored under the given key. This command is useful when you want to list the fields within a JSON object stored in a database. --- The `JSON.OBJKEYS` command in DiceDB allows users to access the keys of a JSON object stored at a specific path within a document identified by a given key. By executing this command, users can easily retrieve a list of the fields present in the JSON object, making it a valuable tool for exploring and managing the structure of JSON data stored in the database. @@ -26,7 +26,7 @@ JSON.OBJKEYS key [path] | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- | | Success | ([]String) `Array of strings containing the keys present within the JSON object at the specified path.` | | Key does not exist | Error: `(error) ERR could not perform this operation on a key that doesn't exist` | -| Wrong number of arguments | Error: `(error) ERR wrong number of arguments for JSON.ARRTRIM command` | +| Wrong number of arguments | Error: `(error) ERR wrong number of arguments for JSON.OBJKEYS command` | | Key has wrong type | Error: `(error) ERR Existing key has wrong Dice type` | | Operation attempted on a key with an incompatible type | Error: `(error) ERR WRONGTYPE Operation against a key holding the wrong kind of value` | @@ -41,7 +41,7 @@ JSON.OBJKEYS key [path] 1. `Wrong number of arguments`: - - Error Message: `(error) ERR wrong number of arguments for JSON.ARRINSERT command` + - Error Message: `(error) ERR wrong number of arguments for JSON.OBJKEYS command` - Raised if the number of arguments are less or more than expected. 2. `Key doesn't exist`: @@ -52,7 +52,7 @@ JSON.OBJKEYS key [path] 3. `Key has wrong Dice type`: - Error Message: `(error) ERR Existing key has wrong Dice type` - - Raised if thevalue of the specified key doesn't match the specified value in DIceDb + - Raised if thevalue of the specified key doesn't match the specified value in DiceDb 4. `Path doesn't exist`: diff --git a/docs/src/content/docs/commands/JSON.OBJLEN.md b/docs/src/content/docs/commands/JSON.OBJLEN.md new file mode 100644 index 000000000..5c756348c --- /dev/null +++ b/docs/src/content/docs/commands/JSON.OBJLEN.md @@ -0,0 +1,123 @@ +--- +title: JSON.OBJLEN +description: The `JSON.OBJLEN` command in DiceDB retrieves the number of keys stored in the JSON object located at key. +--- + +The `JSON.OBJLEN` command in DiceDB retrieves the number of keys stored in the JSON object located at key. By default, it counts the keys in the whole JSON object, but you can optionally specify a JSONPath to narrow the operation to a subset of the JSON object. + +This functionality is particularly useful for developers working with complex JSON structures who need to quickly gauge the size of those structures. + +## Syntax + +```bash +JSON.OBJLEN key [path] +``` + +## Parameters + +| Parameter | Description | Type | Required | +| --------- | ------------------------------------------------------- | ------ | -------- | +| `key` | The name of the key holding the JSON document. | String | Yes | +| `path` | JSONPath pointing to an array within the JSON document. | String | No | + +## Return values + +| Condition | Return Value | +| ------------------------------- | ------------------------------------------------------------------------------------------- | +| Command is successful | `Integer` denoting the number of keys length of the list at the specified key. | +| Wrong number of arguments | Error: `(error) ERR wrong number of arguments for JSON.OBJLEN command` | +| Key does not exist | Error: `(error) ERR could not perform this operation on a key that doesn't exist` | +| Key is not for a JSON object | Error: `(error) ERR WRONGTYPE Operation against a key holding the wrong kind of value` | +| Path malformed or doesn't exist | Error: `(error) ERR Path 'foo' does not exist` | + +## Behaviour + +- Root Path (Default): If no path is provided, JSON.OBJLEN retrieves keys from the root object of the JSON document. +- Path Validation: If the specified path does not point to an object (e.g., if it points to a scalar, array, or does not exist), the command returns `(nil)` for that path. +- Non-existing Key: If the specified key does not exist in the database, an error is returned. +- Invalid JSON Path: If the provided JSONPath expression is invalid, an error message with the details of the parse error is returned. + +## Errors + +1. `Wrong number of arguments`: + + - Error Message: `(error) ERR wrong number of arguments for JSON.OBJLEN command` + - Happens if the number of arguments is less or more than required. (It must have at least one argument, or at most two arguments). + +2. `Key doesn't exist`: + + - Error Message: `(error) ERR could not perform this operation on a key that doesn't exist` + - Happens if the specified key does not exist in the DiceDB database. + +3. `Key has wrong Dice type`: + + - Error Message: `(error) ERR WRONGTYPE Operation against a key holding the wrong kind of value` + - Happens if an operation attempted on a key with an incompatible type. + +4. `ERR Path 'foo' does not exist`: + - Error Message: `(error) ERR Path 'foo' does not exist` + - Happens if the path string provided (ie. 'foo') could not be parsed into a valid JSONPath, or if the JSONPath does not exist in the object. + +## Example Usage + +### Basic usage + +Get number of keys in the Root JSON Object. You can specify the JSON root using the symbol `$`. + +```bash +127.0.0.1:7379> JSON.SET a $ '{"name": "Alice", "age": 30, "address": {"city": "Wonderland", "zipcode": "12345"}}' +"OK" +127.0.0.1:7379> JSON.OBJLEN a $ +1) 3 +``` +It returns 3, because there are three root keys in the root JSON object: `name`, `age`, and `address`. + +Or, if you don't want to specify a JSON path, it may be omitted. The path defaults to the root, and the result is given as a scalar: +```bash +127.0.0.1:7379> JSON.OBJLEN a +3 +``` + + +### Keys inside nested object + +To count the number of keys inside a nested object, specify a JSON Path. The root of the JSON object is referred to by the `$` symbol. + +```bash +127.0.0.1:7379> JSON.SET b $ '{"name": "Alice", "address": {"city": "Wonderland", "state": "Fantasy", "zipcode": "12345"}}' +"OK" +127.0.0.1:7379> JSON.OBJLEN b $.address +1) 3 +``` +Here, it returns 3 because it's counting the three keys inside the `$.address` JSON object: `city`, `state`, and `zipcode`. + +### When path is not a JSON object + +When `path` points to an existing element in a JSON object, but that element is not itself a JSON object, the result is `(nil)`. + +```bash +127.0.0.1:7379> JSON.SET c $ '{"name": "Alice", "age": 30}' +"OK" +127.0.0.1:7379> JSON.OBJLEN c $.age +1) (nil) +``` + +### When path doesn't exist + +When `path` does not exist, the result is an empty list or set. + +```bash +127.0.0.1:7379> JSON.SET d $ '{"name": "Alice", "address": {"city": "Wonderland"}}' +"OK" +127.0.0.1:7379> JSON.OBJLEN d $.nonexistentPath +(empty list or set) +``` + +### Invalid Usage: When key doesn't exist + +When `key` does not exist, the result is an error. + +```bash +127.0.0.1:7379> JSON.OBJLEN nonexistent_key $ +(error) ERR could not perform this operation on a key that doesn't exist +``` diff --git a/docs/src/content/docs/commands/OBJECT.md b/docs/src/content/docs/commands/OBJECT.md index 5929ae5d9..0256f7918 100644 --- a/docs/src/content/docs/commands/OBJECT.md +++ b/docs/src/content/docs/commands/OBJECT.md @@ -16,7 +16,6 @@ OBJECT - ``: The specific operation you want to perform on the key. The available subcommands are: - `REFCOUNT`: Returns the number of references of the value associated with the specified key. - - `ENCODING`: Returns the internal representation (encoding) used to store the value associated with the specified key. - `IDLETIME`: Returns the number of seconds since the object was last accessed. - `FREQ`: Returns the access frequency of a key, if the LFU (Least Frequently Used) eviction policy is enabled. @@ -27,7 +26,6 @@ OBJECT The return value depends on the subcommand used: - `REFCOUNT`: Returns an integer representing the reference count of the key. -- `ENCODING`: Returns a string representing the encoding type of the key. - `IDLETIME`: Returns an integer representing the idle time in seconds. - `FREQ`: Returns an integer representing the access frequency of the key. @@ -38,7 +36,6 @@ When the `OBJECT` command is executed, DiceDB inspects the specified key and ret ### Subcommand Behaviours - `REFCOUNT`: This subcommand returns the number of references to the key's value. A higher reference count indicates that the value is being shared among multiple keys or clients. -- `ENCODING`: This subcommand reveals the internal representation of the key's value, such as `int`, `embstr`, `raw`, `ziplist`, `linkedlist`, etc. - `IDLETIME`: This subcommand provides the time in seconds since the key was last accessed. It is useful for identifying stale keys. - `FREQ`: This subcommand returns the access frequency of the key, which is useful when using the LFU eviction policy. @@ -61,15 +58,6 @@ OBJECT REFCOUNT mykey This response indicates that the value associated with `mykey` has a reference count of 1. -### Using the `ENCODING` Subcommand - -```bash -OBJECT ENCODING mykey -"embstr" -``` - -This response indicates that the value associated with `mykey` is stored using the `embstr` encoding. - ### Using the `IDLETIME` Subcommand ```bash diff --git a/docs/src/content/docs/commands/SETEX.md b/docs/src/content/docs/commands/SETEX.md new file mode 100644 index 000000000..7415a2173 --- /dev/null +++ b/docs/src/content/docs/commands/SETEX.md @@ -0,0 +1,87 @@ +--- +title: SETEX +description: The SETEX command in DiceDB is used to set the value of a key and its expiration time in seconds. This command is atomic and is commonly used to create time-sensitive key-value pairs. +sidebar: + badge: + text: Deprecated + variant: danger +--- + +The SETEX command in DiceDB is used to set the value of a key and its expiration time in seconds. This command is atomic and is commonly used to create time-sensitive key-value pairs. + +## Syntax + +```bash +SETEX key seconds value +``` + +## Parameters + +| Parameter | Description | Type | Required | +| --------- | ------------------------------------------------------------------------- | ------- | -------- | +| `key` | The name of the key to be set. | String | Yes | +| `seconds` | Expiration time for the key in seconds. | Integer | Yes | +| `value` | The value to be set for the key. | Integer | No | + +## Return values + +| Condition | Return Value | +| ------------------------------------------- | ----------------------------------------------- | +| Command is successful | `OK` | +| Syntax or specified constraints are invalid | error | + +## Behaviour + +- The SETEX command sets the value of a key and specifies its expiration time in seconds. +- If the specified key already exists, the value is overwritten, and the new expiration time is set. +- If the key does not exist, it is created with the specified expiration time. +- If the provided expiration time is invalid or not an integer, the command will return an error. +- This command is equivalent to using SET key value EX seconds but provides a more concise and dedicated syntax. + +## Errors + +1. `Missing or invalid expiration time`: + + - Error Message: `(error) ERR value is not an integer or out of range` + - Occurs if the expiration time is not a valid positive integer. + +2. `Missing required arguments`: + + - Error Message: `(error) ERR wrong number of arguments for 'SETEX' command` + - Occurs if any of the required arguments (key, seconds, or value) are not provided. + +## Example Usage + +### Basic Usage + +Set a key `foo` with the value `bar` to expire in `10` seconds: + +```bash +127.0.0.1:7379> SETEX foo 10 bar +OK +``` + +Set a key `foo` with the value `new_value`, overwriting the existing value and resetting the expiration time: + +```bash +127.0.0.1:7379> SETEX foo 20 new_value +OK +``` + +### Invalid usage + +Setting a key with an invalid expiration time will result in an error: + +```bash +127.0.0.1:7379> SETEX foo -10 bar +(error) ERROR invalid expire time in 'setex' command +``` + +Attempting to use the command with missing arguments will result in an error: +```bash +127.0.0.1:7379> SETEX foo 10 +(error) ERROR wrong number of arguments for 'setex' command +``` + +### Notes: +`SETEX` can be replaced via [`SET`](/commands/set) with `EX` option. diff --git a/docs/src/content/docs/get-started/installation.mdx b/docs/src/content/docs/get-started/installation.mdx index 75f9622b2..8ba500b4e 100644 --- a/docs/src/content/docs/get-started/installation.mdx +++ b/docs/src/content/docs/get-started/installation.mdx @@ -16,7 +16,7 @@ We are looking for Early Design Partners, so, if you want to evaluate DiceDB, [b The easiest way to get started with DiceDB is using [Docker](https://www.docker.com/) by running the following command. ```bash -docker run -p 7379:7379 dicedb/dicedb --enable-multithreading --enable-watch +docker run -p 7379:7379 dicedb/dicedb --enable-watch ``` The above command will start the DiceDB server running locally on the port `7379` and you can connect diff --git a/docs/src/content/docs/get-started/reactive-hello-world.mdx b/docs/src/content/docs/get-started/reactive-hello-world.mdx index 744c56866..badd81fed 100644 --- a/docs/src/content/docs/get-started/reactive-hello-world.mdx +++ b/docs/src/content/docs/get-started/reactive-hello-world.mdx @@ -15,12 +15,12 @@ But, before we start, make sure you have ### Starting DiceDB -Start the DiceDB server with the two flags `--enable-multithreading` and `--enable-watch` -to enable multi-threading and watch mode, respectively. Your command would look something +Start the DiceDB server with the flag `--enable-watch` +to enable watch mode. Your command would look something like this ```bash -docker run -p 7379:7379 dicedb/dicedb --enable-multithreading --enable-watch +docker run -p 7379:7379 dicedb/dicedb --enable-watch ``` Also, connect to the database using the CLI as mentioned in the above installation steps or diff --git a/docs/src/pages/redis-compatability.astro b/docs/src/pages/redis-compatability.astro index ff62bb602..238253714 100644 --- a/docs/src/pages/redis-compatability.astro +++ b/docs/src/pages/redis-compatability.astro @@ -776,11 +776,6 @@ const description = ""; MSETNX - - - OBJECT|ENCODING - - OBJECT|FREQ diff --git a/integration_tests/commands/http/append_test.go b/integration_tests/commands/http/append_test.go index 3adb26f4c..5c4150ae2 100644 --- a/integration_tests/commands/http/append_test.go +++ b/integration_tests/commands/http/append_test.go @@ -122,6 +122,19 @@ func TestAPPEND(t *testing.T) { {Command: "del", Body: map[string]interface{}{"key": "bitkey"}}, }, }, + { + name: "SET and SETBIT commands followed by GET", + commands: []HTTPCommand{ + {Command: "SET", Body: map[string]interface{}{"key": "key", "value": "10"}}, + {Command: "SETBIT", Body: map[string]interface{}{"key": "key", "values": []string{"1", "1"}}}, + {Command: "GET", Body: map[string]interface{}{"key": "key"}}, + {Command: "SETBIT", Body: map[string]interface{}{"key": "key", "values": []string{"0", "1"}}}, + }, + expected: []interface{}{"OK", float64(0), "q0", float64(0)}, + cleanup: []HTTPCommand{ + {Command: "del", Body: map[string]interface{}{"key": "key"}}, + }, + }, { name: "APPEND After SET and DEL", commands: []HTTPCommand{ diff --git a/integration_tests/commands/http/bloom_test.go b/integration_tests/commands/http/bloom_test.go index d6c47e41b..8d28958b9 100644 --- a/integration_tests/commands/http/bloom_test.go +++ b/integration_tests/commands/http/bloom_test.go @@ -3,6 +3,7 @@ package http import ( "testing" + diceerrors "github.com/dicedb/dice/internal/errors" "github.com/stretchr/testify/assert" ) @@ -82,7 +83,7 @@ func TestBloomFilter(t *testing.T) { Body: map[string]interface{}{"key": "bf", "values": []interface{}{0.01, 2000}}, }, }, - expected: []interface{}{"OK", "ERR item exists"}, + expected: []interface{}{"OK", diceerrors.ErrKeyExists.Error()}, }, } @@ -199,7 +200,7 @@ func TestBFEdgeCasesAndErrors(t *testing.T) { Body: map[string]interface{}{"key": "bf"}, }, }, - expected: []interface{}{"ERR not found"}, + expected: []interface{}{diceerrors.ErrKeyNotFound.Error()}, }, { name: "BF.RESERVE with a very high error rate", @@ -281,7 +282,7 @@ func TestBFEdgeCasesAndErrors(t *testing.T) { Body: map[string]interface{}{"key": "bf", "values": []interface{}{0.01, 2000}}, }, }, - expected: []interface{}{"OK", "ERR item exists"}, + expected: []interface{}{"OK", diceerrors.ErrKeyExists.Error()}, }, { name: "BF.INFO after multiple additions", diff --git a/integration_tests/commands/http/jsondebug_test.go b/integration_tests/commands/http/jsondebug_test.go index 26db95c84..37ab3a061 100644 --- a/integration_tests/commands/http/jsondebug_test.go +++ b/integration_tests/commands/http/jsondebug_test.go @@ -16,7 +16,7 @@ func TestJSONDEBUG(t *testing.T) { {Command: "JSON.SET", Body: map[string]interface{}{"key": "k1", "path": "$", "json": map[string]interface{}{"a": 1}}}, {Command: "JSON.DEBUG", Body: map[string]interface{}{"values": []interface{}{"MEMORY", "k1"}}}, }, - expected: []interface{}{"OK", float64(89)}, + expected: []interface{}{"OK", float64(72)}, }, { name: "jsondebug with a valid path", diff --git a/integration_tests/commands/resp/bloom_test.go b/integration_tests/commands/resp/bloom_test.go index 53ba8b506..5af5b3044 100644 --- a/integration_tests/commands/resp/bloom_test.go +++ b/integration_tests/commands/resp/bloom_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + diceerrors "github.com/dicedb/dice/internal/errors" "github.com/stretchr/testify/assert" ) @@ -42,7 +43,7 @@ func TestBFReserveAddInfoExists(t *testing.T) { { name: "BF.RESERVE on existent filter returns error", cmds: []string{"BF.RESERVE bf 0.01 1000", "BF.RESERVE bf 0.01 1000"}, - expect: []interface{}{"OK", "ERR item exists"}, + expect: []interface{}{"OK", diceerrors.ErrKeyExists.Error()}, delays: []time.Duration{0, 0}, cleanUp: []string{"DEL bf"}, }, @@ -135,7 +136,7 @@ func TestBFEdgeCasesAndErrors(t *testing.T) { { name: "BF.INFO on a non-existent filter", cmds: []string{"BF.INFO bf"}, - expect: []interface{}{"ERR not found"}, + expect: []interface{}{diceerrors.ErrKeyNotFound.Error()}, delays: []time.Duration{0}, cleanUp: []string{"del bf"}, }, @@ -170,7 +171,7 @@ func TestBFEdgeCasesAndErrors(t *testing.T) { { name: "BF.RESERVE with duplicate filter name", cmds: []string{"BF.RESERVE bf 0.01 1000", "BF.RESERVE bf 0.01 2000"}, - expect: []interface{}{"OK", "ERR item exists"}, + expect: []interface{}{"OK", diceerrors.ErrKeyExists.Error()}, delays: []time.Duration{0, 0}, cleanUp: []string{"del bf"}, }, diff --git a/integration_tests/commands/resp/deque_test.go b/integration_tests/commands/resp/deque_test.go index c935e95d0..db69db3ce 100644 --- a/integration_tests/commands/resp/deque_test.go +++ b/integration_tests/commands/resp/deque_test.go @@ -468,7 +468,7 @@ func TestLInsert(t *testing.T) { { name: "LINSERT wrong type", cmds: []string{"SET k1 val1", "LINSERT k1 before val1 val2"}, - expect: []any{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"}, + expect: []any{"OK", "-WRONGTYPE Operation against a key holding the wrong kind of value"}, }, } @@ -512,7 +512,7 @@ func TestLRange(t *testing.T) { { name: "LRANGE wrong type", cmds: []string{"SET k1 val1", "LRANGE k1 0 100"}, - expect: []any{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"}, + expect: []any{"OK", "-WRONGTYPE Operation against a key holding the wrong kind of value"}, }, } diff --git a/integration_tests/commands/resp/dump_test.go b/integration_tests/commands/resp/dump_test.go index 88f41ace4..27d50badb 100644 --- a/integration_tests/commands/resp/dump_test.go +++ b/integration_tests/commands/resp/dump_test.go @@ -1,7 +1,6 @@ package resp import ( - "encoding/base64" "testing" "github.com/dicedb/dice/testutils" @@ -11,7 +10,7 @@ import ( func TestDumpRestore(t *testing.T) { conn := getLocalConnection() defer conn.Close() - + simpleJSON := `{"name":"John","age":30}` testCases := []struct { name string commands []string @@ -20,57 +19,31 @@ func TestDumpRestore(t *testing.T) { { name: "DUMP and RESTORE string value", commands: []string{ - "SET mykey hello", - "DUMP mykey", - "DEL mykey", - "RESTORE mykey 2 CQAAAAAFaGVsbG//AEeXk742Rcc=", - "GET mykey", + "SET foo bar", + "DUMP foo", + "DEL foo", + "RESTORE foo 2 CQAAAAADYmFy/72GUVF+ClKv", + "GET foo", }, expected: []interface{}{ "OK", - func(result interface{}) bool { - dumped, ok := result.(string) - if !ok { - return false - } - decoded, err := base64.StdEncoding.DecodeString(dumped) - if err != nil { - return false - } - return len(decoded) > 11 && - decoded[0] == 0x09 && - decoded[1] == 0x00 && - string(decoded[6:11]) == "hello" && - decoded[11] == 0xFF - }, + "CQAAAAADYmFy/72GUVF+ClKv", int64(1), "OK", - "hello", + "bar", }, }, { name: "DUMP and RESTORE integer value", commands: []string{ - "SET intkey 42", - "DUMP intkey", - "DEL intkey", - "RESTORE intkey 2 CcAAAAAAAAAAKv9S/ymRDY3rXg==", + "set foo 12345", + "DUMP foo", + "DEL foo", + "RESTORE foo 2 CQUAAAAAAAAwOf8OqbusYAl2pQ==", }, expected: []interface{}{ "OK", - func(result interface{}) bool { - dumped, ok := result.(string) - if !ok { - return false - } - decoded, err := base64.StdEncoding.DecodeString(dumped) - if err != nil { - return false - } - return len(decoded) > 2 && - decoded[0] == 0x09 && - decoded[1] == 0xC0 - }, + "CQUAAAAAAAAwOf8OqbusYAl2pQ==", int64(1), "OK", }, @@ -84,26 +57,157 @@ func TestDumpRestore(t *testing.T) { "(nil)", }, }, + { + name: "DUMP JSON", + commands: []string{ + `JSON.SET foo $ ` + simpleJSON, + "DUMP foo", + "del foo", + "restore foo 2 CQMAAAAYeyJhZ2UiOjMwLCJuYW1lIjoiSm9obiJ9/6PVaIgw0n+C", + "JSON.GET foo $..name", + }, + expected: []interface{}{ + "OK", + "skip", + int64(1), + "OK", + `"John"`, + }, + }, + { + name: "DUMP Set", + commands: []string{ + "sadd foo bar baz bazz", + "dump foo", + "del foo", + "restore foo 2 CQYAAAAAAAAAAwAAAANiYXIAAAADYmF6AAAABGJhenr/DSf4vHxjdYo=", + "smembers foo", + }, + expected: []interface{}{ + int64(3), + "skip", + int64(1), + "OK", + []interface{}{"bar", "baz", "bazz"}, + }, + }, + { + name: "DUMP bytearray", + commands: []string{ + "setbit foo 1 1", + "dump foo", + "del foo", + "restore foo 2 CQQAAAAAAAAAAUD/g00L5pRbaJI=", + "get foo", + }, + expected: []interface{}{ + int64(0), + "CQQAAAAAAAAAAUD/g00L5pRbaJI=", + int64(1), + "OK", + "@", + }, + }, + { + name: "DUMP sorted set", + commands: []string{ + "zadd foo 1 bar 2 bazz", + "dump foo", + "del foo", + "restore foo 2 CQgAAAAAAAAAAgAAAAAAAAADYmFyP/AAAAAAAAAAAAAAAAAABGJhenpAAAAAAAAAAP/POOElibTuYQ==", + "zrange foo 0 2", + }, + expected: []interface{}{ + int64(2), + "skip", + int64(1), + "OK", + []interface{}{"bar", "bazz"}, + }, + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - FireCommand(conn, "FLUSHALL") + FireCommand(conn, "del foo") for i, cmd := range tc.commands { result := FireCommand(conn, cmd) expected := tc.expected[i] - + if expected == "skip" { + // when order of elements define the dump value, we test the restore function and skip dump + continue + } switch exp := expected.(type) { case string: assert.Equal(t, exp, result) case []interface{}: assert.True(t, testutils.UnorderedEqual(exp, result)) - case func(interface{}) bool: - assert.True(t, exp(result), cmd) default: assert.Equal(t, expected, result) } } }) } + FireCommand(conn, "FLUSHDB") +} + +func TestDumpRestoreBF(t *testing.T) { + conn := getLocalConnection() + defer conn.Close() + res := FireCommand(conn, "bf.add foo bar") + assert.Equal(t, int64(1), res) + + dumpValue := FireCommand(conn, "dump foo") + FireCommand(conn, "del foo") + + res = FireCommand(conn, "restore foo 0 "+dumpValue.(string)) + assert.Equal(t, "OK", res) + res = FireCommand(conn, "bf.exists foo bazz") + assert.Equal(t, int64(0), res) + + FireCommand(conn, "FLUSHDB") +} + +func TestDumpRestoreCMS(t *testing.T) { + conn := getLocalConnection() + defer conn.Close() + + // Add a value to the CMS + FireCommand(conn, "CMS.INITBYPROB foo 0.1 0.01") + res := FireCommand(conn, "cms.incrby foo bar 42") + assert.Equal(t, []interface{}([]interface{}{int64(42)}), res) + + // Dump the serialized value + dumpValue := FireCommand(conn, "dump foo") + FireCommand(conn, "del foo") // Delete the CMS + + // Restore the CMS from the dumped value + res = FireCommand(conn, "restore foo 0 "+dumpValue.(string)) + assert.Equal(t, "OK", res) + + // Check the value for a key in the restored CMS + res = FireCommand(conn, "cms.query foo bar") + assert.Equal(t, []interface{}([]interface{}{int64(42)}), res) + + // Check that another key not in the CMS returns 0 + res = FireCommand(conn, "cms.query foo bar") + assert.Equal(t, []interface{}([]interface{}{int64(42)}), res) + + FireCommand(conn, "FLUSHDB") +} + +func TestDumpRestoreDeque(t *testing.T) { + conn := getLocalConnection() + defer conn.Close() + res := FireCommand(conn, "lpush foo bar") + assert.Equal(t, int64(1), res) + dumpValue := FireCommand(conn, "dump foo") + res = FireCommand(conn, "del foo") + assert.Equal(t, int64(1), res) + res = FireCommand(conn, "restore foo 0 "+dumpValue.(string)) + assert.Equal(t, "OK", res) + res = FireCommand(conn, "lpop foo") + assert.Equal(t, "bar", res) + + FireCommand(conn, "FLUSHDB") } diff --git a/integration_tests/commands/resp/jsondebug_test.go b/integration_tests/commands/resp/jsondebug_test.go index af1bda920..8ad10a9ae 100644 --- a/integration_tests/commands/resp/jsondebug_test.go +++ b/integration_tests/commands/resp/jsondebug_test.go @@ -23,7 +23,7 @@ func TestJSONDEBUG(t *testing.T) { `JSON.SET k1 $ {"a":1}`, "JSON.DEBUG MEMORY k1", }, - expected: []interface{}{"OK", int64(89)}, + expected: []interface{}{"OK", int64(72)}, }, { name: "jsondebug with a valid path", diff --git a/integration_tests/commands/resp/object_test.go b/integration_tests/commands/resp/object_test.go index 9e528bc6e..cd6c9cd74 100644 --- a/integration_tests/commands/resp/object_test.go +++ b/integration_tests/commands/resp/object_test.go @@ -11,7 +11,6 @@ func TestObjectCommand(t *testing.T) { conn := getLocalConnection() defer conn.Close() defer FireCommand(conn, "FLUSHDB") - simpleJSON := `{"name":"John","age":30}` testCases := []struct { name string @@ -29,86 +28,6 @@ func TestObjectCommand(t *testing.T) { delay: []time.Duration{0, 2 * time.Second, 3 * time.Second, 0, 0}, cleanup: []string{"DEL foo"}, }, - { - name: "Object Encoding check for raw", - commands: []string{"SET foo foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar", "OBJECT ENCODING foo"}, - expected: []interface{}{"OK", "raw"}, - assertType: []string{"equal", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL foo"}, - }, - { - name: "Object Encoding check for int", - commands: []string{"SET foo 1", "OBJECT ENCODING foo"}, - expected: []interface{}{"OK", "int"}, - assertType: []string{"equal", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL foo"}, - }, - { - name: "Object Encoding check for embstr", - commands: []string{"SET foo bar", "OBJECT ENCODING foo"}, - expected: []interface{}{"OK", "embstr"}, - assertType: []string{"equal", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL foo"}, - }, - { - name: "Object Encoding check for deque", - commands: []string{"LPUSH listKey 'value1'", "LPUSH listKey 'value2'", "OBJECT ENCODING listKey"}, - expected: []interface{}{int64(1), int64(2), "deque"}, - assertType: []string{"assert", "assert", "equal"}, - delay: []time.Duration{0, 0, 0}, - cleanup: []string{"DEL listKey"}, - }, - { - name: "Object Encoding check for bf", - commands: []string{"BF.ADD bloomkey value1", "BF.ADD bloomkey value2", "OBJECT ENCODING bloomkey"}, - expected: []interface{}{int64(1), int64(1), "bf"}, - assertType: []string{"assert", "assert", "equal"}, - delay: []time.Duration{0, 0, 0}, - cleanup: []string{"DEL bloomkey"}, - }, - { - name: "Object Encoding check for json", - commands: []string{`JSON.SET k10 $ ` + simpleJSON, "OBJECT ENCODING k10"}, - expected: []interface{}{"OK", "json"}, - assertType: []string{"equal", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL k10"}, - }, - { - name: "Object Encoding check for bytearray", - commands: []string{"SETBIT kbitset 0 1", "SETBIT kbitset 1 0", "SETBIT kbitset 2 1", "OBJECT ENCODING kbitset"}, - expected: []interface{}{int64(0), int64(0), int64(0), "bytearray"}, - assertType: []string{"assert", "assert", "assert", "equal"}, - delay: []time.Duration{0, 0, 0, 0}, - cleanup: []string{"DEL kbitset"}, - }, - { - name: "Object Encoding check for hashmap", - commands: []string{"HSET hashKey hKey hValue", "OBJECT ENCODING hashKey"}, - expected: []interface{}{int64(1), "hashmap"}, - assertType: []string{"assert", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL hashKey"}, - }, - { - name: "Object Encoding check for btree", - commands: []string{"ZADD btreekey 1 'member1' 2 'member2'", "OBJECT ENCODING btreekey"}, - expected: []interface{}{int64(2), "btree"}, - assertType: []string{"equal", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL btreekey"}, - }, - { - name: "Object Encoding check for setstr", - commands: []string{"SADD skey one two three", "OBJECT ENCODING skey"}, - expected: []interface{}{int64(3), "setstr"}, - assertType: []string{"assert", "equal"}, - delay: []time.Duration{0, 0}, - cleanup: []string{"DEL skey"}, - }, } for _, tc := range testCases { diff --git a/integration_tests/commands/websocket/bloom_test.go b/integration_tests/commands/websocket/bloom_test.go index 7198505df..d8c9222ca 100644 --- a/integration_tests/commands/websocket/bloom_test.go +++ b/integration_tests/commands/websocket/bloom_test.go @@ -4,6 +4,7 @@ import ( "testing" "time" + diceerrors "github.com/dicedb/dice/internal/errors" "github.com/stretchr/testify/assert" ) @@ -37,7 +38,7 @@ func TestBFReserveAddInfoExists(t *testing.T) { { name: "BF.RESERVE on existent filter returns error", cmds: []string{"BF.RESERVE bf 0.01 1000", "BF.RESERVE bf 0.01 1000"}, - expect: []interface{}{"OK", "ERR item exists"}, + expect: []interface{}{"OK", diceerrors.ErrKeyExists.Error()}, cleanUp: []string{"DEL bf"}, }, } @@ -126,7 +127,7 @@ func TestBFEdgeCasesAndErrors(t *testing.T) { { name: "BF.INFO on a non-existent filter", cmds: []string{"BF.INFO bf"}, - expect: []interface{}{"ERR not found"}, + expect: []interface{}{diceerrors.ErrKeyNotFound.Error()}, delays: []time.Duration{0}, cleanUp: []string{"del bf"}, }, @@ -161,7 +162,7 @@ func TestBFEdgeCasesAndErrors(t *testing.T) { { name: "BF.RESERVE with duplicate filter name", cmds: []string{"BF.RESERVE bf 0.01 1000", "BF.RESERVE bf 0.01 2000"}, - expect: []interface{}{"OK", "ERR item exists"}, + expect: []interface{}{"OK", diceerrors.ErrKeyExists.Error()}, delays: []time.Duration{0, 0}, cleanUp: []string{"del bf"}, }, diff --git a/integration_tests/commands/websocket/jsondebug_test.go b/integration_tests/commands/websocket/jsondebug_test.go index 8f2cba904..77a805f69 100644 --- a/integration_tests/commands/websocket/jsondebug_test.go +++ b/integration_tests/commands/websocket/jsondebug_test.go @@ -30,7 +30,7 @@ func TestJSONDEBUG(t *testing.T) { `JSON.SET k1 $ {"a":1}`, "JSON.DEBUG MEMORY k1", }, - expected: []interface{}{"OK", float64(89)}, + expected: []interface{}{"OK", float64(72)}, }, { name: "jsondebug with a valid path", diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 36f80cf15..62820dec4 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -49,7 +49,7 @@ func printConfiguration() { // Add whether the watch feature is enabled slog.Info("running with", slog.Bool("profiling", config.DiceConfig.Performance.EnableProfiling)) - // Add whether the watch feature is enabled + // Add whether the persistence feature is enabled slog.Info("running with", slog.Bool("persistence", config.DiceConfig.Persistence.Enabled)) } @@ -73,10 +73,10 @@ func Execute() { flag.IntVar(&flagsConfig.RespServer.Port, "port", 7379, "port for the DiceDB server") - flag.IntVar(&flagsConfig.HTTP.Port, "http-port", 7380, "port for accepting requets over HTTP") + flag.IntVar(&flagsConfig.HTTP.Port, "http-port", 8082, "port for accepting requets over HTTP") flag.BoolVar(&flagsConfig.HTTP.Enabled, "enable-http", false, "enable DiceDB to listen, accept, and process HTTP") - flag.IntVar(&flagsConfig.WebSocket.Port, "websocket-port", 7381, "port for accepting requets over WebSocket") + flag.IntVar(&flagsConfig.WebSocket.Port, "websocket-port", 8379, "port for accepting requets over WebSocket") flag.BoolVar(&flagsConfig.WebSocket.Enabled, "enable-websocket", false, "enable DiceDB to listen, accept, and process WebSocket") flag.IntVar(&flagsConfig.Performance.NumShards, "num-shards", -1, "number shards to create. defaults to number of cores") @@ -98,7 +98,7 @@ func Execute() { flag.IntVar(&flagsConfig.Memory.KeysLimit, "keys-limit", config.DefaultKeysLimit, "keys limit for the DiceDB server. "+ "This flag controls the number of keys each shard holds at startup. You can multiply this number with the "+ "total number of shard threads to estimate how much memory will be required at system start up.") - flag.Float64Var(&flagsConfig.Memory.EvictionRatio, "eviction-ratio", 0.1, "ratio of keys to evict when the "+ + flag.Float64Var(&flagsConfig.Memory.EvictionRatio, "eviction-ratio", 0.9, "ratio of keys to evict when the "+ "keys limit is reached") flag.Usage = func() { @@ -115,9 +115,9 @@ func Execute() { fmt.Println(" -h, --help Show this help message") fmt.Println(" -host Host for the DiceDB server (default: \"0.0.0.0\")") fmt.Println(" -port Port for the DiceDB server (default: 7379)") - fmt.Println(" -http-port Port for accepting requests over HTTP (default: 7380)") + fmt.Println(" -http-port Port for accepting requests over HTTP (default: 8082)") fmt.Println(" -enable-http Enable DiceDB to listen, accept, and process HTTP (default: false)") - fmt.Println(" -websocket-port Port for accepting requests over WebSocket (default: 7381)") + fmt.Println(" -websocket-port Port for accepting requests over WebSocket (default: 8379)") fmt.Println(" -enable-websocket Enable DiceDB to listen, accept, and process WebSocket (default: false)") fmt.Println(" -num-shards Number of shards to create. Defaults to number of cores (default: -1)") fmt.Println(" -enable-watch Enable support for .WATCH commands and real-time reactivity (default: false)") @@ -130,8 +130,8 @@ func Execute() { fmt.Println(" -requirepass Enable authentication for the default user (default: \"\")") fmt.Println(" -o Directory path to create the config file (default: \"\")") fmt.Println(" -c File path of the config file (default: \"\")") - fmt.Println(" -keys-limit Keys limit for the DiceDB server (default: 0)") - fmt.Println(" -eviction-ratio Ratio of keys to evict when the keys limit is reached (default: 0.1)") + fmt.Println(" -keys-limit Keys limit for the DiceDB server (default: 200000000)") + fmt.Println(" -eviction-ratio Ratio of keys to evict when the keys limit is reached (default: 0.9)") color.Unset() os.Exit(0) } diff --git a/internal/errors/migrated_errors.go b/internal/errors/migrated_errors.go index 6c8fe4e4c..ea81b0c4e 100644 --- a/internal/errors/migrated_errors.go +++ b/internal/errors/migrated_errors.go @@ -33,6 +33,7 @@ var ( ErrInvalidIPAddress = errors.New("invalid IP address") ErrInvalidFingerprint = errors.New("invalid fingerprint") ErrKeyDoesNotExist = errors.New("ERR could not perform this operation on a key that doesn't exist") + ErrKeyExists = errors.New("ERR key exists") // Error generation functions for specific error messages with dynamic parameters. ErrWrongArgumentCount = func(command string) error { diff --git a/internal/eval/bloom_test.go b/internal/eval/bloom_test.go index 3d06c3daa..d88d97f2f 100644 --- a/internal/eval/bloom_test.go +++ b/internal/eval/bloom_test.go @@ -100,19 +100,19 @@ func TestGetOrCreateBloomFilter(t *testing.T) { opts := defaultBloomOpts() // Should create a new filter under the key `key`. - bloom, err := getOrCreateBloomFilter(key, store, opts) + bloom, err := GetOrCreateBloomFilter(key, store, opts) if bloom == nil || err != nil { t.Errorf("nil bloom or non-nil error returned while creating new filter - key: %s, opts: %+v, err: %v", key, opts, err) } // Should get the filter (which was created above) - bloom, err = getOrCreateBloomFilter(key, store, opts) + bloom, err = GetOrCreateBloomFilter(key, store, opts) if bloom == nil || err != nil { t.Errorf("nil bloom or non-nil error returned while fetching existing filter - key: %s, opts: %+v, err: %v", key, opts, err) } // Should get the filter with nil opts - bloom, err = getOrCreateBloomFilter(key, store, nil) + bloom, err = GetOrCreateBloomFilter(key, store, nil) if bloom == nil || err != nil { t.Errorf("nil bloom or non-nil error returned while fetching existing filter - key: %s, opts: %+v, err: %v", key, opts, err) } @@ -122,7 +122,7 @@ func TestUpdateIndexes(t *testing.T) { // Create a value, default opts and initialize all params of the filter value := "hello" opts := defaultBloomOpts() - bloom := newBloomFilter(opts) + bloom := NewBloomFilter(opts) err := opts.updateIndexes(value) if err != nil { diff --git a/internal/eval/bytearray.go b/internal/eval/bytearray.go index ff612364b..4bf4f1f0a 100644 --- a/internal/eval/bytearray.go +++ b/internal/eval/bytearray.go @@ -36,12 +36,12 @@ func NewByteArrayFromObj(obj *object.Obj) (*ByteArray, error) { } func getValueAsByteSlice(obj *object.Obj) ([]byte, error) { - oType, oEnc := object.ExtractTypeEncoding(obj) + oType := obj.Type switch oType { case object.ObjTypeInt: return []byte(strconv.FormatInt(obj.Value.(int64), 10)), nil case object.ObjTypeString: - return getStringValueAsByteSlice(obj, oEnc) + return getStringValueAsByteSlice(obj) // TODO: Have this case as SETBIT stores values encoded as byte arrays. Need to investigate this further. case object.ObjTypeByteArray: return getByteArrayValueAsByteSlice(obj) @@ -50,16 +50,16 @@ func getValueAsByteSlice(obj *object.Obj) ([]byte, error) { } } -func getStringValueAsByteSlice(obj *object.Obj, oEnc uint8) ([]byte, error) { - switch oEnc { - case object.ObjEncodingInt: +func getStringValueAsByteSlice(obj *object.Obj) ([]byte, error) { + switch obj.Type { + case object.ObjTypeInt: intVal, ok := obj.Value.(int64) if !ok { return nil, errors.New("expected integer value but got another type") } return []byte(strconv.FormatInt(intVal, 10)), nil - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: + case object.ObjTypeString: strVal, ok := obj.Value.(string) if !ok { return nil, errors.New("expected string value but got another type") @@ -67,7 +67,7 @@ func getStringValueAsByteSlice(obj *object.Obj, oEnc uint8) ([]byte, error) { return []byte(strVal), nil default: - return nil, fmt.Errorf("unsupported encoding type: %d", oEnc) + return nil, fmt.Errorf("unsupported type type: %d", obj.Type) } } @@ -81,12 +81,12 @@ func getByteArrayValueAsByteSlice(obj *object.Obj) ([]byte, error) { } // ByteSliceToObj converts a byte slice to an Obj of the specified type and encoding -func ByteSliceToObj(store *dstore.Store, oldObj *object.Obj, b []byte, objType, encoding uint8) (*object.Obj, error) { +func ByteSliceToObj(store *dstore.Store, oldObj *object.Obj, b []byte, objType object.ObjectType) (*object.Obj, error) { switch objType { case object.ObjTypeInt: return ByteSliceToIntObj(store, oldObj, b) case object.ObjTypeString: - return ByteSliceToStringObj(store, oldObj, b, encoding) + return ByteSliceToStringObj(store, oldObj, b) case object.ObjTypeByteArray: return ByteSliceToByteArrayObj(store, oldObj, b) default: @@ -98,21 +98,14 @@ func ByteSliceToObj(store *dstore.Store, oldObj *object.Obj, b []byte, objType, func ByteSliceToIntObj(store *dstore.Store, oldObj *object.Obj, b []byte) (*object.Obj, error) { intVal, err := strconv.ParseInt(string(b), 10, 64) if err != nil { - return nil, fmt.Errorf("failed to parse byte slice to int: %v", err) + return store.NewObj(string(b), -1, object.ObjTypeString), nil } - return store.NewObj(intVal, -1, object.ObjTypeInt, object.ObjEncodingInt), nil + return store.NewObj(intVal, -1, object.ObjTypeInt), nil } // ByteSliceToStringObj converts a byte slice to an Obj with a string value -func ByteSliceToStringObj(store *dstore.Store, oldObj *object.Obj, b []byte, encoding uint8) (*object.Obj, error) { - switch encoding { - case object.ObjEncodingInt: - return ByteSliceToIntObj(store, oldObj, b) - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: - return store.NewObj(string(b), -1, object.ObjTypeString, object.ObjEncodingEmbStr), nil - default: - return nil, fmt.Errorf("unsupported encoding type") - } +func ByteSliceToStringObj(store *dstore.Store, oldObj *object.Obj, b []byte) (*object.Obj, error) { + return store.NewObj(string(b), -1, object.ObjTypeString), nil } // ByteSliceToByteArrayObj converts a byte slice to an Obj with a ByteArray value @@ -121,7 +114,7 @@ func ByteSliceToByteArrayObj(store *dstore.Store, oldObj *object.Obj, b []byte) data: b, Length: int64(len(b)), } - return store.NewObj(byteValue, -1, object.ObjTypeByteArray, object.ObjEncodingByteArray), nil + return store.NewObj(byteValue, -1, object.ObjTypeByteArray), nil } // SetBit sets the bit at the given position to the specified value diff --git a/internal/eval/commands.go b/internal/eval/commands.go index 787bca20c..6463d6b57 100644 --- a/internal/eval/commands.go +++ b/internal/eval/commands.go @@ -1301,6 +1301,14 @@ var ( NewEval: evalGEODIST, KeySpecs: KeySpecs{BeginIndex: 1}, } + geoSearchCmdMeta = DiceCmdMeta{ + Name: "GEOSEARCH", + Info: `Return the members of a sorted set populated with geospatial information using GEOADD, which are within the borders of the area specified by a given shape.`, + Arity: -6, + IsMigrated: true, + NewEval: evalGEOSEARCH, + KeySpecs: KeySpecs{BeginIndex: 1}, + } jsonstrappendCmdMeta = DiceCmdMeta{ Name: "JSON.STRAPPEND", Info: `JSON.STRAPPEND key [path] value @@ -1444,6 +1452,7 @@ func init() { DiceCmds["FLUSHDB"] = flushdbCmdMeta DiceCmds["GEOADD"] = geoAddCmdMeta DiceCmds["GEODIST"] = geoDistCmdMeta + DiceCmds["GEOSEARCH"] = geoSearchCmdMeta DiceCmds["GET"] = getCmdMeta DiceCmds["GETBIT"] = getBitCmdMeta DiceCmds["GETDEL"] = getDelCmdMeta diff --git a/internal/eval/countminsketch.go b/internal/eval/countminsketch.go index ecafa3709..80a564631 100644 --- a/internal/eval/countminsketch.go +++ b/internal/eval/countminsketch.go @@ -1,7 +1,9 @@ package eval import ( + "bytes" "encoding/binary" + "errors" "fmt" "hash" "hash/fnv" @@ -232,6 +234,84 @@ func (c *CountMinSketch) mergeMatrices(sources []*CountMinSketch, weights []uint } } +// serialize encodes the CountMinSketch into a byte slice. +func (c *CountMinSketch) serialize(buffer *bytes.Buffer) error { + if c == nil { + return errors.New("cannot serialize a nil CountMinSketch") + } + + // Write depth, width, and count + if err := binary.Write(buffer, binary.BigEndian, c.opts.depth); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, c.opts.width); err != nil { + return err + } + if err := binary.Write(buffer, binary.BigEndian, c.count); err != nil { + return err + } + + // Write matrix + for i := 0; i < len(c.matrix); i++ { + for j := 0; j < len(c.matrix[i]); j++ { + if err := binary.Write(buffer, binary.BigEndian, c.matrix[i][j]); err != nil { + return err + } + } + } + + return nil +} + +// deserialize reconstructs a CountMinSketch from a byte slice. +func DeserializeCMS(buffer *bytes.Reader) (*CountMinSketch, error) { + if buffer.Len() < 24 { // Minimum size for depth, width, and count + return nil, errors.New("insufficient data for deserialization") + } + + var depth, width, count uint64 + + // Read depth, width, and count + if err := binary.Read(buffer, binary.BigEndian, &depth); err != nil { + return nil, err + } + if err := binary.Read(buffer, binary.BigEndian, &width); err != nil { + return nil, err + } + if err := binary.Read(buffer, binary.BigEndian, &count); err != nil { + return nil, err + } + fmt.Println(depth, width, count, buffer.Len()) + // Validate data size + expectedSize := int(depth * width * 8) // Each uint64 takes 8 bytes + if buffer.Len() <= expectedSize { + return nil, errors.New("data size mismatch with expected matrix size") + } + + // Read matrix + matrix := make([][]uint64, depth) + for i := 0; i < int(depth); i++ { + matrix[i] = make([]uint64, width) + for j := 0; j < int(width); j++ { + if err := binary.Read(buffer, binary.BigEndian, &matrix[i][j]); err != nil { + return nil, err + } + } + } + + opts := &CountMinSketchOpts{ + depth: depth, + width: width, + hasher: fnv.New64(), // Default hasher + } + + return &CountMinSketch{ + opts: opts, + matrix: matrix, + count: count, + }, nil +} + // evalCMSMerge is used to merge multiple sketches into one. The final sketch // contains the weighted sum of the values in each of the source sketches. If // weights are not provided, default is 1. @@ -511,7 +591,7 @@ func createCountMinSketch(key string, opts *CountMinSketchOpts, store *dstore.St return diceerrors.NewErr("key already exists") } - obj = store.NewObj(newCountMinSketch(opts), -1, object.ObjTypeCountMinSketch, object.ObjEncodingMatrix) + obj = store.NewObj(newCountMinSketch(opts), -1, object.ObjTypeCountMinSketch) store.Put(key, obj) return nil @@ -526,11 +606,7 @@ func getCountMinSketch(key string, store *dstore.Store) (*CountMinSketch, error) return nil, diceerrors.NewErr("key does not exist") } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeCountMinSketch); err != nil { - return nil, err - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingMatrix); err != nil { + if err := object.AssertTypeWithError(obj.Type, object.ObjTypeCountMinSketch); err != nil { return nil, err } diff --git a/internal/eval/deque.go b/internal/eval/deque.go index 59d755c5f..2bf8c7d65 100644 --- a/internal/eval/deque.go +++ b/internal/eval/deque.go @@ -1,6 +1,8 @@ package eval import ( + "bytes" + "encoding/binary" "errors" "fmt" "strconv" @@ -838,3 +840,160 @@ func DecodeDeqEntry(xb []byte) (x string, entryLen int) { val >>= 64 - bit return strconv.FormatInt(val, 10), entryLen } + +func (q *Deque) Serialize(buf *bytes.Buffer) error { + if q == nil { + return errors.New("deque is nil") + } + + err := binary.Write(buf, binary.BigEndian, q.Length) + if err != nil { + return err + } + err = binary.Write(buf, binary.BigEndian, int32(q.leftIdx)) + if err != nil { + return err + } + + // Serialize byteList + err = serializeByteList(buf, q.list) + if err != nil { + return err + } + + return nil +} + +func serializeByteList(buf *bytes.Buffer, list *byteList) error { + if list == nil { + return binary.Write(buf, binary.BigEndian, int32(0)) + } + + err := binary.Write(buf, binary.BigEndian, int32(list.bufLen)) + if err != nil { + return err + } + err = binary.Write(buf, binary.BigEndian, list.size) + if err != nil { + return err + } + + current := list.head + var nodeCount int32 + nodes := [][]byte{} + + for current != nil { + nodes = append(nodes, current.buf) + current = current.next + nodeCount++ + } + + err = binary.Write(buf, binary.BigEndian, nodeCount) + if err != nil { + return err + } + + for _, nodeBuf := range nodes { + err = binary.Write(buf, binary.BigEndian, int32(len(nodeBuf))) + if err != nil { + return err + } + _, err = buf.Write(nodeBuf) + if err != nil { + return err + } + } + + return nil +} + +func DeserializeDeque(buf *bytes.Reader) (*Deque, error) { + if buf.Len() == 0 { + return nil, errors.New("data is empty") + } + + var length int64 + var leftIdx int32 + + err := binary.Read(buf, binary.BigEndian, &length) + if err != nil { + return nil, err + } + + err = binary.Read(buf, binary.BigEndian, &leftIdx) + if err != nil { + return nil, err + } + + list, err := deserializeByteList(buf) + if err != nil { + return nil, err + } + + return &Deque{ + Length: length, + list: list, + leftIdx: int(leftIdx), + }, nil +} + +func deserializeByteList(buf *bytes.Reader) (*byteList, error) { + var bufLen int32 + var size int64 + var nodeCount int32 + + err := binary.Read(buf, binary.BigEndian, &bufLen) + if err != nil { + return nil, err + } + + err = binary.Read(buf, binary.BigEndian, &size) + if err != nil { + return nil, err + } + + // Read the number of nodes + err = binary.Read(buf, binary.BigEndian, &nodeCount) + if err != nil { + return nil, err + } + + // Reconstruct the nodes + var prev *byteListNode + list := &byteList{ + bufLen: int(bufLen), + size: size, + } + + for i := int32(0); i < nodeCount; i++ { + // Read the length of the buffer + var bufSize int32 + err := binary.Read(buf, binary.BigEndian, &bufSize) + if err != nil { + return nil, err + } + + // Read the buffer data + nodeBuf := make([]byte, bufSize) + _, err = buf.Read(nodeBuf) + if err != nil { + return nil, err + } + + // Create and link the node + node := &byteListNode{ + buf: nodeBuf, + prev: prev, + } + if prev == nil { + list.head = node + } else { + prev.next = node + } + prev = node + } + + list.tail = prev + + return list, nil +} diff --git a/internal/eval/dump_restore.go b/internal/eval/dump_restore.go index 0c1428127..7049cdd2b 100644 --- a/internal/eval/dump_restore.go +++ b/internal/eval/dump_restore.go @@ -3,9 +3,11 @@ package eval import ( "bytes" "encoding/binary" + "encoding/json" "errors" "hash/crc64" + "github.com/dicedb/dice/internal/eval/sortedset" "github.com/dicedb/dice/internal/object" ) @@ -13,19 +15,64 @@ func rdbDeserialize(data []byte) (*object.Obj, error) { if len(data) < 3 { return nil, errors.New("insufficient data for deserialization") } - objType := data[1] + var value interface{} + var err error + var valueRaw interface{} + + buf := bytes.NewReader(data) + _, err = buf.ReadByte() + if err != nil { + return nil, err + } + _oType, err := buf.ReadByte() + if err != nil { + return nil, err + } + + objType := object.ObjectType(_oType) switch objType { - case 0x00: - return readString(data[2:]) - case 0xC0: // Integer type - return readInt(data[2:]) + case object.ObjTypeString: + value, err = readString(buf) + case object.ObjTypeInt: // Integer type + value, err = readInt(buf) + case object.ObjTypeSet: // Set type + value, err = readSet(buf) + case object.ObjTypeJSON: // JSON type + valueRaw, err = readString(buf) + if err := json.Unmarshal([]byte(valueRaw.(string)), &value); err != nil { + return nil, err + } + case object.ObjTypeByteArray: // Byte array type + valueRaw, err = readInt(buf) + if err != nil { + return nil, err + } + byteArray := &ByteArray{ + Length: valueRaw.(int64), + data: make([]byte, valueRaw.(int64)), + } + if _, err := buf.Read(byteArray.data); err != nil { + return nil, err + } + value = byteArray + case object.ObjTypeDequeue: // Byte list type (Deque) + value, err = DeserializeDeque(buf) + case object.ObjTypeBF: // Bloom filter type + value, err = DeserializeBloom(buf) + case object.ObjTypeSortedSet: + value, err = sortedset.DeserializeSortedSet(buf) + case object.ObjTypeCountMinSketch: + value, err = DeserializeCMS(buf) default: return nil, errors.New("unsupported object type") } + if err != nil { + return nil, err + } + return &object.Obj{Type: objType, Value: value}, nil } -func readString(data []byte) (*object.Obj, error) { - buf := bytes.NewReader(data) +func readString(buf *bytes.Reader) (interface{}, error) { var strLen uint32 if err := binary.Read(buf, binary.BigEndian, &strLen); err != nil { return nil, err @@ -36,29 +83,44 @@ func readString(data []byte) (*object.Obj, error) { return nil, err } - return &object.Obj{TypeEncoding: object.ObjTypeString, Value: string(strBytes)}, nil + return string(strBytes), nil } -func readInt(data []byte) (*object.Obj, error) { +func readInt(buf *bytes.Reader) (interface{}, error) { var intVal int64 - if err := binary.Read(bytes.NewReader(data), binary.BigEndian, &intVal); err != nil { + if err := binary.Read(buf, binary.BigEndian, &intVal); err != nil { return nil, err } - return &object.Obj{TypeEncoding: object.ObjTypeInt, Value: intVal}, nil + return intVal, nil +} + +func readSet(buf *bytes.Reader) (interface{}, error) { + var strLen uint64 + if err := binary.Read(buf, binary.BigEndian, &strLen); err != nil { + return nil, err + } + setItems := make(map[string]struct{}) + for i := 0; i < int(strLen); i++ { + value, err := readString(buf) + if err != nil { + return nil, err + } + setItems[value.(string)] = struct{}{} + } + return setItems, nil } func rdbSerialize(obj *object.Obj) ([]byte, error) { var buf bytes.Buffer buf.WriteByte(0x09) - - switch object.GetType(obj.TypeEncoding) { + buf.WriteByte(byte(obj.Type)) + switch obj.Type { case object.ObjTypeString: str, ok := obj.Value.(string) if !ok { return nil, errors.New("invalid string value") } - buf.WriteByte(0x00) if err := writeString(&buf, str); err != nil { return nil, err } @@ -68,15 +130,67 @@ func rdbSerialize(obj *object.Obj) ([]byte, error) { if !ok { return nil, errors.New("invalid integer value") } - buf.WriteByte(0xC0) writeInt(&buf, intVal) - + case object.ObjTypeSet: + setItems, ok := obj.Value.(map[string]struct{}) + if !ok { + return nil, errors.New("invalid set value") + } + if err := writeSet(&buf, setItems); err != nil { + return nil, err + } + case object.ObjTypeJSON: + jsonValue, err := json.Marshal(obj.Value) + if err != nil { + return nil, err + } + if err := writeString(&buf, string(jsonValue)); err != nil { + return nil, err + } + case object.ObjTypeByteArray: + byteArray, ok := obj.Value.(*ByteArray) + if !ok { + return nil, errors.New("invalid byte array value") + } + writeInt(&buf, byteArray.Length) + buf.Write(byteArray.data) + case object.ObjTypeDequeue: + deque, ok := obj.Value.(*Deque) + if !ok { + return nil, errors.New("invalid byte list value") + } + if err := deque.Serialize(&buf); err != nil { + return nil, err + } + case object.ObjTypeBF: + bitSet, ok := obj.Value.(*Bloom) + if !ok { + return nil, errors.New("invalid bloom filter value") + } + if err := bitSet.Serialize(&buf); err != nil { + return nil, err + } + case object.ObjTypeSortedSet: + sortedSet, ok := obj.Value.(*sortedset.Set) + if !ok { + return nil, errors.New("invalid sorted set value") + } + if err := sortedSet.Serialize(&buf); err != nil { + return nil, err + } + case object.ObjTypeCountMinSketch: + cms, ok := obj.Value.(*CountMinSketch) + if !ok { + return nil, errors.New("invalid countminsketch value") + } + if err := cms.serialize(&buf); err != nil { + return nil, err + } default: return nil, errors.New("unsupported object type") } buf.WriteByte(0xFF) // End marker - return appendChecksum(buf.Bytes()), nil } @@ -95,6 +209,18 @@ func writeInt(buf *bytes.Buffer, intVal int64) { buf.Write(tempBuf) } +func writeSet(buf *bytes.Buffer, setItems map[string]struct{}) error { + setLen := uint64(len(setItems)) + if err := binary.Write(buf, binary.BigEndian, setLen); err != nil { + return err + } + for item := range setItems { + if err := writeString(buf, item); err != nil { + return err + } + } + return nil +} func appendChecksum(data []byte) []byte { checksum := crc64.Checksum(data, crc64.MakeTable(crc64.ECMA)) checksumBuf := make([]byte, 8) diff --git a/internal/eval/eval.go b/internal/eval/eval.go index ab0190dee..0b28e079d 100644 --- a/internal/eval/eval.go +++ b/internal/eval/eval.go @@ -165,17 +165,8 @@ func evalMSET(args []string, store *dstore.Store) []byte { insertMap := make(map[string]*object.Obj, len(args)/2) for i := 0; i < len(args); i += 2 { key, value := args[i], args[i+1] - oType, oEnc := deduceTypeEncoding(value) - var storedValue interface{} - switch oEnc { - case object.ObjEncodingInt: - storedValue, _ = strconv.ParseInt(value, 10, 64) - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: - storedValue = value - default: - return clientio.Encode(fmt.Errorf("ERR unsupported encoding: %d", oEnc), false) - } - insertMap[key] = store.NewObj(storedValue, exDurationMs, oType, oEnc) + storedValue, oType := getRawStringOrInt(value) + insertMap[key] = store.NewObj(storedValue, exDurationMs, oType) } store.PutAll(insertMap) @@ -294,8 +285,7 @@ func jsonMGETHelper(store *dstore.Store, path, key string) (result interface{}, } // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return result, errWithMessage } @@ -625,11 +615,7 @@ func evalSDIFF(args []string, store *dstore.Store) []byte { return clientio.Encode([]string{}, false) } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr) - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr) } @@ -656,11 +642,7 @@ func evalSDIFF(args []string, store *dstore.Store) []byte { } // If the object exists, check if it is a set object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr) - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr) } @@ -710,11 +692,7 @@ func evalSINTER(args []string, store *dstore.Store) []byte { } // If the object exists, check if it is a set object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr) - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return diceerrors.NewErrWithFormattedMessage(diceerrors.WrongTypeErr) } diff --git a/internal/eval/eval_test.go b/internal/eval/eval_test.go index fc6028e02..f1a629a6e 100644 --- a/internal/eval/eval_test.go +++ b/internal/eval/eval_test.go @@ -133,7 +133,6 @@ func TestEval(t *testing.T) { testEvalGEOADD(t, store) testEvalGEODIST(t, store) testEvalSINTER(t, store) - testEvalOBJECTENCODING(t, store) testEvalJSONSTRAPPEND(t, store) testEvalINCR(t, store) testEvalINCRBY(t, store) @@ -288,7 +287,7 @@ func testEvalSET(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "bar" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, migratedOutput: EvalResponse{Result: "bar", Error: nil}, @@ -304,7 +303,7 @@ func testEvalSET(t *testing.T, store *dstore.Store) { value := "{\"a\":2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, migratedOutput: EvalResponse{Result: nil, Error: diceerrors.ErrWrongTypeOperation}, @@ -929,7 +928,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `{"a":2}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$", "a", "1"}, @@ -945,7 +944,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `[1,2,3]` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$", "0", "10"}, @@ -961,7 +960,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `{"a":2}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.a", "0", "6"}, @@ -977,7 +976,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `[1,2,3,4,5]` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$", "0", "2"}, @@ -993,7 +992,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `{"connection":{"wireless":true,"names":[0,1,2,3,4]},"names":[0,1,2,3,4]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.names", "1", "3"}, @@ -1015,7 +1014,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { }` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$..names", "1", "3"}, @@ -1031,7 +1030,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `{"connection":{"wireless":true,"names":[0,1,2,3,4]},"names":[0,1,2,3,4]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.connection", "1", "2"}, @@ -1047,7 +1046,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `{"connection":{"wireless":true,"names":[0,1,2,3,4]},"names":[0,1,2,3,4]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.names", "-3", "-1"}, @@ -1063,7 +1062,7 @@ func testEvalJSONARRTRIM(t *testing.T, store *dstore.Store) { value := `{"connection":{"wireless":true,"names":[0,1,2,3,4]},"names":[0,1,2,3,4]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.names", "-1", "-3"}, @@ -1120,7 +1119,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := "{\"a\":2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"NONEXISTENT_KEY", "$.a", "0", "1"}, @@ -1136,7 +1135,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := "{\"a\":2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.a", "a", "1"}, @@ -1152,7 +1151,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := "[1,2,3]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$", "4", "\"a\"", "1"}, @@ -1168,7 +1167,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := "{\"a\":2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.a", "0", "6"}, @@ -1184,7 +1183,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := "[1,2]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$", "0", "6", "\"a\"", "3.14"}, @@ -1200,7 +1199,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := `{"connection":{"wireless":true,"names":["1","2"]},"price":99.98,"names":[3,4]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$..names", "2", "7", "8"}, @@ -1216,7 +1215,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := `{"connection":{"wireless":true,"names":["1","2"]},"price":99.98,"names":[3,4]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$..names", "-1", "7", "8"}, @@ -1232,7 +1231,7 @@ func testEvalJSONARRINSERT(t *testing.T, store *dstore.Store) { value := "{\"a\":[1,2,3]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.a", "0", "1", "null", "3.14", "true", "{\"a\":123}"}, @@ -1296,7 +1295,7 @@ func testEvalJSONARRLEN(t *testing.T, store *dstore.Store) { value := "{\"age\":13,\"name\":\"a\"}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1312,7 +1311,7 @@ func testEvalJSONARRLEN(t *testing.T, store *dstore.Store) { value := "[1,2,3]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1328,7 +1327,7 @@ func testEvalJSONARRLEN(t *testing.T, store *dstore.Store) { value := "{\"age\":13,\"high\":1.60,\"pet\":null,\"flag\":false, \"partner\":{\"name\":\"tom\"}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1346,7 +1345,7 @@ func testEvalJSONARRLEN(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\"}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1420,7 +1419,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "[1,2,3]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1436,7 +1435,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1452,7 +1451,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"name\":\"John\",\"age\":30,\"pets\":null,\"languages\":[\"python\",\"golang\"],\"flag\":false}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.*"}, @@ -1468,7 +1467,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"person\":{\"name\":\"John\",\"age\":30},\"languages\":[\"python\",\"golang\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.person"}, @@ -1484,7 +1483,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"name\":\"John\",\"age\":30}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$invalid_path"}, @@ -1500,7 +1499,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"person\":{\"name\":\"John\",\"age\":30},\"languages\":[\"python\",\"golang\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.person.age"}, @@ -1516,7 +1515,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"person\":{\"name\":\"John\",\"age\":30},\"languages\":[\"python\",\"golang\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.person.name"}, @@ -1532,7 +1531,7 @@ func testEvalJSONOBJLEN(t *testing.T, store *dstore.Store) { value := "{\"person\":{\"name\":\"John\",\"age\":30},\"languages\":[\"python\",\"golang\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.languages"}, @@ -1625,7 +1624,7 @@ func testEvalJSONDEL(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1642,7 +1641,7 @@ func testEvalJSONDEL(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1660,7 +1659,7 @@ func testEvalJSONDEL(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1702,7 +1701,7 @@ func testEvalJSONFORGET(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1719,7 +1718,7 @@ func testEvalJSONFORGET(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1737,7 +1736,7 @@ func testEvalJSONFORGET(t *testing.T, store *dstore.Store) { "\"flag\":false, \"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1788,7 +1787,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { "\"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -1804,7 +1803,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { value := "{\"array\":[1,2,3,\"s\",null]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1821,7 +1820,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { value := "{\"a\":\"test\"}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1838,7 +1837,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { value := "{\"age\":13}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1855,7 +1854,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { value := "{\"price\":3.14}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1872,7 +1871,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { value := "{\"flag\":false}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.flag"}, @@ -1889,7 +1888,7 @@ func testEvalJSONCLEAR(t *testing.T, store *dstore.Store) { "\"partner\":{\"name\":\"tom\",\"language\":[\"rust\"]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.*"}, @@ -1955,7 +1954,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"language\":[\"java\",\"go\",\"python\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1971,7 +1970,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"language\":[\"java\",\"go\",\"python\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -1987,7 +1986,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"a\":\"test\"}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -2003,7 +2002,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"flag\":true}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -2019,7 +2018,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"price\":3}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -2035,7 +2034,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"price\":3.14}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -2051,7 +2050,7 @@ func testEvalJSONTYPE(t *testing.T, store *dstore.Store) { value := "{\"name\":\"tom\",\"partner\":{\"name\":\"jerry\"}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -2114,7 +2113,7 @@ func testEvalJSONGET(t *testing.T, store *dstore.Store) { value := "{\"a\":2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -2231,7 +2230,7 @@ func testEvalJSONNUMMULTBY(t *testing.T, store *dstore.Store) { value := "{\"a\":10,\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc", "$.a", "qwe"}, @@ -2247,7 +2246,7 @@ func testEvalJSONNUMMULTBY(t *testing.T, store *dstore.Store) { value := "{\"a\": \"b\",\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc", "$.a", "2"}, @@ -2263,7 +2262,7 @@ func testEvalJSONNUMMULTBY(t *testing.T, store *dstore.Store) { value := "{\"a\": \"b\",\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc", "$..a", "2"}, @@ -2279,7 +2278,7 @@ func testEvalJSONNUMMULTBY(t *testing.T, store *dstore.Store) { value := "{\"a\":10,\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc", "$.a", "2"}, @@ -2295,7 +2294,7 @@ func testEvalJSONNUMMULTBY(t *testing.T, store *dstore.Store) { value := "{\"a\":10,\"b\":[{\"a\":2}, {\"a\":5}, {\"a\":\"c\"}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc", "$..fe", "2"}, @@ -2316,7 +2315,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.a", "6"}, @@ -2332,7 +2331,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":[1,2]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.a", "6"}, @@ -2348,7 +2347,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":[1,2]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.a", "6", "7", "8"}, @@ -2364,7 +2363,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"b\":[\"b\",\"c\"]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.b", `"d"`}, @@ -2380,7 +2379,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":[[1,2]]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.a", "[1,2,3]"}, @@ -2396,7 +2395,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":[{\"b\": 1}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.a", "{\"c\": 3}"}, @@ -2412,7 +2411,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":[1,2],\"b\":{\"a\":[10]}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$..a", "6"}, @@ -2428,7 +2427,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "[1,2,3]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$", "6"}, @@ -2444,7 +2443,7 @@ func testEvalJSONARRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":[1,2]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"array", "$.a", `"blue"`}, @@ -2519,7 +2518,7 @@ func testEvalJSONTOGGLE(t *testing.T, store *dstore.Store) { if err != nil { fmt.Printf("Debug: Error unmarshaling JSON: %v\n", err) } - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", ".active"}, @@ -2538,7 +2537,7 @@ func testEvalJSONTOGGLE(t *testing.T, store *dstore.Store) { if err != nil { fmt.Printf("Debug: Error unmarshaling JSON: %v\n", err) } - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", ".active"}, @@ -2572,7 +2571,7 @@ func testEvalJSONTOGGLE(t *testing.T, store *dstore.Store) { value := `{"isSimple":true,"nested":{"isSimple":false}}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"NESTED_KEY", "$..isSimple"}, @@ -2588,7 +2587,7 @@ func testEvalJSONTOGGLE(t *testing.T, store *dstore.Store) { value := `{"field": true, "nested": {"field": false, "nested": {"field": true}}}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"DEEP_NESTED_KEY", "$..field"}, @@ -2996,11 +2995,11 @@ func testEvalPFADD(t *testing.T, store *dstore.Store) { name: "PFADD Incorrect type provided", setup: func() { key, value := "EXISTING_KEY", "VALUE" - oType, oEnc := deduceTypeEncoding(value) + _, oType := getRawStringOrInt(value) var exDurationMs int64 = -1 keepttl := false - store.Put(key, store.NewObj(value, exDurationMs, oType, oEnc), dstore.WithKeepTTL(keepttl)) + store.Put(key, store.NewObj(value, exDurationMs, oType), dstore.WithKeepTTL(keepttl)) }, input: []string{"EXISTING_KEY", "1"}, output: []byte("-WRONGTYPE Key is not a valid HyperLogLog string value"), @@ -3213,7 +3212,7 @@ func testEvalHGET(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3234,7 +3233,7 @@ func testEvalHGET(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3276,7 +3275,7 @@ func testEvalHGETALL(t *testing.T, store *dstore.Store) { newMap := make(HashMap) // Empty hash map obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3298,7 +3297,7 @@ func testEvalHGETALL(t *testing.T, store *dstore.Store) { newMap["field3"] = "value3" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3350,7 +3349,7 @@ func testEvalHMGET(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3371,7 +3370,7 @@ func testEvalHMGET(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3392,7 +3391,7 @@ func testEvalHMGET(t *testing.T, store *dstore.Store) { "field2": "value2", } obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3433,7 +3432,7 @@ func testEvalHVALS(t *testing.T, store *dstore.Store) { newMap[field] = "mock_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3502,7 +3501,7 @@ func testEvalHSTRLEN(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3520,7 +3519,7 @@ func testEvalHSTRLEN(t *testing.T, store *dstore.Store) { newMap[field] = "HelloWorld" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3564,7 +3563,7 @@ func testEvalHEXISTS(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3583,7 +3582,7 @@ func testEvalHEXISTS(t *testing.T, store *dstore.Store) { newMap[field] = "HelloWorld" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -3787,7 +3786,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := "{\"name\":\"Bhima\",\"age\":10}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -3803,7 +3802,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := "10.9" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -3819,7 +3818,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := "10" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -3835,7 +3834,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := "[\"age\", \"name\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -3851,7 +3850,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := "true" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -3867,7 +3866,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := `"hello"` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -3883,7 +3882,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := `{"partner":{"name":"tom","language":["rust"]}}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -3900,7 +3899,7 @@ func testEvalJSONSTRLEN(t *testing.T, store *dstore.Store) { value := `{"partner":{"name":21,"language":["rust"]}}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, @@ -4176,7 +4175,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": 2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$.a", "3"}, @@ -4193,7 +4192,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": 2.5}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$.a", "1.5"}, @@ -4210,7 +4209,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": 2, \"b\": 10, \"c\": [15, {\"d\": 20}]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$..*", "5"}, @@ -4240,7 +4239,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": [1, 2, 3]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$.a[1]", "5"}, @@ -4256,7 +4255,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": 2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$.b", "3"}, @@ -4272,7 +4271,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": 5, \"b\": \"not a number\", \"c\": [1, 2]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$..*", "2"}, @@ -4319,7 +4318,7 @@ func testEvalJSONNUMINCRBY(t *testing.T, store *dstore.Store) { value := "{\"a\": {\"b\": {\"c\": 10}}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"number", "$..c", "5"}, @@ -4471,7 +4470,7 @@ func testEvalHSET(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -4493,7 +4492,7 @@ func testEvalHSET(t *testing.T, store *dstore.Store) { newMap[field] = mockValue obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -4574,7 +4573,7 @@ func testEvalHMSET(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -4596,7 +4595,7 @@ func testEvalHMSET(t *testing.T, store *dstore.Store) { newMap[field] = mockValue obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -4650,7 +4649,7 @@ func testEvalHKEYS(t *testing.T, store *dstore.Store) { newMap[field1] = "HelloWorld" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -4827,11 +4826,11 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "{\"a\": 1}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY"}, - migratedOutput: EvalResponse{Result: 89, Error: nil}, + migratedOutput: EvalResponse{Result: 72, Error: nil}, }, "root path": { @@ -4840,11 +4839,11 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "{\"a\": 1}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$"}, - migratedOutput: EvalResponse{Result: 89, Error: nil}, + migratedOutput: EvalResponse{Result: 72, Error: nil}, }, "invalid path": { @@ -4853,7 +4852,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "{\"a\": 1}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "INVALID_PATH"}, @@ -4866,7 +4865,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "{\"a\": 1, \"b\": 2}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$.a"}, @@ -4881,7 +4880,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "{\"a\": 1, \"b\": \"dice\"}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$.a", "$.b"}, @@ -4894,7 +4893,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[1]"}, @@ -4907,7 +4906,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[1,2]"}, @@ -4920,7 +4919,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[4]"}, @@ -4933,7 +4932,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[1,2,4]"}, @@ -4946,7 +4945,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[-1]"}, @@ -4959,7 +4958,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[-1,-2]"}, @@ -4972,7 +4971,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[-4]"}, @@ -4985,7 +4984,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[*]"}, @@ -4998,7 +4997,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[\"roll\", \"the\", \"dices\"]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[:]"}, @@ -5011,7 +5010,7 @@ func testEvalDebug(t *testing.T, store *dstore.Store) { value := "[2, 3.5, true, null, \"dice\", {}, [], {\"a\": 1, \"b\": 2}, [7, 8, 0]]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MEMORY", "EXISTING_KEY", "$[:]"}, @@ -5105,7 +5104,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -5121,7 +5120,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "{\"a\": 1, \"b\": []}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$.b"}, @@ -5137,7 +5136,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "{\"a\": 1, \"b\": []}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$.*"}, @@ -5153,7 +5152,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[0, 1, 2, 3, 4, 5]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -5169,7 +5168,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[0, 1, 2, 3, 4, 5]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$", "2"}, @@ -5185,7 +5184,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[0, 1, 2, 3, 4, 5]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$", "10"}, @@ -5201,7 +5200,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[0, 1, 2, 3, 4, 5]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$", "-2"}, @@ -5217,7 +5216,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[0, 1, 2, 3, 4, 5]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$", "-10"}, @@ -5233,7 +5232,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "[0, 1, 2, 3, 4, 5]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$", "2"}, @@ -5256,7 +5255,7 @@ func testEvalJSONARRPOP(t *testing.T, store *dstore.Store) { value := "{\"a\": 2, \"b\": [0, 1, 2, 3, 4, 5]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$.b", "2"}, @@ -5332,7 +5331,7 @@ func testEvalTYPE(t *testing.T, store *dstore.Store) { "TYPE key exists and is of type String": { name: "TYPE key exists and is of type String", setup: func() { - store.Put("string_key", store.NewObj("value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("string_key", store.NewObj("value", -1, object.ObjTypeString)) }, input: []string{"string_key"}, migratedOutput: EvalResponse{ @@ -5343,7 +5342,7 @@ func testEvalTYPE(t *testing.T, store *dstore.Store) { "TYPE key exists and is of type List": { name: "TYPE key exists and is of type List", setup: func() { - store.Put("list_key", store.NewObj([]byte("value"), -1, object.ObjTypeByteList, object.ObjEncodingRaw)) + evalLPUSH([]string{"list_key", "value"}, store) }, input: []string{"list_key"}, migratedOutput: EvalResponse{ @@ -5354,7 +5353,7 @@ func testEvalTYPE(t *testing.T, store *dstore.Store) { "TYPE key exists and is of type Set": { name: "TYPE key exists and is of type Set", setup: func() { - store.Put("set_key", store.NewObj([]byte("value"), -1, object.ObjTypeSet, object.ObjEncodingRaw)) + store.Put("set_key", store.NewObj([]byte("value"), -1, object.ObjTypeSet)) }, input: []string{"set_key"}, migratedOutput: EvalResponse{ @@ -5365,7 +5364,7 @@ func testEvalTYPE(t *testing.T, store *dstore.Store) { "TYPE key exists and is of type Hash": { name: "TYPE key exists and is of type Hash", setup: func() { - store.Put("hash_key", store.NewObj([]byte("value"), -1, object.ObjTypeHashMap, object.ObjEncodingRaw)) + store.Put("hash_key", store.NewObj([]byte("value"), -1, object.ObjTypeHashMap)) }, input: []string{"hash_key"}, migratedOutput: EvalResponse{ @@ -5383,16 +5382,16 @@ func BenchmarkEvalTYPE(b *testing.B) { // Define different types of objects to benchmark objectTypes := map[string]func(){ "String": func() { - store.Put("string_key", store.NewObj("value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("string_key", store.NewObj("value", -1, object.ObjTypeString)) }, "List": func() { - store.Put("list_key", store.NewObj([]byte("value"), -1, object.ObjTypeByteList, object.ObjEncodingRaw)) + store.Put("list_key", store.NewObj([]byte("value"), -1, object.ObjTypeDequeue)) }, "Set": func() { - store.Put("set_key", store.NewObj([]byte("value"), -1, object.ObjTypeSet, object.ObjEncodingRaw)) + store.Put("set_key", store.NewObj([]byte("value"), -1, object.ObjTypeSet)) }, "Hash": func() { - store.Put("hash_key", store.NewObj([]byte("value"), -1, object.ObjTypeHashMap, object.ObjEncodingRaw)) + store.Put("hash_key", store.NewObj([]byte("value"), -1, object.ObjTypeHashMap)) }, } @@ -5609,7 +5608,7 @@ func testEvalJSONOBJKEYS(t *testing.T, store *dstore.Store) { value := "[1]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY"}, @@ -5625,7 +5624,7 @@ func testEvalJSONOBJKEYS(t *testing.T, store *dstore.Store) { value := `{"name":"John","age":30,"pets":null,"languages":["python","golang"],"flag":false}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.*"}, @@ -5641,7 +5640,7 @@ func testEvalJSONOBJKEYS(t *testing.T, store *dstore.Store) { value := `{"person":{"name":"John","age":30},"languages":["python","golang"]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.person.age"}, @@ -5657,7 +5656,7 @@ func testEvalJSONOBJKEYS(t *testing.T, store *dstore.Store) { value := `{"person":{"name":"John","age":30},"languages":["python","golang"]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.person.name"}, @@ -5673,7 +5672,7 @@ func testEvalJSONOBJKEYS(t *testing.T, store *dstore.Store) { value := `{"person":{"name":"John","age":30},"languages":["python","golang"]}` var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"EXISTING_KEY", "$.languages"}, @@ -5742,10 +5741,10 @@ func BenchmarkEvalJSONOBJKEYS(b *testing.B) { func testEvalGETRANGE(t *testing.T, store *dstore.Store) { setupForStringValue := func() { - store.Put("STRING_KEY", store.NewObj("Hello World", maxExDuration, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("STRING_KEY", store.NewObj("Hello World", maxExDuration, object.ObjTypeString)) } setupForIntegerValue := func() { - store.Put("INTEGER_KEY", store.NewObj("1234", maxExDuration, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("INTEGER_KEY", store.NewObj("1234", maxExDuration, object.ObjTypeString)) } tests := map[string]evalTestCase{ "GETRANGE against non-existing key": { @@ -5944,7 +5943,7 @@ func testEvalGETRANGE(t *testing.T, store *dstore.Store) { "GETRANGE against byte array with valid range: 0 4": { setup: func() { key := "BYTEARRAY_KEY" - store.Put(key, store.NewObj(&ByteArray{data: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, maxExDuration, object.ObjTypeByteArray, object.ObjEncodingByteArray)) + store.Put(key, store.NewObj(&ByteArray{data: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, maxExDuration, object.ObjTypeByteArray)) }, input: []string{"BYTEARRAY_KEY", "0", "4"}, migratedOutput: EvalResponse{Result: "hello", Error: nil}, @@ -5952,7 +5951,7 @@ func testEvalGETRANGE(t *testing.T, store *dstore.Store) { "GETRANGE against byte array with valid range: 6 -1": { setup: func() { key := "BYTEARRAY_KEY" - store.Put(key, store.NewObj(&ByteArray{data: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, maxExDuration, object.ObjTypeByteArray, object.ObjEncodingByteArray)) + store.Put(key, store.NewObj(&ByteArray{data: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, maxExDuration, object.ObjTypeByteArray)) }, input: []string{"BYTEARRAY_KEY", "6", "-1"}, migratedOutput: EvalResponse{Result: "world", Error: nil}, @@ -5960,7 +5959,7 @@ func testEvalGETRANGE(t *testing.T, store *dstore.Store) { "GETRANGE against byte array with invalid range: 20 30": { setup: func() { key := "BYTEARRAY_KEY" - store.Put(key, store.NewObj(&ByteArray{data: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, maxExDuration, object.ObjTypeByteArray, object.ObjEncodingByteArray)) + store.Put(key, store.NewObj(&ByteArray{data: []byte{0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64}}, maxExDuration, object.ObjTypeByteArray)) }, input: []string{"BYTEARRAY_KEY", "20", "30"}, migratedOutput: EvalResponse{Result: "", Error: nil}, @@ -5972,7 +5971,7 @@ func testEvalGETRANGE(t *testing.T, store *dstore.Store) { func BenchmarkEvalGETRANGE(b *testing.B) { store := dstore.NewStore(nil, nil, nil) - store.Put("BENCHMARK_KEY", store.NewObj("Hello World", maxExDuration, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("BENCHMARK_KEY", store.NewObj("Hello World", maxExDuration, object.ObjTypeString)) inputs := []struct { start string @@ -6060,7 +6059,7 @@ func testEvalHSETNX(t *testing.T, store *dstore.Store) { newMap[field] = "mock_field_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6081,7 +6080,7 @@ func testEvalHSETNX(t *testing.T, store *dstore.Store) { newMap[field] = "existing_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6149,7 +6148,7 @@ func testEvalHINCRBY(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "10" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6175,7 +6174,7 @@ func testEvalHINCRBY(t *testing.T, store *dstore.Store) { newMap := make(HashMap) newMap[field] = "new_value" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6193,7 +6192,7 @@ func testEvalHINCRBY(t *testing.T, store *dstore.Store) { h[field] = " 10 " obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6215,7 +6214,7 @@ func testEvalHINCRBY(t *testing.T, store *dstore.Store) { h[field] = "-10" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6232,7 +6231,7 @@ func testEvalHINCRBY(t *testing.T, store *dstore.Store) { h[field] = fmt.Sprintf("%v", math.MaxInt64) obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6249,7 +6248,7 @@ func testEvalHINCRBY(t *testing.T, store *dstore.Store) { h[field] = fmt.Sprintf("%v", math.MinInt64) obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6404,7 +6403,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "2.1" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "0.1"}, @@ -6415,7 +6414,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "2" - obj := store.NewObj(value, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(value, -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"key", "0.1"}, @@ -6426,7 +6425,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "2" - obj := store.NewObj(value, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(value, -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"key", "-0.1"}, @@ -6437,7 +6436,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "1" - obj := store.NewObj(value, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(value, -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"key", "1e-2"}, @@ -6448,7 +6447,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "1e2" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "1e-1"}, @@ -6459,7 +6458,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "0.1" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "-0.1"}, @@ -6470,7 +6469,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := " 2 " - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "0.1"}, @@ -6481,7 +6480,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "string" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "0.1"}, @@ -6492,7 +6491,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "2.0" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "a"}, @@ -6503,7 +6502,7 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "1e308" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "1e308"}, @@ -6539,8 +6538,8 @@ func testEvalINCRBYFLOAT(t *testing.T, store *dstore.Store) { func BenchmarkEvalINCRBYFLOAT(b *testing.B) { store := dstore.NewStore(nil, nil, nil) - store.Put("key1", store.NewObj("1", maxExDuration, object.ObjTypeString, object.ObjEncodingEmbStr)) - store.Put("key2", store.NewObj("1.2", maxExDuration, object.ObjTypeString, object.ObjEncodingEmbStr)) + store.Put("key1", store.NewObj("1", maxExDuration, object.ObjTypeString)) + store.Put("key2", store.NewObj("1.2", maxExDuration, object.ObjTypeString)) inputs := []struct { key string @@ -6585,7 +6584,7 @@ func testEvalHRANDFIELD(t *testing.T, store *dstore.Store) { newMap["field2"] = "Value2" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6614,7 +6613,7 @@ func testEvalHRANDFIELD(t *testing.T, store *dstore.Store) { newMap["field3"] = "value3" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6650,7 +6649,7 @@ func testEvalHRANDFIELD(t *testing.T, store *dstore.Store) { newMap["field3"] = "value3" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: newMap, LastAccessedAt: uint32(time.Now().Unix()), } @@ -6706,7 +6705,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "val" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", "val"}, @@ -6720,8 +6719,8 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { migratedOutput: EvalResponse{Result: 3, Error: nil}, validator: func(output []byte) { obj := store.Get("key") - _, enc := object.ExtractTypeEncoding(obj) - if enc != object.ObjEncodingInt { + oType := obj.Type + if oType != object.ObjTypeInt { t.Errorf("unexpected encoding") } }, @@ -6731,7 +6730,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { key := "key" value := "123" storedValue, _ := strconv.ParseInt(value, 10, 64) - obj := store.NewObj(storedValue, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(storedValue, -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"key", "val"}, @@ -6748,7 +6747,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", ""}, @@ -6758,7 +6757,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { setup: func() { key := "key" value := "val" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"key", ""}, @@ -6768,15 +6767,15 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { setup: func() { store.Del("key") storedValue, _ := strconv.ParseInt("1", 10, 64) - obj := store.NewObj(storedValue, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(storedValue, -1, object.ObjTypeInt) store.Put("key", obj) }, input: []string{"key", "2"}, migratedOutput: EvalResponse{Result: 2, Error: nil}, validator: func(output []byte) { obj := store.Get("key") - _, enc := object.ExtractTypeEncoding(obj) - if enc != object.ObjEncodingRaw { + oType := obj.Type + if oType != object.ObjTypeString { t.Errorf("unexpected encoding") } }, @@ -6786,7 +6785,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { key := "listKey" value := "val" // Create a new list object - obj := store.NewObj(NewDeque(), -1, object.ObjTypeByteList, object.ObjEncodingDeque) + obj := store.NewObj(NewDeque(), -1, object.ObjTypeDequeue) store.Put(key, obj) obj.Value.(*Deque).LPush(value) }, @@ -6801,7 +6800,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { "existingVal": {}, "anotherVal": {}, } - obj := store.NewObj(initialValues, -1, object.ObjTypeSet, object.ObjEncodingSetStr) + obj := store.NewObj(initialValues, -1, object.ObjTypeSet) store.Put(key, obj) }, input: []string{"setKey", "val"}, @@ -6815,7 +6814,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { "field1": "value1", "field2": "value2", } - obj := store.NewObj(initialValues, -1, object.ObjTypeHashMap, object.ObjEncodingHashMap) + obj := store.NewObj(initialValues, -1, object.ObjTypeHashMap) store.Put(key, obj) }, input: []string{"hashKey", "val"}, @@ -6832,7 +6831,7 @@ func testEvalAPPEND(t *testing.T, store *dstore.Store) { initialByteArray.SetBit(10, true) // Set the eleventh bit to 1 initialByteArray.SetBit(11, true) // Set the twelfth bit to 1 initialByteArray.SetBit(14, true) // Set the fifteenth bit to 1 - obj := store.NewObj(initialByteArray, -1, object.ObjTypeByteArray, object.ObjEncodingByteArray) + obj := store.NewObj(initialByteArray, -1, object.ObjTypeByteArray) store.Put(key, obj) }, input: []string{"bitKey", "1"}, @@ -6875,7 +6874,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "\"Roll the Dice\"" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6887,7 +6886,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "10" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6899,7 +6898,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "true" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6910,7 +6909,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { key := "MOCK_KEY" var rootData interface{} _ = sonic.Unmarshal([]byte(nil), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6922,7 +6921,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "[]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6934,7 +6933,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "{}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6946,7 +6945,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "[\"dice\", 10, 10.5, true, null]" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6958,7 +6957,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "{\"b\": [\"dice\", 10, 10.5, true, null]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY"}, @@ -6970,7 +6969,7 @@ func testEvalJSONRESP(t *testing.T, store *dstore.Store) { value := "{\"b\": [\"dice\", 10, 10.5, true, null]}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"MOCK_KEY", "$.b"}, @@ -7304,7 +7303,7 @@ func testEvalZADD(t *testing.T, store *dstore.Store) { }, "ZADD to a key of wrong type": { setup: func() { - store.Put("mywrongtypekey", store.NewObj("string_value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("mywrongtypekey", store.NewObj("string_value", -1, object.ObjTypeString)) }, input: []string{"mywrongtypekey", "1", "member1"}, migratedOutput: EvalResponse{ @@ -7328,7 +7327,7 @@ func testEvalZRANGE(t *testing.T, store *dstore.Store) { }, "ZRANGE with wrong type key": { setup: func() { - store.Put("mystring", store.NewObj("string_value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("mystring", store.NewObj("string_value", -1, object.ObjTypeString)) }, input: []string{"mystring", "0", "-1"}, migratedOutput: EvalResponse{ @@ -7452,7 +7451,7 @@ func testEvalZPOPMIN(t *testing.T, store *dstore.Store) { }, "ZPOPMIN with wrong type of key with/without count argument": { setup: func() { - store.Put("mystring", store.NewObj("string_value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("mystring", store.NewObj("string_value", -1, object.ObjTypeString)) }, input: []string{"mystring", "1"}, migratedOutput: EvalResponse{ @@ -7522,7 +7521,7 @@ func testEvalZPOPMIN(t *testing.T, store *dstore.Store) { }, "ZPOPMIN on empty sorted set": { setup: func() { - store.Put("myzset", store.NewObj(sortedset.New(), -1, object.ObjTypeSortedSet, object.ObjEncodingBTree)) // Ensure the set exists but is empty + store.Put("myzset", store.NewObj(sortedset.New(), -1, object.ObjTypeSortedSet)) // Ensure the set exists but is empty }, input: []string{"myzset"}, migratedOutput: EvalResponse{ @@ -7694,7 +7693,7 @@ func testEvalZREM(t *testing.T, store *dstore.Store) { }, "ZREM with wrong type key": { setup: func() { - store.Put("string_key", store.NewObj("string_value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("string_key", store.NewObj("string_value", -1, object.ObjTypeString)) }, input: []string{"string_key", "field"}, migratedOutput: EvalResponse{ @@ -7787,7 +7786,7 @@ func testEvalZCARD(t *testing.T, store *dstore.Store) { }, "ZCARD with wrong type key": { setup: func() { - store.Put("string_key", store.NewObj("string_value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("string_key", store.NewObj("string_value", -1, object.ObjTypeString)) }, input: []string{"string_key"}, migratedOutput: EvalResponse{ @@ -7899,7 +7898,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { key := "key" h := make(HashMap) obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -7915,7 +7914,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "2.1" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -7931,7 +7930,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "2" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -7947,7 +7946,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "2.0" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -7963,7 +7962,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "2.0" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -7980,7 +7979,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "non_numeric" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -7996,7 +7995,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "1e308" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -8012,7 +8011,7 @@ func testEvalHINCRBYFLOAT(t *testing.T, store *dstore.Store) { h := make(HashMap) h[field] = "1e2" obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: h, LastAccessedAt: uint32(time.Now().Unix()), } @@ -8030,8 +8029,8 @@ func BenchmarkEvalHINCRBYFLOAT(b *testing.B) { store := dstore.NewStore(nil, nil, nil) // Setting initial fields with some values - store.Put("key1", store.NewObj(HashMap{"field1": "1.0", "field2": "1.2"}, maxExDuration, object.ObjTypeHashMap, object.ObjEncodingHashMap)) - store.Put("key2", store.NewObj(HashMap{"field1": "0.1"}, maxExDuration, object.ObjTypeHashMap, object.ObjEncodingHashMap)) + store.Put("key1", store.NewObj(HashMap{"field1": "1.0", "field2": "1.2"}, maxExDuration, object.ObjTypeHashMap)) + store.Put("key2", store.NewObj(HashMap{"field1": "0.1"}, maxExDuration, object.ObjTypeHashMap)) inputs := []struct { key string @@ -8085,7 +8084,7 @@ func testEvalDUMP(t *testing.T, store *dstore.Store) { setup: func() { key := "user" value := "hello" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"user"}, @@ -8103,18 +8102,12 @@ func testEvalDUMP(t *testing.T, store *dstore.Store) { setup: func() { key := "INTEGER_KEY" value := int64(10) - obj := store.NewObj(value, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(value, -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"INTEGER_KEY"}, migratedOutput: EvalResponse{ - Result: base64.StdEncoding.EncodeToString([]byte{ - 0x09, - 0xC0, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, - 0xFF, - 0x12, 0x77, 0xDE, 0x29, 0x53, 0xDB, 0x44, 0xC2, - }), + Result: "CQUAAAAAAAAACv9+l81XgsShqw==", Error: nil, }, }, @@ -8122,7 +8115,7 @@ func testEvalDUMP(t *testing.T, store *dstore.Store) { setup: func() { key := "EXPIRED_KEY" value := "This will expire" - obj := store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj := store.NewObj(value, -1, object.ObjTypeString) store.Put(key, obj) var exDurationMs int64 = -1 store.SetExpiry(obj, exDurationMs) @@ -8266,7 +8259,7 @@ func testEvalGEOADD(t *testing.T, store *dstore.Store) { }, "GEOADD to a key of wrong type": { setup: func() { - store.Put("mygeo", store.NewObj("string_value", -1, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put("mygeo", store.NewObj("string_value", -1, object.ObjTypeString)) }, input: []string{"mygeo", "-74.0060", "40.7128", "NewYork"}, migratedOutput: EvalResponse{ @@ -8369,7 +8362,7 @@ func testEvalSINTER(t *testing.T, store *dstore.Store) { "intersection with wrong type": { setup: func() { evalSADD([]string{"set1", "a", "b", "c"}, store) - store.Put("string", &object.Obj{Value: "string", TypeEncoding: object.ObjTypeString}) + store.Put("string", &object.Obj{Value: "string", Type: object.ObjTypeString}) }, input: []string{"set1", "string"}, output: []byte("-WRONGTYPE Operation against a key holding the wrong kind of value\r\n"), @@ -8383,55 +8376,6 @@ func testEvalSINTER(t *testing.T, store *dstore.Store) { runEvalTests(t, tests, evalSINTER, store) } -func testEvalOBJECTENCODING(t *testing.T, store *dstore.Store) { - tests := map[string]evalTestCase{ - "nil value": { - setup: func() {}, - input: nil, - migratedOutput: EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongArgumentCount("OBJECT"), - }, - }, - "empty array": { - setup: func() {}, - input: []string{}, - migratedOutput: EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongArgumentCount("OBJECT"), - }, - }, - "object with invalid subcommand": { - setup: func() {}, - input: []string{"TESTSUBCOMMAND", "key"}, - migratedOutput: EvalResponse{ - Result: nil, - Error: diceerrors.ErrSyntax, - }, - }, - "key does not exist": { - setup: func() {}, - input: []string{"ENCODING", "NONEXISTENT_KEY"}, - migratedOutput: EvalResponse{ - Result: clientio.NIL, - Error: nil, - }, - }, - "key exists": { - setup: func() { - evalLPUSH([]string{"EXISTING_KEY", "mock_value"}, store) - }, - input: []string{"ENCODING", "EXISTING_KEY"}, - migratedOutput: EvalResponse{ - Result: "deque", - Error: nil, - }, - }, - } - - runMigratedEvalTests(t, tests, evalOBJECT, store) -} - func testEvalJSONSTRAPPEND(t *testing.T, store *dstore.Store) { tests := map[string]evalTestCase{ "append to single field": { @@ -8440,7 +8384,7 @@ func testEvalJSONSTRAPPEND(t *testing.T, store *dstore.Store) { value := "{\"a\":\"foo\", \"nested1\": {\"a\": \"hello\"}, \"nested2\": {\"a\": 31}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc1", "$.nested1.a", "\"baz\""}, @@ -8465,7 +8409,7 @@ func testEvalJSONSTRAPPEND(t *testing.T, store *dstore.Store) { value := "\"abcd\"" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) }, input: []string{"doc1", "$", "\"piu\""}, @@ -8488,7 +8432,7 @@ func BenchmarkEvalJSONSTRAPPEND(b *testing.B) { value := "{\"a\":\"foo\", \"nested1\": {\"a\": \"hello\"}, \"nested2\": {\"a\": 31}}" var rootData interface{} _ = sonic.Unmarshal([]byte(value), &rootData) - obj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + obj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, obj) b.ResetTimer() @@ -8555,7 +8499,7 @@ func testEvalZPOPMAX(t *testing.T, store *dstore.Store) { }, "ZPOPMAX on an empty sorted set": { setup: func() { - store.Put("myzset", store.NewObj(sortedset.New(), -1, object.ObjTypeSortedSet, object.ObjEncodingBTree)) + store.Put("myzset", store.NewObj(sortedset.New(), -1, object.ObjTypeSortedSet)) }, input: []string{"myzset"}, migratedOutput: EvalResponse{ @@ -8685,7 +8629,7 @@ func testEvalINCR(t *testing.T, store *dstore.Store) { name: "INCR key exists", setup: func() { key := "KEY2" - obj := store.NewObj(int64(1), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(1), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY2"}, @@ -8695,7 +8639,7 @@ func testEvalINCR(t *testing.T, store *dstore.Store) { name: "INCR key holding string value", setup: func() { key := "KEY3" - obj := store.NewObj("VAL1", -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj("VAL1", -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"KEY3"}, @@ -8726,7 +8670,7 @@ func testEvalINCR(t *testing.T, store *dstore.Store) { name: "INCR Max Overflow", setup: func() { key := "KEY5" - obj := store.NewObj(int64(math.MaxInt64), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(math.MaxInt64), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY5"}, @@ -8772,7 +8716,7 @@ func testEvalINCRBY(t *testing.T, store *dstore.Store) { name: "INCRBY key exists", setup: func() { key := "KEY2" - obj := store.NewObj(int64(1), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(1), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY2", "3"}, @@ -8782,7 +8726,7 @@ func testEvalINCRBY(t *testing.T, store *dstore.Store) { name: "INCRBY key holding string value", setup: func() { key := "KEY3" - obj := store.NewObj("VAL1", -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj("VAL1", -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"KEY3", "2"}, @@ -8813,7 +8757,7 @@ func testEvalINCRBY(t *testing.T, store *dstore.Store) { name: "INCRBY Max Overflow", setup: func() { key := "KEY5" - obj := store.NewObj(int64(math.MaxInt64-3), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(math.MaxInt64-3), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY5", "4"}, @@ -8859,7 +8803,7 @@ func testEvalDECR(t *testing.T, store *dstore.Store) { name: "DECR key exists", setup: func() { key := "KEY2" - obj := store.NewObj(int64(1), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(1), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY2"}, @@ -8869,7 +8813,7 @@ func testEvalDECR(t *testing.T, store *dstore.Store) { name: "DECR key holding string value", setup: func() { key := "KEY3" - obj := store.NewObj("VAL1", -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj("VAL1", -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"KEY3"}, @@ -8900,7 +8844,7 @@ func testEvalDECR(t *testing.T, store *dstore.Store) { name: "DECR Min Overflow", setup: func() { key := "KEY5" - obj := store.NewObj(int64(math.MinInt64), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(math.MinInt64), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY5"}, @@ -8946,7 +8890,7 @@ func testEvalDECRBY(t *testing.T, store *dstore.Store) { name: "DECRBY key exists", setup: func() { key := "KEY2" - obj := store.NewObj(int64(1), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(1), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY2", "3"}, @@ -8956,7 +8900,7 @@ func testEvalDECRBY(t *testing.T, store *dstore.Store) { name: "DECRBY key holding string value", setup: func() { key := "KEY3" - obj := store.NewObj("VAL1", -1, object.ObjTypeString, object.ObjEncodingEmbStr) + obj := store.NewObj("VAL1", -1, object.ObjTypeString) store.Put(key, obj) }, input: []string{"KEY3", "2"}, @@ -8987,7 +8931,7 @@ func testEvalDECRBY(t *testing.T, store *dstore.Store) { name: "DECRBY Min Overflow", setup: func() { key := "KEY5" - obj := store.NewObj(int64(math.MinInt64+3), -1, object.ObjTypeInt, object.ObjEncodingInt) + obj := store.NewObj(int64(math.MinInt64+3), -1, object.ObjTypeInt) store.Put(key, obj) }, input: []string{"KEY5", "4"}, @@ -9078,7 +9022,7 @@ func testEvalBFINFO(t *testing.T, store *dstore.Store) { { name: "BF.INFO on non-existent filter", input: []string{"nonExistentFilter"}, - migratedOutput: EvalResponse{Result: nil, Error: errors.New("ERR not found")}, + migratedOutput: EvalResponse{Result: nil, Error: diceerrors.ErrKeyNotFound}, }, } @@ -9227,7 +9171,7 @@ func testEvalLINSERT(t *testing.T, store *dstore.Store) { evalSET([]string{"EXISTING_KEY", "mock_value"}, store) }, input: []string{"EXISTING_KEY", "before", "mock_value", "element"}, - migratedOutput: EvalResponse{Result: nil, Error: errors.New("WRONGTYPE Operation against a key holding the wrong kind of value")}, + migratedOutput: EvalResponse{Result: nil, Error: errors.New("-WRONGTYPE Operation against a key holding the wrong kind of value")}, }, } runMigratedEvalTests(t, tests, evalLINSERT, store) @@ -9273,7 +9217,7 @@ func testEvalLRANGE(t *testing.T, store *dstore.Store) { evalSET([]string{"EXISTING_KEY", "mock_value"}, store) }, input: []string{"EXISTING_KEY", "0", "4"}, - migratedOutput: EvalResponse{Result: nil, Error: errors.New("WRONGTYPE Operation against a key holding the wrong kind of value")}, + migratedOutput: EvalResponse{Result: nil, Error: errors.New("-WRONGTYPE Operation against a key holding the wrong kind of value")}, }, } runMigratedEvalTests(t, tests, evalLRANGE, store) diff --git a/internal/eval/hmap_test.go b/internal/eval/hmap_test.go index 40fcc8005..1e30be0a0 100644 --- a/internal/eval/hmap_test.go +++ b/internal/eval/hmap_test.go @@ -79,7 +79,7 @@ func TestGetValueFromHashMap(t *testing.T) { hmap.Set(field, value) obj := &object.Obj{ - TypeEncoding: object.ObjTypeHashMap | object.ObjEncodingHashMap, + Type: object.ObjTypeHashMap, Value: hmap, LastAccessedAt: uint32(time.Now().Unix()), } diff --git a/internal/eval/sortedset/sorted_set.go b/internal/eval/sortedset/sorted_set.go index f24a62a93..5b4435c3f 100644 --- a/internal/eval/sortedset/sorted_set.go +++ b/internal/eval/sortedset/sorted_set.go @@ -1,6 +1,8 @@ package sortedset import ( + "bytes" + "encoding/binary" "strconv" "strings" @@ -42,7 +44,7 @@ func New() *Set { } func FromObject(obj *object.Obj) (value *Set, err []byte) { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeSortedSet, object.ObjEncodingBTree); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSortedSet); err != nil { return nil, err } value, ok := obj.Value.(*Set) @@ -251,3 +253,59 @@ func (ss *Set) CountInRange(minVal, maxVal float64) int { return count } + +func (ss *Set) Serialize(buf *bytes.Buffer) error { + // Serialize the length of the memberMap + memberCount := uint64(len(ss.memberMap)) + if err := binary.Write(buf, binary.BigEndian, memberCount); err != nil { + return err + } + + // Serialize each member and its score + for member, score := range ss.memberMap { + memberLen := uint64(len(member)) + if err := binary.Write(buf, binary.BigEndian, memberLen); err != nil { + return err + } + if _, err := buf.WriteString(member); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, score); err != nil { + return err + } + } + return nil +} + +func DeserializeSortedSet(buf *bytes.Reader) (*Set, error) { + ss := New() + + // Read the member count + var memberCount uint64 + if err := binary.Read(buf, binary.BigEndian, &memberCount); err != nil { + return nil, err + } + + // Read each member and its score + for i := uint64(0); i < memberCount; i++ { + var memberLen uint64 + if err := binary.Read(buf, binary.BigEndian, &memberLen); err != nil { + return nil, err + } + + member := make([]byte, memberLen) + if _, err := buf.Read(member); err != nil { + return nil, err + } + + var score float64 + if err := binary.Read(buf, binary.BigEndian, &score); err != nil { + return nil, err + } + + // Add the member back to the set + ss.Upsert(score, string(member)) + } + + return ss, nil +} diff --git a/internal/eval/store_eval.go b/internal/eval/store_eval.go index d627c8b6f..112ca82e3 100644 --- a/internal/eval/store_eval.go +++ b/internal/eval/store_eval.go @@ -201,7 +201,7 @@ func evalSET(args []string, store *dstore.Store) *EvalResponse { var oldVal *interface{} key, value = args[0], args[1] - oType, oEnc := deduceTypeEncoding(value) + _, oType := getRawStringOrInt(value) for i := 2; i < len(args); i++ { arg := strings.ToUpper(args[i]) @@ -296,17 +296,17 @@ func evalSET(args []string, store *dstore.Store) *EvalResponse { // Cast the value properly based on the encoding type var storedValue interface{} - switch oEnc { - case object.ObjEncodingInt: + switch oType { + case object.ObjTypeInt: storedValue, _ = strconv.ParseInt(value, 10, 64) - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: + case object.ObjTypeString: storedValue = value default: - return makeEvalError(diceerrors.ErrUnsupportedEncoding(int(oEnc))) + return makeEvalError(diceerrors.ErrUnsupportedEncoding(int(oType))) } // putting the k and value in a Hash Table - store.Put(key, store.NewObj(storedValue, exDurationMs, oType, oEnc), dstore.WithKeepTTL(keepttl)) + store.Put(key, store.NewObj(storedValue, exDurationMs, oType), dstore.WithKeepTTL(keepttl)) if oldVal != nil { return makeEvalResult(*oldVal) } @@ -338,8 +338,8 @@ func evalGET(args []string, store *dstore.Store) *EvalResponse { } // Decode and return the value based on its encoding - switch _, oEnc := object.ExtractTypeEncoding(obj); oEnc { - case object.ObjEncodingInt: + switch oType := obj.Type; oType { + case object.ObjTypeInt: // Value is stored as an int64, so use type assertion if IsInt64(obj.Value) { return &EvalResponse{ @@ -358,7 +358,7 @@ func evalGET(args []string, store *dstore.Store) *EvalResponse { } } - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: + case object.ObjTypeString: // Value is stored as a string, use type assertion if IsString(obj.Value) { return &EvalResponse{ @@ -377,7 +377,7 @@ func evalGET(args []string, store *dstore.Store) *EvalResponse { } } - case object.ObjEncodingByteArray: + case object.ObjTypeByteArray: // Value is stored as a bytearray, use type assertion if val, ok := obj.Value.(*ByteArray); ok { return &EvalResponse{ @@ -494,7 +494,7 @@ func evalHEXISTS(args []string, store *dstore.Store) *EvalResponse { Error: nil, } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Error: diceerrors.ErrGeneral(diceerrors.WrongTypeErr), Result: nil, @@ -539,7 +539,7 @@ func evalHKEYS(args []string, store *dstore.Store) *EvalResponse { var result []string if obj != nil { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Error: diceerrors.ErrGeneral(diceerrors.WrongTypeErr), Result: nil, @@ -586,7 +586,7 @@ func evalHVALS(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Error: diceerrors.ErrGeneral(diceerrors.WrongTypeErr), Result: nil, @@ -642,8 +642,8 @@ func evalGETRANGE(args []string, store *dstore.Store) *EvalResponse { } var str string - switch _, oEnc := object.ExtractTypeEncoding(obj); oEnc { - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: + switch oType := obj.Type; oType { + case object.ObjTypeString: if val, ok := obj.Value.(string); ok { str = val } else { @@ -652,9 +652,9 @@ func evalGETRANGE(args []string, store *dstore.Store) *EvalResponse { Error: diceerrors.ErrGeneral("expected string but got another type"), } } - case object.ObjEncodingInt: + case object.ObjTypeInt: str = strconv.FormatInt(obj.Value.(int64), 10) - case object.ObjEncodingByteArray: + case object.ObjTypeByteArray: if val, ok := obj.Value.(*ByteArray); ok { str = string(val.data) } else { @@ -881,7 +881,7 @@ func shouldSkipMember(score, currentScore float64, exists bool, flags map[string // storeUpdatedSet stores the updated sorted set in the store. func storeUpdatedSet(store *dstore.Store, key string, sortedSet *sortedset.Set) { - store.Put(key, store.NewObj(sortedSet, -1, object.ObjTypeSortedSet, object.ObjEncodingBTree), dstore.WithPutCmd(dstore.ZAdd)) + store.Put(key, store.NewObj(sortedSet, -1, object.ObjTypeSortedSet), dstore.WithPutCmd(dstore.ZAdd)) } // getOrCreateSortedSet fetches the sorted set if it exists, otherwise creates a new one. @@ -1095,19 +1095,8 @@ func evalAPPEND(args []string, store *dstore.Store) *EvalResponse { // Key does not exist, create a new key if obj == nil { - // Deduce type and encoding based on the value if no leading zeros - oType, oEnc := deduceTypeEncoding(value) - - // Transform the value based on the type and encoding - storedValue, err := storeValueWithEncoding(value, oEnc) - if err != nil { - return &EvalResponse{ - Result: nil, - Error: err, - } - } - - store.Put(key, store.NewObj(storedValue, exDurationMs, oType, oEnc)) + storedValue, oType := getRawStringOrInt(value) + store.Put(key, store.NewObj(storedValue, exDurationMs, oType)) return &EvalResponse{ Result: len(value), Error: nil, @@ -1121,10 +1110,10 @@ func evalAPPEND(args []string, store *dstore.Store) *EvalResponse { Error: diceerrors.ErrWrongTypeOperation, } } - _, currentEnc := object.ExtractTypeEncoding(obj) + oType := obj.Type // Transform the value based on the current encoding - currentValue, err := convertValueToString(obj, currentEnc) + currentValue, err := convertValueToString(obj, oType) if err != nil { // If the encoding is neither integer nor string, return a "wrong type" error return &EvalResponse{ @@ -1139,7 +1128,7 @@ func evalAPPEND(args []string, store *dstore.Store) *EvalResponse { // We need to store the new appended value as a string // Even if append is performed on integers, the result will be stored as a string // This is consistent with the redis implementation as append is considered a string operation - store.Put(key, store.NewObj(newValue, exDurationMs, object.ObjTypeString, object.ObjEncodingRaw)) + store.Put(key, store.NewObj(newValue, exDurationMs, object.ObjTypeString)) return &EvalResponse{ Result: len(newValue), Error: nil, @@ -1273,8 +1262,7 @@ func evalJSONCLEAR(args []string, store *dstore.Store) *EvalResponse { } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -1295,7 +1283,7 @@ func evalJSONCLEAR(args []string, store *dstore.Store) *EvalResponse { if len(args) == 1 || path == defaultRootPath { if jsonData != struct{}{} { // If path is root and len(args) == 1, return it instantly - newObj := store.NewObj(struct{}{}, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + newObj := store.NewObj(struct{}{}, -1, object.ObjTypeJSON) store.Put(key, newObj) countClear++ return &EvalResponse{ @@ -1384,8 +1372,7 @@ func jsonGETHelper(store *dstore.Store, path, key string) *EvalResponse { } // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -1525,15 +1512,7 @@ func evalJSONSET(args []string, store *dstore.Store) *EvalResponse { } } else { // If the key exists, check if it's a JSON object - err := object.AssertType(obj.TypeEncoding, object.ObjTypeJSON) - if err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - err = object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingJSON) - if err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeJSON); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -1565,7 +1544,7 @@ func evalJSONSET(args []string, store *dstore.Store) *EvalResponse { } // Create a new object with the updated JSON data - newObj := store.NewObj(rootData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + newObj := store.NewObj(rootData, -1, object.ObjTypeJSON) store.Put(key, newObj) return &EvalResponse{ Result: clientio.OK, @@ -1638,8 +1617,7 @@ func evalJSONTYPE(args []string, store *dstore.Store) *EvalResponse { } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -1717,7 +1695,7 @@ func evalPFADD(args []string, store *dstore.Store) *EvalResponse { hll.Insert([]byte(arg)) } - obj = store.NewObj(hll, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj = store.NewObj(hll, -1, object.ObjTypeString) store.Put(key, obj, dstore.WithPutCmd(dstore.PFADD)) return &EvalResponse{ @@ -1738,7 +1716,7 @@ func evalPFADD(args []string, store *dstore.Store) *EvalResponse { existingHll.Insert([]byte(arg)) } - obj = store.NewObj(existingHll, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj = store.NewObj(existingHll, -1, object.ObjTypeString) store.Put(key, obj, dstore.WithPutCmd(dstore.PFADD)) if newCardinality := existingHll.Estimate(); initialCardinality != newCardinality { @@ -1804,8 +1782,7 @@ func evalJSONSTRLEN(args []string, store *dstore.Store) *EvalResponse { path := args[1] // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -1919,8 +1896,7 @@ func evalJSONOBJLEN(args []string, store *dstore.Store) *EvalResponse { } // check if the object is json - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2059,7 +2035,7 @@ func evalPFMERGE(args []string, store *dstore.Store) *EvalResponse { } // Save the mergedHll - obj = store.NewObj(mergedHll, -1, object.ObjTypeString, object.ObjEncodingRaw) + obj = store.NewObj(mergedHll, -1, object.ObjTypeString) store.Put(destKey, obj, dstore.WithPutCmd(dstore.PFMERGE)) return &EvalResponse{ @@ -2183,7 +2159,7 @@ func evalHINCRBY(args []string, store *dstore.Store) *EvalResponse { key := args[0] obj := store.Get(key) if obj != nil { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2205,7 +2181,7 @@ func evalHINCRBY(args []string, store *dstore.Store) *EvalResponse { } } - obj = store.NewObj(hashmap, -1, object.ObjTypeHashMap, object.ObjEncodingHashMap) + obj = store.NewObj(hashmap, -1, object.ObjTypeHashMap) store.Put(key, obj) return &EvalResponse{ @@ -2242,7 +2218,7 @@ func evalHINCRBYFLOAT(args []string, store *dstore.Store) *EvalResponse { obj := store.Get(key) var hashmap HashMap if obj != nil { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2264,7 +2240,7 @@ func evalHINCRBYFLOAT(args []string, store *dstore.Store) *EvalResponse { } } - obj = store.NewObj(hashmap, -1, object.ObjTypeHashMap, object.ObjEncodingHashMap) + obj = store.NewObj(hashmap, -1, object.ObjTypeHashMap) store.Put(key, obj) return &EvalResponse{ @@ -2296,7 +2272,7 @@ func evalHRANDFIELD(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2432,7 +2408,7 @@ func incrDecrCmd(args []string, incr int64, store *dstore.Store) *EvalResponse { key := args[0] obj := store.Get(key) if obj == nil { - obj = store.NewObj(incr, -1, object.ObjTypeInt, object.ObjEncodingInt) + obj = store.NewObj(incr, -1, object.ObjTypeInt) store.Put(key, obj) return &EvalResponse{ Result: incr, @@ -2441,17 +2417,14 @@ func incrDecrCmd(args []string, incr int64, store *dstore.Store) *EvalResponse { } // if the type is not KV : return wrong type error // if the encoding or type is not int : return value is not an int error - errStr := object.AssertType(obj.TypeEncoding, object.ObjTypeString) - if errStr == nil { + if err := object.AssertTypeWithError(obj.Type, object.ObjTypeString); err == nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrIntegerOutOfRange, } } - errTypeInt := object.AssertType(obj.TypeEncoding, object.ObjTypeInt) - errEncInt := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingInt) - if errEncInt != nil || errTypeInt != nil { + if errTypeInt := object.AssertType(obj.Type, object.ObjTypeInt); errTypeInt != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2504,8 +2477,8 @@ func incrByFloatCmd(args []string, incr float64, store *dstore.Store) *EvalRespo if obj == nil { strValue := formatFloat(incr, false) - oType, oEnc := deduceTypeEncoding(strValue) - obj = store.NewObj(strValue, -1, oType, oEnc) + _, oType := getRawStringOrInt(strValue) + obj = store.NewObj(strValue, -1, oType) store.Put(key, obj) return &EvalResponse{ Result: strValue, @@ -2513,8 +2486,8 @@ func incrByFloatCmd(args []string, incr float64, store *dstore.Store) *EvalRespo } } - errString := object.AssertType(obj.TypeEncoding, object.ObjTypeString) - errInt := object.AssertType(obj.TypeEncoding, object.ObjTypeInt) + errString := object.AssertType(obj.Type, object.ObjTypeString) + errInt := object.AssertType(obj.Type, object.ObjTypeInt) if errString != nil && errInt != nil { return &EvalResponse{ Result: nil, @@ -2538,14 +2511,14 @@ func incrByFloatCmd(args []string, incr float64, store *dstore.Store) *EvalRespo } strValue := formatFloat(value, true) - oType, oEnc := deduceTypeEncoding(strValue) + _, oType := getRawStringOrInt(strValue) // Remove the trailing decimal for integer values // to maintain consistency with redis strValue = strings.TrimSuffix(strValue, ".0") obj.Value = strValue - obj.TypeEncoding = oType | oEnc + obj.Type = oType return &EvalResponse{ Result: strValue, @@ -2646,6 +2619,7 @@ func evalDUMP(args []string, store *dstore.Store) *EvalResponse { serializedValue, err := rdbSerialize(obj) if err != nil { + fmt.Println("error", err) return makeEvalError(diceerrors.ErrGeneral("serialization failed")) } encodedResult := base64.StdEncoding.EncodeToString(serializedValue) @@ -2667,13 +2641,12 @@ func evalRestore(args []string, store *dstore.Store) *EvalResponse { if err != nil { return makeEvalError(diceerrors.ErrGeneral("failed to decode base64 value")) } - obj, err := rdbDeserialize(serializedData) if err != nil { return makeEvalError(diceerrors.ErrGeneral("deserialization failed")) } - newobj := store.NewObj(obj.Value, ttl, obj.TypeEncoding, obj.TypeEncoding) + newobj := store.NewObj(obj.Value, ttl, obj.Type) var keepttl = true if ttl > 0 { @@ -2709,7 +2682,7 @@ func evalHLEN(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2745,7 +2718,7 @@ func evalHSTRLEN(args []string, store *dstore.Store) *EvalResponse { var hashMap HashMap if obj != nil { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2806,7 +2779,7 @@ func evalHSCAN(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -2894,9 +2867,16 @@ func evalBFRESERVE(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(err) } - _, err = CreateBloomFilter(args[0], store, opts) - if err != nil { + key := args[0] + + bf, err := GetBloomFilter(key, store) + if err != nil && err != diceerrors.ErrKeyNotFound { // bloom filter does not exist return makeEvalError(err) + } else if err != nil && err == diceerrors.ErrKeyNotFound { // key does not exists + CreateOrReplaceBloomFilter(key, opts, store) + return makeEvalResult(clientio.OK) + } else if bf != nil { // bloom filter already exists + return makeEvalError(diceerrors.ErrKeyExists) } return makeEvalResult(clientio.OK) } @@ -2908,12 +2888,12 @@ func evalBFADD(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(diceerrors.ErrWrongArgumentCount("BF.ADD")) } - bloom, err := getOrCreateBloomFilter(args[0], store, nil) + bf, err := GetOrCreateBloomFilter(args[0], store, nil) if err != nil { return makeEvalError(err) } - result, err := bloom.add(args[1]) + result, err := bf.add(args[1]) if err != nil { return makeEvalError(err) } @@ -2928,14 +2908,14 @@ func evalBFEXISTS(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(diceerrors.ErrWrongArgumentCount("BF.EXISTS")) } - bloom, err := GetBloomFilter(args[0], store) - if err != nil { + bf, err := GetBloomFilter(args[0], store) + if err != nil && err != diceerrors.ErrKeyNotFound { return makeEvalError(err) - } - if bloom == nil { + } else if err != nil && err == diceerrors.ErrKeyNotFound { return makeEvalResult(clientio.IntegerZero) } - result, err := bloom.exists(args[1]) + + result, err := bf.exists(args[1]) if err != nil { return makeEvalError(err) } @@ -2949,25 +2929,20 @@ func evalBFINFO(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(diceerrors.ErrWrongArgumentCount("BF.INFO")) } - bloom, err := GetBloomFilter(args[0], store) - + bf, err := GetBloomFilter(args[0], store) if err != nil { return makeEvalError(err) } - if bloom == nil { - return makeEvalError(diceerrors.ErrGeneral("not found")) - } opt := "" if len(args) == 2 { opt = args[1] } - result, err := bloom.info(opt) + result, err := bf.info(opt) if err != nil { return makeEvalError(err) } - return makeEvalResult(result) } @@ -3066,8 +3041,7 @@ func evalJSONARRTRIM(args []string, store *dstore.Store) *EvalResponse { } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrGeneral(string(errWithMessage)), @@ -3147,17 +3121,10 @@ func evalLPUSH(args []string, store *dstore.Store) *EvalResponse { obj := store.Get(args[0]) if obj == nil { - obj = store.NewObj(NewDeque(), -1, object.ObjTypeByteList, object.ObjEncodingDeque) + obj = store.NewObj(NewDeque(), -1, object.ObjTypeDequeue) } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeDequeue); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3192,17 +3159,10 @@ func evalRPUSH(args []string, store *dstore.Store) *EvalResponse { obj := store.Get(args[0]) if obj == nil { - obj = store.NewObj(NewDeque(), -1, object.ObjTypeByteList, object.ObjEncodingDeque) + obj = store.NewObj(NewDeque(), -1, object.ObjTypeDequeue) } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeDequeue); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3273,14 +3233,7 @@ func evalLPOP(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeDequeue); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3342,14 +3295,7 @@ func evalRPOP(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeDequeue); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3392,7 +3338,7 @@ func evalLLEN(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeByteList, object.ObjEncodingDeque); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeDequeue); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3431,8 +3377,7 @@ func evalJSONARRAPPEND(args []string, store *dstore.Store) *EvalResponse { Error: nil, } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3534,8 +3479,7 @@ func evalJSONARRLEN(args []string, store *dstore.Store) *EvalResponse { } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3677,8 +3621,7 @@ func evalJSONARRPOP(args []string, store *dstore.Store) *EvalResponse { } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -3714,7 +3657,7 @@ func evalJSONARRPOP(args []string, store *dstore.Store) *EvalResponse { } // save the remaining array - newObj := store.NewObj(arr, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + newObj := store.NewObj(arr, -1, object.ObjTypeJSON) store.Put(key, newObj) return &EvalResponse{ @@ -3788,8 +3731,7 @@ func evalJSONARRINSERT(args []string, store *dstore.Store) *EvalResponse { } } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrGeneral(string(errWithMessage)), @@ -3925,8 +3867,7 @@ func evalJSONOBJKEYS(args []string, store *dstore.Store) *EvalResponse { } // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrGeneral(string(errWithMessage)), @@ -4022,8 +3963,7 @@ func evalJSONRESP(args []string, store *dstore.Store) *EvalResponse { } // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4158,8 +4098,7 @@ func evalJSONDebugMemory(args []string, store *dstore.Store) *EvalResponse { } // check if the object is a valid JSON - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrInvalidJSONPathType, @@ -4179,7 +4118,7 @@ func evalJSONDebugMemory(args []string, store *dstore.Store) *EvalResponse { } } // add memory used by storage object - size += int(unsafe.Sizeof(obj)) + calculateSizeInBytes(obj.LastAccessedAt) + calculateSizeInBytes(obj.TypeEncoding) + size += int(unsafe.Sizeof(obj)) + calculateSizeInBytes(obj.LastAccessedAt) + calculateSizeInBytes(obj.Type) return &EvalResponse{ Result: size, @@ -4419,8 +4358,8 @@ func evalGETEX(args []string, store *dstore.Store) *EvalResponse { } } - if object.AssertType(obj.TypeEncoding, object.ObjTypeSet) == nil || - object.AssertType(obj.TypeEncoding, object.ObjTypeJSON) == nil { + if object.AssertType(obj.Type, object.ObjTypeSet) == nil || + object.AssertType(obj.Type, object.ObjTypeJSON) == nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4474,7 +4413,7 @@ func evalGETDEL(args []string, store *dstore.Store) *EvalResponse { } // If the object exists, check if it is a Set object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err == nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err == nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4482,7 +4421,7 @@ func evalGETDEL(args []string, store *dstore.Store) *EvalResponse { } // If the object exists, check if it is a JSON object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeJSON); err == nil { + if err := object.AssertType(obj.Type, object.ObjTypeJSON); err == nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4493,8 +4432,8 @@ func evalGETDEL(args []string, store *dstore.Store) *EvalResponse { objVal := store.GetDel(key) // Decode and return the value based on its encoding - switch _, oEnc := object.ExtractTypeEncoding(objVal); oEnc { - case object.ObjEncodingInt: + switch oType := objVal.Type; oType { + case object.ObjTypeInt: // Value is stored as an int64, so use type assertion if IsInt64(objVal.Value) { return &EvalResponse{ @@ -4513,7 +4452,7 @@ func evalGETDEL(args []string, store *dstore.Store) *EvalResponse { } } - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: + case object.ObjTypeString: // Value is stored as a string, use type assertion if IsString(objVal.Value) { return &EvalResponse{ @@ -4532,7 +4471,7 @@ func evalGETDEL(args []string, store *dstore.Store) *EvalResponse { } } - case object.ObjEncodingByteArray: + case object.ObjTypeByteArray: // Value is stored as a bytearray, use type assertion if val, ok := objVal.Value.(*ByteArray); ok { return &EvalResponse{ @@ -4562,7 +4501,7 @@ func insertInHashMap(args []string, store *dstore.Store) (int64, error) { var hashMap HashMap if obj != nil { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return 0, diceerrors.ErrWrongTypeOperation } hashMap = obj.Value.(HashMap) @@ -4575,7 +4514,7 @@ func insertInHashMap(args []string, store *dstore.Store) (int64, error) { return 0, err } - obj = store.NewObj(hashMap, -1, object.ObjTypeHashMap, object.ObjEncodingHashMap) + obj = store.NewObj(hashMap, -1, object.ObjTypeHashMap) store.Put(key, obj) return numKeys, nil @@ -4674,7 +4613,7 @@ func evalHMGET(args []string, store *dstore.Store) *EvalResponse { } // Assert that the object is of type HashMap - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4741,7 +4680,7 @@ func evalHGETALL(args []string, store *dstore.Store) *EvalResponse { var results []string if obj != nil { - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4814,7 +4753,7 @@ func evalHDEL(args []string, store *dstore.Store) *EvalResponse { } } - if err := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeHashMap, object.ObjEncodingHashMap); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeHashMap); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4866,18 +4805,11 @@ func evalSADD(args []string, store *dstore.Store) *EvalResponse { // If the object does not exist, create a new set object. value := make(map[string]struct{}, lengthOfItems) // Create a new object. - obj = store.NewObj(value, exDurationMs, object.ObjTypeSet, object.ObjEncodingSetStr) + obj = store.NewObj(value, exDurationMs, object.ObjTypeSet) store.Put(key, obj, dstore.WithKeepTTL(keepttl)) } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4926,14 +4858,7 @@ func evalSREM(args []string, store *dstore.Store) *EvalResponse { } // If the object exists, check if it is a set object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -4980,14 +4905,7 @@ func evalSCARD(args []string, store *dstore.Store) *EvalResponse { } // If the object exists, check if it is a set object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -5025,14 +4943,7 @@ func evalSMEMBERS(args []string, store *dstore.Store) *EvalResponse { } // If the object exists, check if it is a set object. - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeSet); err != nil { - return &EvalResponse{ - Result: nil, - Error: diceerrors.ErrWrongTypeOperation, - } - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingSetStr); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeSet); err != nil { return &EvalResponse{ Result: nil, Error: diceerrors.ErrWrongTypeOperation, @@ -5077,19 +4988,10 @@ func evalLRANGE(args []string, store *dstore.Store) *EvalResponse { return makeEvalResult([]string{}) } - // if object is a set type, return error - if object.AssertType(obj.TypeEncoding, object.ObjTypeSet) == nil { + if object.AssertType(obj.Type, object.ObjTypeDequeue) != nil { return makeEvalError(errors.New(diceerrors.WrongTypeErr)) } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil { - return makeEvalError(err) - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil { - return makeEvalError(err) - } - q := obj.Value.(*Deque) res, err := q.LRange(start, stop) if err != nil { @@ -5119,18 +5021,10 @@ func evalLINSERT(args []string, store *dstore.Store) *EvalResponse { } // if object is a set type, return error - if object.AssertType(obj.TypeEncoding, object.ObjTypeSet) == nil { + if object.AssertType(obj.Type, object.ObjTypeDequeue) != nil { return makeEvalError(errors.New(diceerrors.WrongTypeErr)) } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeByteList); err != nil { - return makeEvalError(err) - } - - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingDeque); err != nil { - return makeEvalError(err) - } - q := obj.Value.(*Deque) res, err := q.LInsert(pivot, element, beforeAfter) if err != nil { @@ -5171,15 +5065,15 @@ func evalSETBIT(args []string, store *dstore.Store) *EvalResponse { requiredByteArraySize := offset>>3 + 1 if obj == nil { - obj = store.NewObj(NewByteArray(int(requiredByteArraySize)), -1, object.ObjTypeByteArray, object.ObjEncodingByteArray) + obj = store.NewObj(NewByteArray(int(requiredByteArraySize)), -1, object.ObjTypeByteArray) store.Put(args[0], obj) } - if object.AssertType(obj.TypeEncoding, object.ObjTypeByteArray) == nil || - object.AssertType(obj.TypeEncoding, object.ObjTypeString) == nil || - object.AssertType(obj.TypeEncoding, object.ObjTypeInt) == nil { + if object.AssertType(obj.Type, object.ObjTypeByteArray) == nil || + object.AssertType(obj.Type, object.ObjTypeString) == nil || + object.AssertType(obj.Type, object.ObjTypeInt) == nil { var byteArray *ByteArray - oType, oEnc := object.ExtractTypeEncoding(obj) + oType := obj.Type switch oType { case object.ObjTypeByteArray: @@ -5212,7 +5106,7 @@ func evalSETBIT(args []string, store *dstore.Store) *EvalResponse { // We are returning newObject here so it is thread-safe // Old will be removed by GC - newObj, err := ByteSliceToObj(store, obj, byteArray.data, oType, oEnc) + newObj, err := ByteSliceToObj(store, obj, byteArray.data, oType) if err != nil { return &EvalResponse{ Result: nil, @@ -5277,7 +5171,7 @@ func evalGETBIT(args []string, store *dstore.Store) *EvalResponse { } requiredByteArraySize := offset>>3 + 1 - switch oType, _ := object.ExtractTypeEncoding(obj); oType { + switch oType := obj.Type; oType { case object.ObjTypeSet: return &EvalResponse{ Result: nil, @@ -5373,14 +5267,14 @@ func evalBITCOUNT(args []string, store *dstore.Store) *EvalResponse { var valueLength int64 switch { - case object.AssertType(obj.TypeEncoding, object.ObjTypeByteArray) == nil: + case object.AssertType(obj.Type, object.ObjTypeByteArray) == nil: byteArray := obj.Value.(*ByteArray) value = byteArray.data valueLength = byteArray.Length - case object.AssertType(obj.TypeEncoding, object.ObjTypeString) == nil: + case object.AssertType(obj.Type, object.ObjTypeString) == nil: value = []byte(obj.Value.(string)) valueLength = int64(len(value)) - case object.AssertType(obj.TypeEncoding, object.ObjTypeInt) == nil: + case object.AssertType(obj.Type, object.ObjTypeInt) == nil: value = []byte(strconv.FormatInt(obj.Value.(int64), 10)) valueLength = int64(len(value)) default: @@ -5520,13 +5414,13 @@ func bitfieldEvalGeneric(args []string, store *dstore.Store, isReadOnly bool) *E key := args[0] obj := store.Get(key) if obj == nil { - obj = store.NewObj(NewByteArray(1), -1, object.ObjTypeByteArray, object.ObjEncodingByteArray) + obj = store.NewObj(NewByteArray(1), -1, object.ObjTypeByteArray) store.Put(args[0], obj) } var value *ByteArray var err error - switch oType, _ := object.ExtractTypeEncoding(obj); oType { + switch oType := obj.Type; oType { case object.ObjTypeByteArray: value = obj.Value.(*ByteArray) case object.ObjTypeString, object.ObjTypeInt: @@ -5644,8 +5538,7 @@ func evalJSONSTRAPPEND(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(diceerrors.ErrKeyDoesNotExist) } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return makeEvalError(diceerrors.ErrWrongTypeOperation) } @@ -5713,8 +5606,7 @@ func evalJSONTOGGLE(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(diceerrors.ErrKeyDoesNotExist) } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return makeEvalError(diceerrors.ErrWrongTypeOperation) } @@ -5802,8 +5694,7 @@ func evalJSONDEL(args []string, store *dstore.Store) *EvalResponse { return makeEvalResult(clientio.IntegerZero) } - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return makeEvalError(diceerrors.ErrWrongTypeOperation) } @@ -5838,7 +5729,7 @@ func evalJSONDEL(args []string, store *dstore.Store) *EvalResponse { return makeEvalError(diceerrors.ErrInternalServer) // no need to send actual internal error } // Create a new object with the updated JSON data - newObj := store.NewObj(jsonData, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + newObj := store.NewObj(jsonData, -1, object.ObjTypeJSON) store.Put(key, newObj) return makeEvalResult(len(results)) @@ -5917,8 +5808,7 @@ func evalJSONNUMMULTBY(args []string, store *dstore.Store) *EvalResponse { } // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return makeEvalError(diceerrors.ErrWrongTypeOperation) } path := args[1] @@ -5975,8 +5865,8 @@ func evalJSONNUMMULTBY(args []string, store *dstore.Store) *EvalResponse { resultString := `[` + strings.Join(resultArray, ",") + `]` newObj := &object.Obj{ - Value: jsonData, - TypeEncoding: object.ObjTypeJSON, + Value: jsonData, + Type: object.ObjTypeJSON, } exp, ok := dstore.GetExpiry(obj, store) @@ -6084,8 +5974,7 @@ func evalJSONNUMINCRBY(args []string, store *dstore.Store) *EvalResponse { } // Check if the object is of JSON type - errWithMessage := object.AssertTypeAndEncoding(obj.TypeEncoding, object.ObjTypeJSON, object.ObjEncodingJSON) - if errWithMessage != nil { + if errWithMessage := object.AssertType(obj.Type, object.ObjTypeJSON); errWithMessage != nil { return makeEvalError(diceerrors.ErrWrongTypeOperation) } @@ -6256,7 +6145,7 @@ func evalGEOADD(args []string, store *dstore.Store) *EvalResponse { } } - obj = store.NewObj(ss, -1, object.ObjTypeSortedSet, object.ObjEncodingBTree) + obj = store.NewObj(ss, -1, object.ObjTypeSortedSet) store.Put(key, obj) return &EvalResponse{ @@ -6485,10 +6374,10 @@ func evalTYPE(args []string, store *dstore.Store) *EvalResponse { } var typeStr string - switch oType, _ := object.ExtractTypeEncoding(obj); oType { + switch oType := obj.Type; oType { case object.ObjTypeString, object.ObjTypeInt, object.ObjTypeByteArray: typeStr = "string" - case object.ObjTypeByteList: + case object.ObjTypeDequeue: typeStr = "list" case object.ObjTypeSet: typeStr = "set" @@ -6505,442 +6394,3 @@ func evalTYPE(args []string, store *dstore.Store) *EvalResponse { Error: nil, } } - -// // BITOP destkey key [key ...] -// func evalBITOP(args []string, store *dstore.Store) *EvalResponse { -// operation, destKey := args[0], args[1] -// operation = strings.ToUpper(operation) - -// // get all the keys -// keys := args[2:] - -// // validation of commands -// // if operation is not from enums, then error out -// if !(operation == AND || operation == OR || operation == XOR || operation == NOT) { -// return makeEvalError(diceerrors.ErrSyntax) -// } - -// if operation == NOT { -// if len(keys) != 1 { -// return makeEvalError(diceerrors.ErrGeneral("BITOP NOT must be called with a single source key")) -// } -// key := keys[0] -// obj := store.Get(key) -// if obj == nil { -// return makeEvalResult(clientio.IntegerZero) -// } - -// var value []byte - -// switch oType, _ := object.ExtractTypeEncoding(obj); oType { -// case object.ObjTypeByteArray: -// byteArray := obj.Value.(*ByteArray) -// byteArrayObject := *byteArray -// value = byteArrayObject.data -// // perform the operation -// result := make([]byte, len(value)) -// for i := 0; i < len(value); i++ { -// result[i] = ^value[i] -// } - -// // initialize result with byteArray -// operationResult := NewByteArray(len(result)) -// operationResult.data = result -// operationResult.Length = int64(len(result)) - -// // resize the byte array if necessary -// operationResult.ResizeIfNecessary() - -// // create object related to result -// obj = store.NewObj(operationResult, -1, object.ObjTypeByteArray, object.ObjEncodingByteArray) - -// // store the result in destKey -// store.Put(destKey, obj) -// return makeEvalResult(len(value)) - -// case object.ObjTypeString, object.ObjTypeInt: -// if oType == object.ObjTypeString { -// value = []byte(obj.Value.(string)) -// } else { -// value = []byte(strconv.FormatInt(obj.Value.(int64), 10)) -// } -// // perform the operation -// result := make([]byte, len(value)) -// for i := 0; i < len(value); i++ { -// result[i] = ^value[i] -// } -// resOType, resOEnc := deduceTypeEncoding(string(result)) -// var storedValue interface{} -// if resOType == object.ObjTypeInt { -// storedValue, _ = strconv.ParseInt(string(result), 10, 64) -// } else { -// storedValue = string(result) -// } -// store.Put(destKey, store.NewObj(storedValue, -1, resOType, resOEnc)) -// return makeEvalResult(len(value)) - -// default: -// return makeEvalError(diceerrors.ErrWrongTypeOperation) -// } -// } -// // if operation is AND, OR, XOR -// values := make([][]byte, len(keys)) - -// // get the values of all keys -// for i, key := range keys { -// obj := store.Get(key) -// if obj == nil { -// values[i] = make([]byte, 0) -// } else { -// // handle the case when it is byte array -// switch oType, _ := object.ExtractTypeEncoding(obj); oType { -// case object.ObjTypeByteArray: -// byteArray := obj.Value.(*ByteArray) -// byteArrayObject := *byteArray -// values[i] = byteArrayObject.data -// case object.ObjTypeString: -// value := obj.Value.(string) -// values[i] = []byte(value) -// case object.ObjTypeInt: -// value := strconv.FormatInt(obj.Value.(int64), 10) -// values[i] = []byte(value) -// default: -// return makeEvalError(diceerrors.ErrWrongTypeOperation) -// } -// } -// } -// // get the length of the largest value -// maxLength := 0 -// minLength := len(values[0]) -// maxKeyIterator := 0 -// for keyIterator, value := range values { -// if len(value) > maxLength { -// maxLength = len(value) -// maxKeyIterator = keyIterator -// } -// minLength = min(minLength, len(value)) -// } - -// result := make([]byte, maxLength) -// if operation == AND { -// for i := 0; i < maxLength; i++ { -// result[i] = 0 -// if i < minLength { -// result[i] = values[maxKeyIterator][i] -// } -// } -// } else { -// for i := 0; i < maxLength; i++ { -// result[i] = 0x00 -// } -// } - -// // perform the operation -// for _, value := range values { -// for i := 0; i < len(value); i++ { -// switch operation { -// case AND: -// result[i] &= value[i] -// case OR: -// result[i] |= value[i] -// case XOR: -// result[i] ^= value[i] -// } -// } -// } -// // initialize result with byteArray -// operationResult := NewByteArray(len(result)) -// operationResult.data = result -// operationResult.Length = int64(len(result)) - -// // create object related to result -// operationResultObject := store.NewObj(operationResult, -1, object.ObjTypeByteArray, object.ObjEncodingByteArray) - -// // store the result in destKey -// store.Put(destKey, operationResultObject) - -// return makeEvalResult(len(result)) -// } - -func evalFLUSHDB(args []string, store *dstore.Store) *EvalResponse { - if len(args) > 1 { - return makeEvalError(diceerrors.ErrWrongArgumentCount("FLUSHDB")) - } - - flushType := Sync - if len(args) == 1 { - flushType = strings.ToUpper(args[0]) - } - - switch flushType { - case Sync, Async: - store.ResetStore() - default: - return makeEvalError(diceerrors.ErrSyntax) - } - - return makeEvalResult(clientio.OK) -} - -func evalObjectIdleTime(key string, store *dstore.Store) *EvalResponse { - obj := store.GetNoTouch(key) - if obj == nil { - return makeEvalResult(clientio.NIL) - } - - return makeEvalResult(int64(dstore.GetIdleTime(obj.LastAccessedAt))) -} - -func evalObjectEncoding(key string, store *dstore.Store) *EvalResponse { - var encodingTypeStr string - - obj := store.GetNoTouch(key) - if obj == nil { - return makeEvalResult(clientio.NIL) - } - - oType, oEnc := object.ExtractTypeEncoding(obj) - switch { - case oType == object.ObjTypeString && oEnc == object.ObjEncodingRaw: - encodingTypeStr = "raw" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeString && oEnc == object.ObjEncodingEmbStr: - encodingTypeStr = "embstr" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeInt && oEnc == object.ObjEncodingInt: - encodingTypeStr = "int" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeByteList && oEnc == object.ObjEncodingDeque: - encodingTypeStr = "deque" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeBitSet && oEnc == object.ObjEncodingBF: - encodingTypeStr = "bf" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeJSON && oEnc == object.ObjEncodingJSON: - encodingTypeStr = "json" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeByteArray && oEnc == object.ObjEncodingByteArray: - encodingTypeStr = "bytearray" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeSet && oEnc == object.ObjEncodingSetStr: - encodingTypeStr = "setstr" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeSet && oEnc == object.ObjEncodingSetInt: - encodingTypeStr = "setint" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeHashMap && oEnc == object.ObjEncodingHashMap: - encodingTypeStr = "hashmap" - return makeEvalResult(encodingTypeStr) - - case oType == object.ObjTypeSortedSet && oEnc == object.ObjEncodingBTree: - encodingTypeStr = "btree" - return makeEvalResult(encodingTypeStr) - - default: - return makeEvalError(diceerrors.ErrWrongTypeOperation) - } -} - -func evalOBJECT(args []string, store *dstore.Store) *EvalResponse { - if len(args) < 2 { - return makeEvalError(diceerrors.ErrWrongArgumentCount("OBJECT")) - } - - subcommand := strings.ToUpper(args[0]) - key := args[1] - - switch subcommand { - case "IDLETIME": - return evalObjectIdleTime(key, store) - case "ENCODING": - return evalObjectEncoding(key, store) - default: - return makeEvalError(diceerrors.ErrSyntax) - } -} - -// evalCommand evaluates COMMAND command based on subcommand -// COUNT: return total count of commands in Dice. -func evalCommand(args []string, store *dstore.Store) *EvalResponse { - if len(args) == 0 { - return evalCommandDefault() - } - subcommand := strings.ToUpper(args[0]) - switch subcommand { - case Count: - return evalCommandCount(args[1:]) - case GetKeys: - return evalCommandGetKeys(args[1:]) - case List: - return evalCommandList(args[1:]) - case Help: - return evalCommandHelp(args[1:]) - case Info: - return evalCommandInfo(args[1:]) - case Docs: - return evalCommandDocs(args[1:]) - default: - return makeEvalError(diceerrors.ErrGeneral(fmt.Sprintf("unknown subcommand '%s'. Try COMMAND HELP.", subcommand))) - } -} - -func evalCommandDefault() *EvalResponse { - cmds := convertDiceCmdsMapToSlice() - return makeEvalResult(cmds) -} - -// evalCommandCount returns a number of commands supported by DiceDB -func evalCommandCount(args []string) *EvalResponse { - if len(args) > 0 { - return makeEvalError(diceerrors.ErrWrongArgumentCount("COMMAND|COUNT")) - } - - return makeEvalResult(diceCommandsCount) -} - -func evalCommandGetKeys(args []string) *EvalResponse { - if len(args) == 0 { - return makeEvalError(diceerrors.ErrWrongArgumentCount("COMMAND|GETKEYS")) - } - diceCmd, ok := DiceCmds[strings.ToUpper(args[0])] - if !ok { - return makeEvalError(diceerrors.ErrGeneral("invalid command specified")) - } - - keySpecs := diceCmd.KeySpecs - if keySpecs.BeginIndex == 0 { - return makeEvalError(diceerrors.ErrGeneral("the command has no key arguments")) - } - - arity := diceCmd.Arity - if (arity < 0 && len(args) < -arity) || - (arity >= 0 && len(args) != arity) { - return makeEvalError(diceerrors.ErrGeneral("invalid number of arguments specified for command")) - } - keys := make([]string, 0) - step := max(keySpecs.Step, 1) - lastIdx := keySpecs.BeginIndex - if keySpecs.LastKey != 0 { - lastIdx = len(args) + keySpecs.LastKey - } - for i := keySpecs.BeginIndex; i <= lastIdx; i += step { - keys = append(keys, args[i]) - } - - return makeEvalResult(keys) -} - -func evalCommandList(args []string) *EvalResponse { - if len(args) > 0 { - return makeEvalError(diceerrors.ErrWrongArgumentCount("COMMAND|LIST")) - } - - cmds := make([]string, 0, diceCommandsCount) - for k := range DiceCmds { - cmds = append(cmds, k) - for _, sc := range DiceCmds[k].SubCommands { - cmds = append(cmds, fmt.Sprint(k, "|", sc)) - } - } - return makeEvalResult(cmds) -} - -// evalCommandHelp prints help message -func evalCommandHelp(args []string) *EvalResponse { - if len(args) > 0 { - return makeEvalError(diceerrors.ErrWrongArgumentCount("COMMAND|HELP")) - } - - format := "COMMAND [ [value] [opt] ...]. Subcommands are:" - noTitle := "(no subcommand)" - noMessage := " Return details about all DiceDB commands." - countTitle := CountConst - countMessage := " Return the total number of commands in this DiceDB server." - listTitle := "LIST" - listMessage := " Return a list of all commands in this DiceDB server." - infoTitle := "INFO [ ...]" - infoMessage := " Return details about the specified DiceDB commands. If no command names are given, documentation details for all commands are returned." - docsTitle := "DOCS [ ...]" - docsMessage := "\tReturn documentation details about multiple diceDB commands.\n\tIf no command names are given, documentation details for all\n\tcommands are returned." - getKeysTitle := "GETKEYS " - getKeysMessage := " Return the keys from a full DiceDB command." - helpTitle := "HELP" - helpMessage := " Print this help." - message := []string{ - format, - noTitle, - noMessage, - countTitle, - countMessage, - listTitle, - listMessage, - infoTitle, - infoMessage, - docsTitle, - docsMessage, - getKeysTitle, - getKeysMessage, - helpTitle, - helpMessage, - } - - return makeEvalResult(message) -} - -func evalCommandDefaultDocs() *EvalResponse { - cmds := convertDiceCmdsMapToDocs() - return makeEvalResult(cmds) -} - -func evalCommandInfo(args []string) *EvalResponse { - if len(args) == 0 { - return evalCommandDefault() - } - - cmdMetaMap := make(map[string]interface{}) - for _, cmdMeta := range DiceCmds { - cmdMetaMap[cmdMeta.Name] = convertCmdMetaToSlice(&cmdMeta) - } - - var result []interface{} - for _, arg := range args { - arg = strings.ToUpper(arg) - if cmdMeta, found := cmdMetaMap[arg]; found { - result = append(result, cmdMeta) - } else { - result = append(result, clientio.RespNIL) - } - } - - return makeEvalResult(result) -} - -func evalCommandDocs(args []string) *EvalResponse { - if len(args) == 0 { - return evalCommandDefaultDocs() - } - - cmdMetaMap := make(map[string]interface{}) - for _, cmdMeta := range DiceCmds { - cmdMetaMap[cmdMeta.Name] = convertCmdMetaToDocs(&cmdMeta) - } - - var result []interface{} - for _, arg := range args { - arg = strings.ToUpper(arg) - if cmdMeta, found := cmdMetaMap[arg]; found { - result = append(result, cmdMeta) - } - } - - return makeEvalResult(result) -} diff --git a/internal/eval/bloom.go b/internal/eval/type_bloomfilter.go similarity index 65% rename from internal/eval/bloom.go rename to internal/eval/type_bloomfilter.go index fc5ce91b8..98c373fa0 100644 --- a/internal/eval/bloom.go +++ b/internal/eval/type_bloomfilter.go @@ -1,6 +1,8 @@ package eval import ( + "bytes" + "encoding/binary" "fmt" "hash" "math" @@ -50,6 +52,8 @@ type BloomOpts struct { // is under the assumption that it's consumed at only 1 place at a time. Add // a lock when multiple clients can be supported. indexes []uint64 + + hashFnsSeeds []uint64 // seed for hash functions } type Bloom struct { @@ -92,7 +96,7 @@ func newBloomOpts(args []string) (*BloomOpts, error) { // newBloomFilter creates and returns a new filter. It is responsible for initializing the // underlying bit array. -func newBloomFilter(opts *BloomOpts) *Bloom { +func NewBloomFilter(opts *BloomOpts) *Bloom { // Calculate bits per element // bpe = -log(errorRate)/ln(2)^2 num := -1 * math.Log(opts.errorRate) @@ -102,10 +106,11 @@ func newBloomFilter(opts *BloomOpts) *Bloom { // k = ceil(ln(2) * bpe) k := math.Ceil(ln2 * opts.bpe) opts.hashFns = make([]hash.Hash64, int(k)) - + opts.hashFnsSeeds = make([]uint64, int(k)) // Initialize hash functions with random seeds for i := 0; i < int(k); i++ { - opts.hashFns[i] = murmur3.SeedNew64(rand.Uint64()) //nolint:gosec + opts.hashFnsSeeds[i] = rand.Uint64() //nolint:gosec + opts.hashFns[i] = murmur3.SeedNew64(opts.hashFnsSeeds[i]) } // initialize the common slice for storing indexes of bits to be set @@ -115,15 +120,15 @@ func newBloomFilter(opts *BloomOpts) *Bloom { // bits = k * entries / ln(2) // bytes = bits * 8 bits := uint64(math.Ceil((k * float64(opts.capacity)) / ln2)) - var bytes uint64 + var bytesNeeded uint64 if bits%8 == 0 { - bytes = bits / 8 + bytesNeeded = bits / 8 } else { - bytes = (bits / 8) + 1 + bytesNeeded = (bits / 8) + 1 } - opts.bits = bytes * 8 + opts.bits = bytesNeeded * 8 - bitset := make([]byte, bytes) + bitset := make([]byte, bytesNeeded) return &Bloom{opts, bitset, 0} } @@ -278,33 +283,46 @@ func (opts *BloomOpts) updateIndexes(value string) error { return nil } -// getOrCreateBloomFilter attempts to fetch an existing bloom filter from -// the kv store. If it does not exist, it tries to create one with -// given `opts` and returns it. -func getOrCreateBloomFilter(key string, store *dstore.Store, opts *BloomOpts) (*Bloom, error) { +// CreateOrReplaceBloomFilter creates a new bloom filter with given `opts` +// and stores it in the kv store. If the bloom filter already exists, it +// replaces the existing one. If `opts` is nil, it uses the default options. +func CreateOrReplaceBloomFilter(key string, opts *BloomOpts, store *dstore.Store) *Bloom { + if opts == nil { + opts = defaultBloomOpts() + } + bf := NewBloomFilter(opts) + obj := store.NewObj(bf, -1, object.ObjTypeBF) + store.Put(key, obj) + return bf +} + +// GetOrCreateBloomFilter fetches an existing bloom filter from +// the kv store and returns the datastructure instance of it. +// If it does not exist, it tries to create one with given `opts` and returns it. +// Note: It also stores it in the kv store. +func GetOrCreateBloomFilter(key string, store *dstore.Store, opts *BloomOpts) (*Bloom, error) { bf, err := GetBloomFilter(key, store) - if err != nil { + if err != nil && err != diceerrors.ErrKeyNotFound { return nil, err + } else if err != nil && err == diceerrors.ErrKeyNotFound { + bf = CreateOrReplaceBloomFilter(key, opts, store) } - if bf == nil { - bf, err = CreateBloomFilter(key, store, opts) - } - return bf, err + return bf, nil } -// get the bloom filter +// GetBloomFilter fetches an existing bloom filter from +// the kv store and returns the datastructure instance of it. +// The function also returns diceerrors.ErrKeyNotFound if the key does not exist. +// It also returns diceerrors.ErrWrongTypeOperation if the object is not a bloom filter. func GetBloomFilter(key string, store *dstore.Store) (*Bloom, error) { obj := store.Get(key) if obj == nil { - return nil, nil + return nil, diceerrors.ErrKeyNotFound } - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeBitSet); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeBF); err != nil { return nil, diceerrors.ErrWrongTypeOperation } - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingBF); err != nil { - return nil, diceerrors.ErrWrongTypeOperation - } return obj.Value.(*Bloom), nil } @@ -319,7 +337,103 @@ func CreateBloomFilter(key string, store *dstore.Store, opts *BloomOpts) (*Bloom if opts == nil { opts = defaultBloomOpts() } - obj := store.NewObj(newBloomFilter(opts), -1, object.ObjTypeBitSet, object.ObjEncodingBF) + obj := store.NewObj(newBloomFilter(opts), -1, object.ObjTypeBF) store.Put(key, obj) return obj.Value.(*Bloom), nil } + +func (b *Bloom) Serialize(buf *bytes.Buffer) error { + // Serialize the Bloom struct + if err := binary.Write(buf, binary.BigEndian, b.cnt); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, b.opts.errorRate); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, b.opts.capacity); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, b.opts.bits); err != nil { + return err + } + + // Serialize the number of seeds and the seeds themselves + numSeeds := uint64(len(b.opts.hashFnsSeeds)) + if err := binary.Write(buf, binary.BigEndian, numSeeds); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, b.opts.hashFnsSeeds); err != nil { + return err + } + + // Serialize the number of indexes and the indexes themselves + numIndexes := uint64(len(b.opts.indexes)) + if err := binary.Write(buf, binary.BigEndian, numIndexes); err != nil { + return err + } + if err := binary.Write(buf, binary.BigEndian, b.opts.indexes); err != nil { + return err + } + + // Serialize the bitset + if _, err := buf.Write(b.bitset); err != nil { + return err + } + + return nil +} + +func DeserializeBloom(buf *bytes.Reader) (*Bloom, error) { + bloom := &Bloom{ + opts: &BloomOpts{}, // Initialize the opts field to prevent nil pointer dereference + } + + // Deserialize the Bloom struct + if err := binary.Read(buf, binary.BigEndian, &bloom.cnt); err != nil { + return nil, err + } + if err := binary.Read(buf, binary.BigEndian, &bloom.opts.errorRate); err != nil { + return nil, err + } + if err := binary.Read(buf, binary.BigEndian, &bloom.opts.capacity); err != nil { + return nil, err + } + if err := binary.Read(buf, binary.BigEndian, &bloom.opts.bits); err != nil { + return nil, err + } + + // Deserialize hash function seeds + var numSeeds uint64 + if err := binary.Read(buf, binary.BigEndian, &numSeeds); err != nil { + return nil, err + } + bloom.opts.hashFnsSeeds = make([]uint64, numSeeds) + if err := binary.Read(buf, binary.BigEndian, &bloom.opts.hashFnsSeeds); err != nil { + return nil, err + } + + // Deserialize indexes + var numIndexes uint64 + if err := binary.Read(buf, binary.BigEndian, &numIndexes); err != nil { + return nil, err + } + bloom.opts.indexes = make([]uint64, numIndexes) + if err := binary.Read(buf, binary.BigEndian, &bloom.opts.indexes); err != nil { + return nil, err + } + + // Deserialize bitset + bloom.bitset = make([]byte, bloom.opts.bits) + if _, err := buf.Read(bloom.bitset); err != nil { + return nil, err + } + + // Recalculate derived values + bloom.opts.bpe = -1 * math.Log(bloom.opts.errorRate) / math.Ln2 + bloom.opts.hashFns = make([]hash.Hash64, len(bloom.opts.hashFnsSeeds)) + for i := 0; i < len(bloom.opts.hashFnsSeeds); i++ { + bloom.opts.hashFns[i] = murmur3.SeedNew64(bloom.opts.hashFnsSeeds[i]) + } + + return bloom, nil +} diff --git a/internal/eval/type_string.go b/internal/eval/type_string.go index a031509a6..8ab3f9938 100644 --- a/internal/eval/type_string.go +++ b/internal/eval/type_string.go @@ -7,61 +7,44 @@ import ( "github.com/dicedb/dice/internal/object" ) -// Similar to -// tryObjectEncoding function in Redis -func deduceTypeEncoding(v string) (o, e uint8) { - // Check if the value has leading zero - if len(v) > 1 && v[0] == '0' { - // If so, treat as string - return object.ObjTypeString, object.ObjEncodingRaw - } - if _, err := strconv.ParseInt(v, 10, 64); err == nil { - return object.ObjTypeInt, object.ObjEncodingInt - } - if len(v) <= 44 { - return object.ObjTypeString, object.ObjEncodingEmbStr +type String struct { + value string +} + +func NewString(value string) *String { + return &String{ + value: value, } - return object.ObjTypeString, object.ObjEncodingRaw } -// Function to handle converting the value based on the encoding type -func storeValueWithEncoding(value string, oEnc uint8) (interface{}, error) { - var returnValue interface{} +func (s *String) Serialize() []byte { + return []byte{} +} - // treat as string if value has leading zero - if len(value) > 1 && value[0] == '0' { +func getRawStringOrInt(v string) (interface{}, object.ObjectType) { + if len(v) > 1 && v[0] == '0' { // If so, treat as string - return value, nil + return v, object.ObjTypeString } - - switch oEnc { - case object.ObjEncodingInt: - intValue, err := strconv.ParseInt(value, 10, 64) - if err != nil { - return nil, diceerrors.ErrWrongTypeOperation - } - returnValue = intValue - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: - returnValue = value - default: - return nil, diceerrors.ErrWrongTypeOperation + intValue, err := strconv.ParseInt(v, 10, 64) + if err != nil { // value is not an integer, hence a string + return v, object.ObjTypeString } - - return returnValue, nil + return intValue, object.ObjTypeInt // value is an integer } // Function to convert the value to a string for concatenation or manipulation -func convertValueToString(obj *object.Obj, oEnc uint8) (string, error) { +func convertValueToString(obj *object.Obj, oType object.ObjectType) (string, error) { var currentValueStr string - switch oEnc { - case object.ObjEncodingInt: + switch oType { + case object.ObjTypeInt: // Convert int64 to string for concatenation currentValueStr = strconv.FormatInt(obj.Value.(int64), 10) - case object.ObjEncodingEmbStr, object.ObjEncodingRaw: + case object.ObjTypeString: // Use the string value directly currentValueStr = obj.Value.(string) - case object.ObjEncodingByteArray: + case object.ObjTypeByteArray: val, ok := obj.Value.(*ByteArray) if !ok { return "", diceerrors.ErrWrongTypeOperation diff --git a/internal/eval/type_string_test.go b/internal/eval/type_string_test.go index 9ba597b46..57230ff89 100644 --- a/internal/eval/type_string_test.go +++ b/internal/eval/type_string_test.go @@ -1,57 +1,53 @@ package eval import ( - "github.com/dicedb/dice/internal/object" "testing" + "github.com/dicedb/dice/internal/object" + "github.com/dicedb/dice/internal/server/utils" ) -// TestDeduceTypeEncoding tests the deduceTypeEncoding function using table-driven tests. -func TestDeduceTypeEncoding(t *testing.T) { +// TestDeduceType tests the deduceType function using table-driven tests. +func TestDeduceType(t *testing.T) { tests := []struct { name string input string - wantType uint8 + wantType object.ObjectType wantEnc uint8 }{ { name: "Integer string", input: "123", wantType: object.ObjTypeInt, - wantEnc: object.ObjEncodingInt, }, { name: "Short string", input: "short string", wantType: object.ObjTypeString, - wantEnc: object.ObjEncodingEmbStr, }, { name: "Long string", input: "this is a very long string that exceeds the maximum length for EMBSTR encoding", wantType: object.ObjTypeString, - wantEnc: object.ObjEncodingRaw, }, { name: "Empty string", input: utils.EmptyStr, wantType: object.ObjTypeString, - wantEnc: object.ObjEncodingEmbStr, }, { name: "Boundary length string", input: "this string is exactly forty-four characters long", wantType: object.ObjTypeString, - wantEnc: object.ObjEncodingRaw, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotType, gotEnc := deduceTypeEncoding(tt.input) - if gotType != tt.wantType || gotEnc != tt.wantEnc { - t.Errorf("deduceTypeEncoding(%q) = (%v, %v), want (%v, %v)", tt.input, gotType, gotEnc, tt.wantType, tt.wantEnc) + _, gotType := getRawStringOrInt(tt.input) + if gotType != tt.wantType { + t.Errorf("deduceType(%q) = (%v), want (%v)", tt.input, gotType, tt.wantType) } }) } diff --git a/internal/object/deep_copy.go b/internal/object/deep_copy.go index bbff08bd8..0e211be9f 100644 --- a/internal/object/deep_copy.go +++ b/internal/object/deep_copy.go @@ -10,7 +10,7 @@ type DeepCopyable interface { func (obj *Obj) DeepCopy() *Obj { newObj := &Obj{ - TypeEncoding: obj.TypeEncoding, + Type: obj.Type, LastAccessedAt: obj.LastAccessedAt, } @@ -19,7 +19,7 @@ func (obj *Obj) DeepCopy() *Obj { newObj.Value = copier.DeepCopy() } else { // Handle types that are not DeepCopyable - sourceType, _ := ExtractTypeEncoding(obj) + sourceType := obj.Type switch sourceType { case ObjTypeString: sourceValue := obj.Value.(string) diff --git a/internal/object/object.go b/internal/object/object.go index 797a0f518..24c8527a5 100644 --- a/internal/object/object.go +++ b/internal/object/object.go @@ -8,7 +8,7 @@ package object // // Fields: // -// - TypeEncoding: A uint8 field used to store the encoding type of the object. This +// - Type: A uint8 field used to store the type of the object. This // helps in identifying how the object is encoded or serialized (e.g., as a string, // number, or more complex type). It is crucial for determining how the object should // be interpreted or processed when retrieved from storage. @@ -18,14 +18,14 @@ package object // freshness of the object and can be used for cache expiry or eviction policies. // in DiceDB we use 32 bits due to Go's lack of native support for bitfields, // and to simplify management by not combining -// `TypeEncoding` and `LastAccessedAt` into a single integer. +// `Type` and `LastAccessedAt` into a single integer. // // - Value: An `interface{}` type that holds the actual data of the object. This could // represent any type of data, allowing flexibility to store different kinds of // objects (e.g., strings, numbers, complex data structures like lists or maps). type Obj struct { - // TypeEncoding holds the encoding type of the object (e.g., string, int, complex structure) - TypeEncoding uint8 + // Type holds the type of the object (e.g., string, int, complex structure) + Type ObjectType // LastAccessedAt stores the last access timestamp of the object. // It helps track when the object was last accessed and may be used for cache eviction or freshness tracking. @@ -72,39 +72,21 @@ type InternalObj struct { ExDuration int64 } -var ObjTypeString uint8 = 0 << 4 - -var ObjEncodingRaw uint8 = 0 -var ObjEncodingInt uint8 = 1 -var ObjEncodingEmbStr uint8 = 8 - -var ObjTypeByteList uint8 = 1 << 4 -var ObjEncodingDeque uint8 = 4 - -var ObjTypeBitSet uint8 = 2 << 4 // 00100000 -var ObjEncodingBF uint8 = 2 // 00000010 - -var ObjTypeJSON uint8 = 3 << 4 // 00110000 -var ObjEncodingJSON uint8 = 0 - -var ObjTypeByteArray uint8 = 4 << 4 // 01000000 -var ObjEncodingByteArray uint8 = 4 - -var ObjTypeInt uint8 = 5 << 4 // 01010000 - -var ObjTypeSet uint8 = 6 << 4 // 01010000 -var ObjEncodingSetInt uint8 = 11 -var ObjEncodingSetStr uint8 = 12 - -var ObjEncodingHashMap uint8 = 6 -var ObjTypeHashMap uint8 = 7 << 4 - -var ObjTypeSortedSet uint8 = 8 << 4 -var ObjEncodingBTree uint8 = 8 - -var ObjTypeCountMinSketch uint8 = 9 << 4 -var ObjEncodingMatrix uint8 = 9 - -func ExtractTypeEncoding(obj *Obj) (e1, e2 uint8) { - return obj.TypeEncoding & 0b11110000, obj.TypeEncoding & 0b00001111 -} +// ObjectType represents the type of a DiceDB object +type ObjectType uint8 + +// Define object types as constants +const ( + ObjTypeString ObjectType = iota + _ // skip 1 and 2 to maintain compatibility + _ + ObjTypeJSON + ObjTypeByteArray + ObjTypeInt + ObjTypeSet + ObjTypeHashMap + ObjTypeSortedSet + ObjTypeCountMinSketch + ObjTypeBF + ObjTypeDequeue +) diff --git a/internal/object/typeencoding.go b/internal/object/typeencoding.go index 619aa8d6d..8934fe710 100644 --- a/internal/object/typeencoding.go +++ b/internal/object/typeencoding.go @@ -6,33 +6,15 @@ import ( diceerrors "github.com/dicedb/dice/internal/errors" ) -func GetType(te uint8) uint8 { - return (te >> 4) << 4 -} - -func GetEncoding(te uint8) uint8 { - return te & 0b00001111 -} - -func AssertType(te, t uint8) error { - if GetType(te) != t { +func AssertTypeWithError(te, t ObjectType) error { + if te != t { return errors.New("WRONGTYPE Operation against a key holding the wrong kind of value") } return nil } -func AssertEncoding(te, e uint8) error { - if GetEncoding(te) != e { - return errors.New("the operation is not permitted on this encoding") - } - return nil -} - -func AssertTypeAndEncoding(typeEncoding, expectedType, expectedEncoding uint8) []byte { - if err := AssertType(typeEncoding, expectedType); err != nil { - return diceerrors.NewErrWithMessage(diceerrors.WrongKeyTypeErr) - } - if err := AssertEncoding(typeEncoding, expectedEncoding); err != nil { +func AssertType(_type, expectedType ObjectType) []byte { + if err := AssertTypeWithError(_type, expectedType); err != nil { return diceerrors.NewErrWithMessage(diceerrors.WrongKeyTypeErr) } return nil diff --git a/internal/sql/executerbechmark_test.go b/internal/sql/executerbechmark_test.go index 082087212..61b4b00c5 100644 --- a/internal/sql/executerbechmark_test.go +++ b/internal/sql/executerbechmark_test.go @@ -29,7 +29,7 @@ func generateBenchmarkData(count int, store *dstore.Store) { for i := 0; i < count; i++ { key := fmt.Sprintf("k%d", i) value := fmt.Sprintf("v%d", i) - data[key] = store.NewObj(value, -1, object.ObjTypeString, object.ObjEncodingRaw) + data[key] = store.NewObj(value, -1, object.ObjTypeString) } store.PutAll(data) } @@ -302,7 +302,7 @@ func generateBenchmarkJSONData(b *testing.B, count int, json string, store *dsto b.Fatalf("Failed to unmarshal JSON: %v", err) } - data[key] = store.NewObj(jsonValue, -1, object.ObjTypeJSON, object.ObjEncodingJSON) + data[key] = store.NewObj(jsonValue, -1, object.ObjTypeJSON) } store.PutAll(data) } diff --git a/internal/sql/executor.go b/internal/sql/executor.go index 9b8e51957..c85758d27 100644 --- a/internal/sql/executor.go +++ b/internal/sql/executor.go @@ -117,7 +117,7 @@ func ExecuteQuery(query *DSQLQuery, store common.ITable[string, *object.Obj]) ([ func MarshalResultIfJSON(row *QueryResultRow) error { // if the row contains JSON field then convert the json object into string representation so it can be encoded // before being returned to the client - if object.GetEncoding(row.Value.TypeEncoding) == object.ObjEncodingJSON && object.GetType(row.Value.TypeEncoding) == object.ObjTypeJSON { + if row.Value.Type == object.ObjTypeJSON { marshaledData, err := sonic.MarshalString(row.Value.Value) if err != nil { return err @@ -333,11 +333,7 @@ func getExprValueAndType(expr sqlparser.Expr, row QueryResultRow, jsonPathCache } func isJSONField(expr *sqlparser.SQLVal, obj *object.Obj) bool { - if err := object.AssertEncoding(obj.TypeEncoding, object.ObjEncodingJSON); err != nil { - return false - } - - if err := object.AssertType(obj.TypeEncoding, object.ObjTypeJSON); err != nil { + if err := object.AssertType(obj.Type, object.ObjTypeJSON); err != nil { return false } diff --git a/internal/sql/executor_test.go b/internal/sql/executor_test.go index 9e1978527..2dd52d798 100644 --- a/internal/sql/executor_test.go +++ b/internal/sql/executor_test.go @@ -279,7 +279,7 @@ func setupJSON(t *testing.T, store *dstore.Store, dataset []keyValue) { t.Fatalf("Failed to unmarshal value: %v", err) } - store.Put(data.key, store.NewObj(jsonValue, -1, object.ObjTypeJSON, object.ObjEncodingJSON)) + store.Put(data.key, store.NewObj(jsonValue, -1, object.ObjTypeJSON)) } } diff --git a/internal/store/store.go b/internal/store/store.go index 0c38aa295..6bb18aecb 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -84,10 +84,10 @@ func ResetStore(store *Store) *Store { return store } -func (store *Store) NewObj(value interface{}, expDurationMs int64, oType, oEnc uint8) *object.Obj { +func (store *Store) NewObj(value interface{}, expDurationMs int64, oType object.ObjectType) *object.Obj { obj := &object.Obj{ Value: value, - TypeEncoding: oType | oEnc, + Type: oType, LastAccessedAt: getCurrentClock(), } if expDurationMs >= 0 {