From ae6a53c5cc6512ae40784e6f93360fb6828d4fbe Mon Sep 17 00:00:00 2001 From: Joseph Brinkman Date: Tue, 18 Feb 2025 18:19:19 -0500 Subject: [PATCH] [Backport 1.3) Merge release 1.3 to main (#3202) Backport 1.3 to main --------- Signed-off-by: Joe Brinkman --- .github/workflows/go-cd.yml | 25 +- .github/workflows/go.yml | 2 +- .github/workflows/install-engine/action.yml | 15 +- .github/workflows/java-cd.yml | 8 +- .github/workflows/java.yml | 2 +- .github/workflows/node.yml | 2 +- .github/workflows/npm-cd.yml | 8 +- .github/workflows/pypi-cd.yml | 10 +- .github/workflows/python.yml | 2 +- .vscode/settings.json | 3 +- CHANGELOG.md | 4 + glide-core/THIRD_PARTY_LICENSES_RUST | 2 +- glide-core/redis-rs/redis/src/aio/mod.rs | 2 +- glide-core/redis-rs/redis/src/client.rs | 2 +- .../cluster_async/connections_container.rs | 192 ++++- .../src/cluster_async/connections_logic.rs | 1 + .../redis-rs/redis/src/cluster_async/mod.rs | 1 + .../redis-rs/redis/src/cluster_client.rs | 2 + .../redis-rs/redis/src/cluster_slotmap.rs | 4 + .../redis/tests/test_cluster_async.rs | 166 ++++- glide-core/src/client/mod.rs | 5 + glide-core/src/client/standalone_client.rs | 72 ++ glide-core/src/client/types.rs | 15 + .../src/protobuf/connection_request.proto | 1 + glide-core/tests/test_standalone_client.rs | 13 + go/.cargo/config.toml | 5 + go/Makefile | 19 +- go/README.md | 13 +- go/THIRD_PARTY_LICENSES_GO | 2 +- go/api/base_client.go | 699 +++++++++++------- go/api/bitmap_commands.go | 2 +- go/api/bitmap_commands_test.go | 8 +- go/api/config/request_routing_config.go | 106 +-- ...ection_management_cluster_commands_test.go | 2 +- go/api/errors/errors.go | 7 - go/api/generic_base_commands.go | 18 +- go/api/generic_base_commands_test.go | 44 +- go/api/glide_client.go | 23 +- go/api/glide_cluster_client.go | 66 +- go/api/hash_commands.go | 2 +- go/api/hash_commands_test.go | 8 +- go/api/list_commands.go | 29 +- go/api/list_commands_test.go | 42 +- go/api/options/base_scan_options.go | 2 +- go/api/options/bitcount_options.go | 2 +- go/api/options/bitfield_options.go | 17 +- go/api/{ => options}/command_options.go | 215 ++---- go/api/options/constants.go | 173 ++++- go/api/options/echo_options.go | 8 +- go/api/options/hscan_options.go | 4 +- go/api/options/ping_options.go | 14 +- go/api/options/sort_options.go | 4 +- go/api/options/stream_options.go | 130 ++-- go/api/options/weight_aggregate_options.go | 14 +- go/api/options/zadd_options.go | 16 +- go/api/options/zcount_options.go | 2 +- go/api/options/zinter_options.go | 8 +- go/api/options/zmpop_options.go | 2 +- go/api/options/zrange_options.go | 40 +- go/api/options/zscan_options.go | 4 +- go/api/options/zunion_options.go | 6 +- .../request_routing_config_test.go | 31 +- go/api/response_handlers.go | 8 - go/api/server_management_cluster_commands.go | 2 +- ...server_management_cluster_commands_test.go | 4 +- go/api/server_management_commands.go | 6 +- go/api/server_management_commands_test.go | 4 +- go/api/set_commands.go | 2 +- go/api/set_commands_test.go | 8 +- go/api/sorted_set_commands.go | 22 +- go/api/sorted_set_commands_test.go | 66 +- go/api/stream_commands.go | 26 +- go/api/stream_commands_test.go | 272 +++---- go/api/string_commands.go | 8 +- go/api/string_commands_test.go | 38 +- go/examples/examples.md | 24 +- go/integTest/cluster_commands_test.go | 31 +- go/integTest/glide_test_suite_test.go | 9 +- go/integTest/json_module_test.go | 7 +- go/integTest/shared_commands_test.go | 584 ++++++++------- go/integTest/standalone_commands_test.go | 12 +- go/integTest/vss_module_test.go | 7 +- java/THIRD_PARTY_LICENSES_JAVA | 2 +- java/benchmarks/build.gradle | 4 +- .../{MultiJson.java => JsonBatch.java} | 12 +- .../BaseClientConfiguration.java | 5 +- .../api/models/configuration/ReadFrom.java | 6 + .../glide/managers/ConnectionManager.java | 10 + .../glide/managers/ConnectionManagerTest.java | 38 +- .../src/test/java/glide/ConnectionTests.java | 86 +++ .../test/java/glide/modules/JsonTests.java | 106 +-- node/THIRD_PARTY_LICENSES_NODE | 3 +- node/npm/glide/index.ts | 2 + node/src/BaseClient.ts | 15 +- node/src/server-modules/GlideJson.ts | 10 +- node/tests/GlideClusterClient.test.ts | 108 +++ node/tests/ServerModules.test.ts | 14 +- node/tests/TestUtilities.ts | 68 +- python/THIRD_PARTY_LICENSES_PYTHON | 2 +- python/python/glide/__init__.py | 4 +- .../{json_transaction.py => json_batch.py} | 6 +- python/python/glide/config.py | 13 + python/python/tests/test_config.py | 15 + .../python/tests/test_read_from_strategy.py | 104 +++ .../tests/tests_server_modules/test_json.py | 64 +- 105 files changed, 2564 insertions(+), 1619 deletions(-) rename go/api/{ => options}/command_options.go (61%) rename go/{integTest => api}/request_routing_config_test.go (62%) rename java/client/src/main/java/glide/api/commands/servermodules/{MultiJson.java => JsonBatch.java} (99%) rename python/python/glide/async_commands/server_modules/{json_transaction.py => json_batch.py} (99%) diff --git a/.github/workflows/go-cd.yml b/.github/workflows/go-cd.yml index 6d060b892a..517163eb95 100644 --- a/.github/workflows/go-cd.yml +++ b/.github/workflows/go-cd.yml @@ -33,13 +33,13 @@ jobs: id: load-platform-matrix shell: bash run: | - # Filter entries with pkg_go_dev in PACKAGE_MANAGERS and remove "ephemeral" from RUNNER + # Filter entries with pkg_go_dev in PACKAGE_MANAGERS and replace "ephemeral" with "persistent" in RUNNER export PLATFORM_MATRIX=$(jq 'map( - select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["pkg_go_dev"]))) + select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["pkg_go_dev"]))) | .RUNNER = ( if (.RUNNER | type == "array") - then (.RUNNER | map(select(. != "ephemeral"))) - else .RUNNER + then (.RUNNER | map(if . == "ephemeral" then "persistent" else . end)) + else (if . == "ephemeral" then "persistent" else . end) end ) )' < .github/json_matrices/build-matrix.json | jq -c .) @@ -148,13 +148,14 @@ jobs: cp protobuf/* $GITHUB_WORKSPACE/go/protobuf/ - name: Commit and push tag run: | + RELEASE_VERSION=${{ needs.validate-release-version.outputs.RELEASE_VERSION }} git config user.name github-actions git config user.email github-actions@github.com git add -f . git commit -m "Automated commit from GitHub Actions" - git tag go/${{ needs.validate-release-version.outputs.RELEASE_VERSION }} - git push origin go/${{ needs.validate-release-version.outputs.RELEASE_VERSION }} - GOPROXY=proxy.golang.org go list -m github.com/valkey-io/valkey-glide/go@${{ needs.validate-release-version.outputs.RELEASE_VERSION }} + git tag go/$RELEASE_VERSION + git push origin go/$RELEASE_VERSION + GOPROXY=proxy.golang.org go list -m github.com/valkey-io/valkey-glide/go@$RELEASE_VERSION extra-post-commit-test: needs: @@ -204,13 +205,13 @@ jobs: working-directory: go/benchmarks run: | # change go/benchmarks/go.mod on the fly - export ESCAPED_VERSION=$(echo "${{ needs.validate-release-version.outputs.RELEASE_VERSION }}" | sed 's/\./\\./g') + RELEASE_VERSION=${{ needs.validate-release-version.outputs.RELEASE_VERSION }} if [[ "${{ matrix.host.OS }}" == "macos" ]]; then - sed -i '' '/replace github\.com\/valkey-io\/valkey-glide\/go/d' go.mod - sed -i '' "s/github\.com\/valkey-io\/valkey-glide\/go v0\.0\.0/github.com\/valkey-io\/valkey-glide\/go $ESCAPED_VERSION/g" go.mod + sed -i '' '\|replace github\.com/valkey-io/valkey-glide/go|d' go.mod + sed -i '' "s|github\.com/valkey-io/valkey-glide/go v.*|github.com/valkey-io/valkey-glide/go $RELEASE_VERSION|g" go.mod else - sed -i '/replace github\.com\/valkey-io\/valkey-glide\/go/d' go.mod - sed -i "s/github\.com\/valkey-io\/valkey-glide\/go v0\.0\.0/github.com\/valkey-io\/valkey-glide\/go $ESCAPED_VERSION/g" go.mod + sed -i '\|replace github\.com/valkey-io/valkey-glide/go|d' go.mod + sed -i "s|github\.com/valkey-io/valkey-glide/go v.*|github.com/valkey-io/valkey-glide/go $RELEASE_VERSION|g" go.mod fi go mod tidy go run . -minimal -clients glide -concurrentTasks 10 -port ${{ env.PORT }} diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1c71bd7cd2..c18b38d86e 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -225,7 +225,7 @@ jobs: if: (github.repository_owner == 'valkey-io' && github.event_name == 'workflow_dispatch') || github.event.pull_request.head.repo.owner.login == 'valkey-io' environment: AWS_ACTIONS name: Modules Tests - runs-on: [self-hosted, linux, ARM64] + runs-on: [self-hosted, linux, ARM64, persistent] timeout-minutes: 15 steps: - name: Setup self-hosted runner access diff --git a/.github/workflows/install-engine/action.yml b/.github/workflows/install-engine/action.yml index e26ae4a863..5d20a34dab 100644 --- a/.github/workflows/install-engine/action.yml +++ b/.github/workflows/install-engine/action.yml @@ -26,7 +26,7 @@ runs: # TODO: self-hosted runners are actually cloning the repo, using the cache from the previous run # will not work as expected. We need to find a way to cache the valkey repo on the runner itself. steps: - - name: Cache Valkey + - name: Cache Valkey for non self hosted runners if: ${{!contains(inputs.target, 'aarch64-unknown') }} uses: actions/cache@v4 id: cache-valkey @@ -35,18 +35,21 @@ runs: ~/valkey key: valkey-${{ inputs.engine-version }}-${{ inputs.target }} - # if no cache hit, build the engine - - name: Build Valkey + - name: Prepare Valkey sources if: ${{ steps.cache-valkey.outputs.cache-hit != 'true' }} shell: bash run: | - echo "Building valkey ${{ inputs.engine-version }}" - cd ~ + echo "Cloning and checking out Valkey ${{ inputs.engine-version }}" + cd ~/ + if [[ -d valkey ]]; then + echo "Removing existing valkey directory..." + rm -fR valkey + fi git clone https://github.com/valkey-io/valkey.git cd valkey git checkout ${{ inputs.engine-version }} - - name: Install engine + - name: Build and install engine shell: bash run: | cd ~/valkey diff --git a/.github/workflows/java-cd.yml b/.github/workflows/java-cd.yml index 5c6e98a156..8e67197890 100644 --- a/.github/workflows/java-cd.yml +++ b/.github/workflows/java-cd.yml @@ -35,13 +35,13 @@ jobs: id: load-platform-matrix shell: bash run: | - # Filter entries with maven in PACKAGE_MANAGERS and remove "ephemeral" from RUNNER + # Filter entries with maven in PACKAGE_MANAGERS and replace "ephemeral" with "persistent" in RUNNER export PLATFORM_MATRIX=$(jq 'map( - select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["maven"]))) + select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["maven"]))) | .RUNNER = ( if (.RUNNER | type == "array") - then (.RUNNER | map(select(. != "ephemeral"))) - else .RUNNER + then (.RUNNER | map(if . == "ephemeral" then "persistent" else . end)) + else (if . == "ephemeral" then "persistent" else . end) end ) )' < .github/json_matrices/build-matrix.json | jq -c .) diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index c837b22dc6..3f2541dea7 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -218,7 +218,7 @@ jobs: if: (github.repository_owner == 'valkey-io' && github.event_name == 'workflow_dispatch') || github.event.pull_request.head.repo.owner.login == 'valkey-io' environment: AWS_ACTIONS name: Modules Tests - runs-on: [self-hosted, linux, ARM64] + runs-on: [self-hosted, linux, ARM64, persistent] timeout-minutes: 15 steps: - name: Setup self-hosted runner access diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 7c12878b38..b64484afaf 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -246,7 +246,7 @@ jobs: if: (github.repository_owner == 'valkey-io' && github.event_name == 'workflow_dispatch') || github.event.pull_request.head.repo.owner.login == 'valkey-io' environment: AWS_ACTIONS name: Running Module Tests - runs-on: [self-hosted, linux, ARM64] + runs-on: [self-hosted, linux, ARM64, persistent] timeout-minutes: 15 steps: diff --git a/.github/workflows/npm-cd.yml b/.github/workflows/npm-cd.yml index f08f5b27ba..ea76aa0e8f 100644 --- a/.github/workflows/npm-cd.yml +++ b/.github/workflows/npm-cd.yml @@ -59,13 +59,13 @@ jobs: id: load-platform-matrix shell: bash run: | - # Filter entries with npm in PACKAGE_MANAGERS and remove "ephemeral" from RUNNER + # Filter entries with npm in PACKAGE_MANAGERS and replace "ephemeral" with "persistent" in RUNNER export PLATFORM_MATRIX=$(jq 'map( - select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["npm"]))) + select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["npm"]))) | .RUNNER = ( if (.RUNNER | type == "array") - then (.RUNNER | map(select(. != "ephemeral"))) - else .RUNNER + then (.RUNNER | map(if . == "ephemeral" then "persistent" else . end)) + else (if . == "ephemeral" then "persistent" else . end) end ) )' < .github/json_matrices/build-matrix.json | jq -c .) diff --git a/.github/workflows/pypi-cd.yml b/.github/workflows/pypi-cd.yml index 8caf9d03e2..e3a2f511d4 100644 --- a/.github/workflows/pypi-cd.yml +++ b/.github/workflows/pypi-cd.yml @@ -41,13 +41,13 @@ jobs: id: load-platform-matrix shell: bash run: | - # Filter entries with pypi in PACKAGE_MANAGERS and remove "ephemeral" from RUNNER + # Filter entries with pypi in PACKAGE_MANAGERS and replace "ephemeral" with "persistent" in RUNNER export PLATFORM_MATRIX=$(jq 'map( - select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["pypi"]))) + select(.PACKAGE_MANAGERS != null and (.PACKAGE_MANAGERS | contains(["pypi"]))) | .RUNNER = ( if (.RUNNER | type == "array") - then (.RUNNER | map(select(. != "ephemeral"))) - else .RUNNER + then (.RUNNER | map(if . == "ephemeral" then "persistent" else . end)) + else (if . == "ephemeral" then "persistent" else . end) end ) )' < .github/json_matrices/build-matrix.json | jq -c .) @@ -171,7 +171,7 @@ jobs: PROTOC_ARCH="x86_64" elif [[ $ARCH == 'aarch64' ]]; then PROTOC_ARCH="aarch_64" - export CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc + export CC_aarch64_unknown_linux_gnu=gcc export CFLAGS_aarch64_unknown_linux_gnu="-march=armv8-a" else echo "Running on unsupported architecture: $ARCH. Expected one of: ['x86_64', 'aarch64']" diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 699033cf1a..0b31a965c8 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -303,7 +303,7 @@ jobs: if: (github.repository_owner == 'valkey-io' && github.event_name == 'workflow_dispatch') || github.event.pull_request.head.repo.owner.login == 'valkey-io' environment: AWS_ACTIONS name: Running Module Tests - runs-on: [self-hosted, linux, ARM64] + runs-on: [self-hosted, linux, ARM64, persistent] timeout-minutes: 15 steps: diff --git a/.vscode/settings.json b/.vscode/settings.json index ed2280da4f..6f9a80be04 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -60,5 +60,6 @@ ], "rust-analyzer.cargo.features": "all", "dotnet.defaultSolution": "csharp/csharp.sln", - "java.compile.nullAnalysis.mode": "automatic" + "java.compile.nullAnalysis.mode": "automatic", + "java.configuration.updateBuildConfiguration": "interactive" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b78ff0d60f..052c78bf7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ #### Changes +* Java: Add support to AzAffinityReplicasAndPrimary read strategy ([#3083](https://github.com/valkey-io/valkey-glide/pull/3083)) +* Python: Add support to AzAffinityReplicasAndPrimary read strategy ([#3071](https://github.com/valkey-io/valkey-glide/pull/3071)) +* Node: Add support to AzAffinityReplicasAndPrimary read strategy ([#3063](https://github.com/valkey-io/valkey-glide/pull/3063)) +* Core: Add support to AzAffinityReplicasAndPrimary read strategy ([#2986](https://github.com/valkey-io/valkey-glide/pull/2986)) * Java, Node, Python: Add transaction commands for JSON module ([#2862](https://github.com/valkey-io/valkey-glide/pull/2862)) * Java: bump `netty` version ([#2795](https://github.com/valkey-io/valkey-glide/pull/2795)) * Java: Bump protobuf (protoc) version ([#2796](https://github.com/valkey-io/valkey-glide/pull/2796), [#2800](https://github.com/valkey-io/valkey-glide/pull/2800)) diff --git a/glide-core/THIRD_PARTY_LICENSES_RUST b/glide-core/THIRD_PARTY_LICENSES_RUST index 7f264f7f17..1c7a0f3d5d 100644 --- a/glide-core/THIRD_PARTY_LICENSES_RUST +++ b/glide-core/THIRD_PARTY_LICENSES_RUST @@ -24332,7 +24332,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- -Package: smallvec:1.13.2 +Package: smallvec:1.14.0 The following copyrights and licenses were found in the source code of this package: diff --git a/glide-core/redis-rs/redis/src/aio/mod.rs b/glide-core/redis-rs/redis/src/aio/mod.rs index 077046feba..17ec7b58b0 100644 --- a/glide-core/redis-rs/redis/src/aio/mod.rs +++ b/glide-core/redis-rs/redis/src/aio/mod.rs @@ -146,7 +146,7 @@ where async fn setup_connection( connection_info: &RedisConnectionInfo, con: &mut C, - // This parameter is set to 'true' if ReadFromReplica strategy is set to AZAffinity. + // This parameter is set to 'true' if ReadFromReplica strategy is set to AZAffinity or AZAffinityReplicasAndPrimary. // An INFO command will be triggered in the connection's setup to update the 'availability_zone' property. discover_az: bool, ) -> RedisResult<()> diff --git a/glide-core/redis-rs/redis/src/client.rs b/glide-core/redis-rs/redis/src/client.rs index 2b97671110..06764cd0f7 100644 --- a/glide-core/redis-rs/redis/src/client.rs +++ b/glide-core/redis-rs/redis/src/client.rs @@ -86,7 +86,7 @@ pub struct GlideConnectionOptions { #[cfg(feature = "aio")] /// Passive disconnect notifier pub disconnect_notifier: Option>, - /// If ReadFromReplica strategy is set to AZAffinity, this parameter will be set to 'true'. + /// If ReadFromReplica strategy is set to AZAffinity or AZAffinityReplicasAndPrimary, this parameter will be set to 'true'. /// In this case, an INFO command will be triggered in the connection's setup to update the connection's 'availability_zone' property. pub discover_az: bool, /// Connection timeout duration. diff --git a/glide-core/redis-rs/redis/src/cluster_async/connections_container.rs b/glide-core/redis-rs/redis/src/cluster_async/connections_container.rs index 91e0e7e3b2..437b2dba97 100644 --- a/glide-core/redis-rs/redis/src/cluster_async/connections_container.rs +++ b/glide-core/redis-rs/redis/src/cluster_async/connections_container.rs @@ -412,17 +412,36 @@ where &self, slot_map_value: &SlotMapValue, client_az: String, + ) -> Option> { + self.get_connection_by_az_affinity_strategy(slot_map_value, client_az, false) + } + + /// Returns the node's connection in the same availability zone as `client_az`, + /// checking replicas first, then primary, and falling back to any available node. + pub(crate) fn round_robin_read_from_replica_with_az_awareness_replicas_and_primary( + &self, + slot_map_value: &SlotMapValue, + client_az: String, + ) -> Option> { + self.get_connection_by_az_affinity_strategy(slot_map_value, client_az, true) + } + + fn get_connection_by_az_affinity_strategy( + &self, + slot_map_value: &SlotMapValue, + client_az: String, + check_primary: bool, // Strategy flag ) -> Option> { let addrs = &slot_map_value.addrs; let initial_index = slot_map_value.last_used_replica.load(Ordering::Relaxed); let mut retries = 0usize; + // Step 1: Try to find a replica in the same AZ loop { retries = retries.saturating_add(1); // Looped through all replicas; no connected replica found in the same availability zone. if retries > addrs.replicas().len() { - // Attempt a fallback to any available replica or primary if needed. - return self.round_robin_read_from_replica(slot_map_value); + break; } // Calculate index based on initial index and check count. @@ -445,6 +464,20 @@ where } } } + + // Step 2: Check if primary is in the same AZ + if check_primary { + if let Some((address, connection_details)) = + self.connection_details_for_address(addrs.primary().as_str()) + { + if self.az_for_address(&address) == Some(client_az) { + return Some((address, connection_details.conn)); + } + } + } + + // Step 3: Fall back to any available replica using round-robin or primary if needed + self.round_robin_read_from_replica(slot_map_value) } fn lookup_route(&self, route: &Route) -> Option> { @@ -470,6 +503,11 @@ where slot_map_value, az.to_string(), ), + ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(az) => self + .round_robin_read_from_replica_with_az_awareness_replicas_and_primary( + slot_map_value, + az.to_string(), + ), }, // when the user strategy per command is replica_preffered SlotAddr::ReplicaRequired => match &self.read_from_replica_strategy { @@ -478,6 +516,11 @@ where slot_map_value, az.to_string(), ), + ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(az) => self + .round_robin_read_from_replica_with_az_awareness_replicas_and_primary( + slot_map_value, + az.to_string(), + ), _ => self.round_robin_read_from_replica(slot_map_value), }, } @@ -714,6 +757,7 @@ mod tests { fn create_container_with_az_strategy( use_management_connections: bool, + strategy: Option, ) -> ConnectionsContainer { let slot_map = SlotMap::new( vec![ @@ -766,15 +810,12 @@ mod tests { "replica3-3".into(), create_cluster_node(33, use_management_connections, Some("use-1a".to_string())), ); - connection_map.insert( - "replica3-3".into(), - create_cluster_node(33, use_management_connections, Some("use-1a".to_string())), - ); ConnectionsContainer { slot_map, connection_map, - read_from_replica_strategy: ReadFromReplicaStrategy::AZAffinity("use-1a".to_string()), + read_from_replica_strategy: strategy + .unwrap_or(ReadFromReplicaStrategy::AZAffinity("use-1a".to_string())), topology_hash: 0, refresh_conn_state: Default::default(), } @@ -1007,7 +1048,10 @@ mod tests { #[test] fn get_connection_for_az_affinity_route() { - let container = create_container_with_az_strategy(false); + let container = create_container_with_az_strategy( + false, + Some(ReadFromReplicaStrategy::AZAffinity("use-1a".to_string())), + ); // slot number is not exits assert!(container @@ -1070,7 +1114,10 @@ mod tests { #[test] fn get_connection_for_az_affinity_route_round_robin() { - let container = create_container_with_az_strategy(false); + let container = create_container_with_az_strategy( + false, + Some(ReadFromReplicaStrategy::AZAffinity("use-1a".to_string())), + ); let mut addresses = vec![ container @@ -1094,6 +1141,133 @@ mod tests { assert_eq!(addresses, vec![31, 31, 33, 33]); } + #[test] + fn get_connection_for_az_affinity_replicas_and_primary_route() { + // Create a container with AZAffinityReplicasAndPrimary strategy + let container: ConnectionsContainer = create_container_with_az_strategy( + false, + Some(ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary( + "use-1a".to_string(), + )), + ); + // Modify the AZ of primary1 + container + .connection_map + .get_mut("primary1") + .unwrap() + .user_connection + .az = Some("use-1b".to_string()); + + // Modify the AZ of primary2 + container + .connection_map + .get_mut("primary2") + .unwrap() + .user_connection + .az = Some("use-1c".to_string()); + + // Modify the AZ of primary3 + container + .connection_map + .get_mut("primary3") + .unwrap() + .user_connection + .az = Some("use-1b".to_string()); + + // Modify the AZ of replica2-1 + container + .connection_map + .get_mut("replica2-1") + .unwrap() + .user_connection + .az = Some("use-1c".to_string()); + + // Slot number does not exist (slot 1001 wasn't assigned to any primary) + assert!(container + .connection_for_route(&Route::new(1001, SlotAddr::ReplicaOptional)) + .is_none()); + + // Test getting replica in client's AZ for slot 2001 + assert!(one_of( + container.connection_for_route(&Route::new(2001, SlotAddr::ReplicaRequired)), + &[31, 33], + )); + + // Remove one replica in the client's AZ + remove_nodes(&container, &["replica3-3"]); + + // Should still get the remaining replica in the client's AZ + assert_eq!( + 31, + container + .connection_for_route(&Route::new(2001, SlotAddr::ReplicaRequired)) + .unwrap() + .1 + ); + + // Remove all replicas in the client's AZ + remove_nodes(&container, &["replica3-1"]); + + // Test falling back to replica in different AZ + assert_eq!( + 32, + container + .connection_for_route(&Route::new(2001, SlotAddr::ReplicaRequired)) + .unwrap() + .1 + ); + + // Set the primary to be in the client's AZ + container + .connection_map + .get_mut("primary3") + .unwrap() + .user_connection + .az = Some("use-1a".to_string()); + + // Remove the last replica + remove_nodes(&container, &["replica3-2"]); + + // Should now fall back to the primary in the client's AZ + assert_eq!( + 3, + container + .connection_for_route(&Route::new(2001, SlotAddr::Master)) + .unwrap() + .1 + ); + + // Move the primary out of the client's AZ + container + .connection_map + .get_mut("primary3") + .unwrap() + .user_connection + .az = Some("use-1b".to_string()); + + // Test falling back to replica under different primary + assert_eq!( + 21, + container + .connection_for_route(&Route::new(1002, SlotAddr::ReplicaRequired)) + .unwrap() + .1 + ); + + // Remove all replicas + remove_nodes(&container, &["replica2-1"]); + + // Test falling back to available primaries with their respective slots + assert!(one_of( + container.connection_for_route(&Route::new(1002, SlotAddr::Master)), + &[2], + )); + assert!(one_of( + container.connection_for_route(&Route::new(500, SlotAddr::Master)), + &[1], + )); + } + #[test] fn get_connection_by_address() { let container = create_container(); diff --git a/glide-core/redis-rs/redis/src/cluster_async/connections_logic.rs b/glide-core/redis-rs/redis/src/cluster_async/connections_logic.rs index e5af8d1e50..9fbd699bc1 100644 --- a/glide-core/redis-rs/redis/src/cluster_async/connections_logic.rs +++ b/glide-core/redis-rs/redis/src/cluster_async/connections_logic.rs @@ -182,6 +182,7 @@ where let discover_az = matches!( params.read_from_replicas, crate::cluster_slotmap::ReadFromReplicaStrategy::AZAffinity(_) + | crate::cluster_slotmap::ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(_) ); match create_connection::( diff --git a/glide-core/redis-rs/redis/src/cluster_async/mod.rs b/glide-core/redis-rs/redis/src/cluster_async/mod.rs index 14388cde63..e66be0efb8 100644 --- a/glide-core/redis-rs/redis/src/cluster_async/mod.rs +++ b/glide-core/redis-rs/redis/src/cluster_async/mod.rs @@ -1089,6 +1089,7 @@ where let discover_az = matches!( cluster_params.read_from_replicas, crate::cluster_slotmap::ReadFromReplicaStrategy::AZAffinity(_) + | crate::cluster_slotmap::ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(_) ); let glide_connection_options = GlideConnectionOptions { diff --git a/glide-core/redis-rs/redis/src/cluster_client.rs b/glide-core/redis-rs/redis/src/cluster_client.rs index fdac644ec7..40dee46733 100644 --- a/glide-core/redis-rs/redis/src/cluster_client.rs +++ b/glide-core/redis-rs/redis/src/cluster_client.rs @@ -394,6 +394,8 @@ impl ClusterClientBuilder { /// The parameter `read_strategy` can be one of: /// `ReadFromReplicaStrategy::AZAffinity(availability_zone)` - attempt to access replicas in the same availability zone. /// If no suitable replica is found (i.e. no replica could be found in the requested availability zone), choose any replica. Falling back to primary if needed. + /// `ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(availability_zone)` - attempt to access nodes in the same availability zone. + /// prioritizing local replicas, then the local primary, and falling back to any replica or the primary if needed. /// `ReadFromReplicaStrategy::RoundRobin` - reads are distributed across replicas for load balancing using round-robin algorithm. Falling back to primary if needed. /// `ReadFromReplicaStrategy::AlwaysFromPrimary` ensures all read and write queries are directed to the primary node. /// diff --git a/glide-core/redis-rs/redis/src/cluster_slotmap.rs b/glide-core/redis-rs/redis/src/cluster_slotmap.rs index f2e43b4449..f519995f50 100644 --- a/glide-core/redis-rs/redis/src/cluster_slotmap.rs +++ b/glide-core/redis-rs/redis/src/cluster_slotmap.rs @@ -32,6 +32,9 @@ pub enum ReadFromReplicaStrategy { /// Spread the read requests between replicas in the same client's Aviliablity zone in a round robin manner, /// falling back to other replicas or the primary if needed. AZAffinity(String), + /// Spread the read requests among nodes within the client's Availability Zone (AZ) in a round robin manner, + /// prioritizing local replicas, then the local primary, and falling back to any replica or the primary if needed. + AZAffinityReplicasAndPrimary(String), } #[derive(Debug, Default)] @@ -60,6 +63,7 @@ fn get_address_from_slot( addrs.replicas()[index].clone() } ReadFromReplicaStrategy::AZAffinity(_az) => todo!(), // Drop sync client + ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(_az) => todo!(), // Drop sync client } } diff --git a/glide-core/redis-rs/redis/tests/test_cluster_async.rs b/glide-core/redis-rs/redis/tests/test_cluster_async.rs index 72293e7898..4b924c7782 100644 --- a/glide-core/redis-rs/redis/tests/test_cluster_async.rs +++ b/glide-core/redis-rs/redis/tests/test_cluster_async.rs @@ -284,6 +284,20 @@ mod cluster_async { #[tokio::test] async fn test_routing_by_slot_to_replica_with_az_affinity_strategy_to_half_replicas() { + test_az_affinity_helper(StrategyVariant::AZAffinity).await; + } + + #[tokio::test] + async fn test_routing_by_slot_to_replica_with_az_affinity_replicas_and_primary_strategy_to_half_replicas( + ) { + test_az_affinity_helper(StrategyVariant::AZAffinityReplicasAndPrimary).await; + } + enum StrategyVariant { + AZAffinity, + AZAffinityReplicasAndPrimary, + } + + async fn test_az_affinity_helper(strategy_variant: StrategyVariant) { // Skip test if version is less then Valkey 8.0 if crate::engine_version_less_than("8.0").await { return; @@ -319,11 +333,18 @@ mod cluster_async { .await .unwrap(); } - + let strategy = match strategy_variant { + StrategyVariant::AZAffinity => { + redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinity(az.clone()) + } + StrategyVariant::AZAffinityReplicasAndPrimary => { + redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary( + az.clone(), + ) + } + }; let mut client = ClusterClient::builder(cluster_addresses.clone()) - .read_from(redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinity( - az.clone(), - )) + .read_from(strategy) .build() .unwrap() .get_async_connection(None) @@ -379,7 +400,16 @@ mod cluster_async { } #[tokio::test] - async fn test_routing_by_slot_to_replica_with_az_affinity_strategy_to_all_replicas() { + async fn test_az_affinity_strategy_to_all_replicas() { + test_all_replicas_helper(StrategyVariant::AZAffinity).await; + } + + #[tokio::test] + async fn test_az_affinity_replicas_and_primary_to_all_replicas() { + test_all_replicas_helper(StrategyVariant::AZAffinityReplicasAndPrimary).await; + } + + async fn test_all_replicas_helper(strategy_variant: StrategyVariant) { // Skip test if version is less then Valkey 8.0 if crate::engine_version_less_than("8.0").await { return; @@ -410,10 +440,19 @@ mod cluster_async { .await .unwrap(); + // Strategy-specific client configuration + let strategy = match strategy_variant { + StrategyVariant::AZAffinity => { + redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinity(az.clone()) + } + StrategyVariant::AZAffinityReplicasAndPrimary => { + redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary( + az.clone(), + ) + } + }; let mut client = ClusterClient::builder(cluster_addresses.clone()) - .read_from(redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinity( - az.clone(), - )) + .read_from(strategy) .build() .unwrap() .get_async_connection(None) @@ -468,6 +507,117 @@ mod cluster_async { ); } + #[tokio::test] + async fn test_az_affinity_replicas_and_primary_prefers_local_primary() { + // Skip test if version is less than Valkey 8.0 + if crate::engine_version_less_than("8.0").await { + return; + } + + let replica_num: u16 = 4; + let primaries_num: u16 = 3; + let primary_in_same_az: u16 = 1; + + let cluster = + TestClusterContext::new((replica_num * primaries_num) + primaries_num, replica_num); + let client_az = "us-east-1a".to_string(); + let other_az = "us-east-1b".to_string(); + + let mut connection = cluster.async_connection(None).await; + let cluster_addresses: Vec<_> = cluster + .cluster + .servers + .iter() + .map(|server| server.connection_info()) + .collect(); + + // Set AZ for all nodes to a different AZ initially + let mut cmd = redis::cmd("CONFIG"); + cmd.arg(&["SET", "availability-zone", &other_az.clone()]); + + connection + .route_command( + &cmd, + RoutingInfo::MultiNode((MultipleNodeRoutingInfo::AllNodes, None)), + ) + .await + .unwrap(); + + // Set the client's AZ for one primary (the last one) + let mut cmd = redis::cmd("CONFIG"); + cmd.arg(&["SET", "availability-zone", &client_az]); + connection + .route_command( + &cmd, + RoutingInfo::SingleNode(SingleNodeRoutingInfo::SpecificNode(Route::new( + 12182, // This should target the third primary + SlotAddr::Master, + ))), + ) + .await + .unwrap(); + + let mut client = ClusterClient::builder(cluster_addresses.clone()) + .read_from( + redis::cluster_slotmap::ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary( + client_az.clone(), + ), + ) + .build() + .unwrap() + .get_async_connection(None) + .await + .unwrap(); + + // Perform read operations + let n = 100; + for _ in 0..n { + let mut cmd = redis::cmd("GET"); + cmd.arg("foo"); // This key should hash to the third primary's slot + let _res: RedisResult = cmd.query_async(&mut client).await; + } + + // Gather INFO + let mut cmd = redis::cmd("INFO"); + cmd.arg("ALL"); + let info = connection + .route_command( + &cmd, + RoutingInfo::MultiNode((MultipleNodeRoutingInfo::AllNodes, None)), + ) + .await + .unwrap(); + + let info_result: HashMap = + redis::from_owned_redis_value::>(info).unwrap(); + let get_cmdstat = "cmdstat_get:calls=".to_string(); + let n_get_cmdstat = format!("cmdstat_get:calls={}", n); + let client_az2 = format!("availability-zone:{}", client_az); + let mut matching_entries_count: usize = 0; + + for value in info_result.values() { + if value.contains(&get_cmdstat) { + if value.contains(&client_az) && value.contains(&n_get_cmdstat) { + matching_entries_count += 1; + } else { + panic!( + "Invalid entry found: {}. Expected cmdstat_get:calls={} and availability_zone={}", + value, n, client_az2); + } + } + } + + assert_eq!( + (matching_entries_count.try_into() as Result).unwrap(), + primary_in_same_az, + "Test failed: expected exactly '{}' entries with '{}' and '{}', found {}", + primary_in_same_az, + get_cmdstat, + client_az, + matching_entries_count + ); + } + #[test] #[serial_test::serial] fn test_async_cluster_basic_eval() { diff --git a/glide-core/src/client/mod.rs b/glide-core/src/client/mod.rs index 36ad93031b..4a4a52b3c2 100644 --- a/glide-core/src/client/mod.rs +++ b/glide-core/src/client/mod.rs @@ -581,6 +581,9 @@ async fn create_cluster_client( let read_from_strategy = request.read_from.unwrap_or_default(); builder = builder.read_from(match read_from_strategy { ReadFrom::AZAffinity(az) => ReadFromReplicaStrategy::AZAffinity(az), + ReadFrom::AZAffinityReplicasAndPrimary(az) => { + ReadFromReplicaStrategy::AZAffinityReplicasAndPrimary(az) + } ReadFrom::PreferReplica => ReadFromReplicaStrategy::RoundRobin, ReadFrom::Primary => ReadFromReplicaStrategy::AlwaysFromPrimary, }); @@ -738,6 +741,8 @@ fn sanitized_request_string(request: &ConnectionRequest) -> String { ReadFrom::Primary => "Only primary", ReadFrom::PreferReplica => "Prefer replica", ReadFrom::AZAffinity(_) => "Prefer replica in user's availability zone", + ReadFrom::AZAffinityReplicasAndPrimary(_) => + "Prefer replica and primary in user's availability zone", } ) }) diff --git a/glide-core/src/client/standalone_client.rs b/glide-core/src/client/standalone_client.rs index c2c541c763..f4945335b2 100644 --- a/glide-core/src/client/standalone_client.rs +++ b/glide-core/src/client/standalone_client.rs @@ -31,6 +31,10 @@ enum ReadFrom { client_az: String, last_read_replica_index: Arc, }, + AZAffinityReplicasAndPrimary { + client_az: String, + last_read_replica_index: Arc, + }, } #[derive(Debug)] @@ -130,6 +134,7 @@ impl StandaloneClient { let discover_az = matches!( connection_request.read_from, Some(ClientReadFrom::AZAffinity(_)) + | Some(ClientReadFrom::AZAffinityReplicasAndPrimary(_)) ); let connection_timeout = to_duration( @@ -306,6 +311,57 @@ impl StandaloneClient { } } + async fn round_robin_read_from_replica_az_awareness_replicas_and_primary( + &self, + latest_read_replica_index: &Arc, + client_az: String, + ) -> &ReconnectingConnection { + let initial_index = latest_read_replica_index.load(Ordering::Relaxed); + let mut retries = 0usize; + + // Step 1: Try to find a replica in the same AZ + loop { + retries = retries.saturating_add(1); + // Looped through all replicas; no connected replica found in the same AZ. + if retries >= self.inner.nodes.len() { + break; + } + + // Calculate index based on initial index and check count. + let index = (initial_index + retries) % self.inner.nodes.len(); + let replica = &self.inner.nodes[index]; + + // Attempt to get a connection and retrieve the replica's AZ. + if let Ok(connection) = replica.get_connection().await { + if let Some(replica_az) = connection.get_az().as_deref() { + if replica_az == client_az { + // Update `latest_used_replica` with the index of this replica. + let _ = latest_read_replica_index.compare_exchange_weak( + initial_index, + index, + Ordering::Relaxed, + Ordering::Relaxed, + ); + return replica; + } + } + } + } + + // Step 2: Check if primary is in the same AZ + let primary = self.get_primary_connection(); + if let Ok(connection) = primary.get_connection().await { + if let Some(primary_az) = connection.get_az().as_deref() { + if primary_az == client_az { + return primary; + } + } + } + + // Step 3: Fall back to any available replica using round-robin + self.round_robin_read_from_replica(latest_read_replica_index) + } + async fn get_connection(&self, readonly: bool) -> &ReconnectingConnection { if self.inner.nodes.len() == 1 || !readonly { return self.get_primary_connection(); @@ -326,6 +382,16 @@ impl StandaloneClient { ) .await } + ReadFrom::AZAffinityReplicasAndPrimary { + client_az, + last_read_replica_index, + } => { + self.round_robin_read_from_replica_az_awareness_replicas_and_primary( + last_read_replica_index, + client_az.to_string(), + ) + .await + } } } @@ -608,6 +674,12 @@ fn get_read_from(read_from: Option) -> ReadFrom { client_az: az, last_read_replica_index: Default::default(), }, + Some(super::ReadFrom::AZAffinityReplicasAndPrimary(az)) => { + ReadFrom::AZAffinityReplicasAndPrimary { + client_az: az, + last_read_replica_index: Default::default(), + } + } None => ReadFrom::Primary, } } diff --git a/glide-core/src/client/types.rs b/glide-core/src/client/types.rs index ae140a434c..c3d609506b 100644 --- a/glide-core/src/client/types.rs +++ b/glide-core/src/client/types.rs @@ -60,6 +60,7 @@ pub enum ReadFrom { Primary, PreferReplica, AZAffinity(String), + AZAffinityReplicasAndPrimary(String), } #[derive(PartialEq, Eq, Clone, Copy, Default)] @@ -115,6 +116,20 @@ impl From for ConnectionRequest { ReadFrom::PreferReplica } } + protobuf::ReadFrom::AZAffinityReplicasAndPrimary => { + if let Some(client_az) = chars_to_string_option(&value.client_az) { + ReadFrom::AZAffinityReplicasAndPrimary(client_az) + } else { + log_warn( + "types", + format!( + "Failed to convert availability zone string: '{:?}'. Falling back to `ReadFrom::PreferReplica`", + value.client_az + ), + ); + ReadFrom::PreferReplica + } + }, }); let client_name = chars_to_string_option(&value.client_name); diff --git a/glide-core/src/protobuf/connection_request.proto b/glide-core/src/protobuf/connection_request.proto index bb88542f32..5ef7719582 100644 --- a/glide-core/src/protobuf/connection_request.proto +++ b/glide-core/src/protobuf/connection_request.proto @@ -11,6 +11,7 @@ enum ReadFrom { PreferReplica = 1; LowestLatency = 2; AZAffinity = 3; + AZAffinityReplicasAndPrimary = 4; } enum TlsMode { diff --git a/glide-core/tests/test_standalone_client.rs b/glide-core/tests/test_standalone_client.rs index 77363b5c18..546cfb9ba9 100644 --- a/glide-core/tests/test_standalone_client.rs +++ b/glide-core/tests/test_standalone_client.rs @@ -272,6 +272,7 @@ mod standalone_client_tests { }); } + // TODO - Current test falls back to PreferReplica when run, need to integrate the az here also #[rstest] #[serial_test::serial] #[timeout(SHORT_STANDALONE_TEST_TIMEOUT)] @@ -283,6 +284,18 @@ mod standalone_client_tests { ..Default::default() }); } + // TODO - Needs changes in the struct and the create_primary_mock + #[rstest] + #[serial_test::serial] + #[timeout(SHORT_STANDALONE_TEST_TIMEOUT)] + fn test_read_from_replica_az_affinity_replicas_and_primary() { + test_read_from_replica(ReadFromReplicaTestConfig { + read_from: ReadFrom::AZAffinityReplicasAndPrimary, + expected_primary_reads: 0, + expected_replica_reads: vec![1, 1, 1], + ..Default::default() + }); + } #[rstest] #[serial_test::serial] diff --git a/go/.cargo/config.toml b/go/.cargo/config.toml index f510628c9e..48a827ca67 100644 --- a/go/.cargo/config.toml +++ b/go/.cargo/config.toml @@ -1,3 +1,8 @@ [env] GLIDE_NAME = { value = "GlideGo", force = true } GLIDE_VERSION = "0.1.0" +# Suppress error +# > ... was built for newer 'macOS' version (14.5) than being linked (14.0) +# See https://github.com/valkey-io/valkey-glide/issues/3177 and https://github.com/valkey-io/valkey-glide/pull/3178 +# TODO: set env var for specific target only https://github.com/rust-lang/cargo/issues/8801 +MACOSX_DEPLOYMENT_TARGET = "10.12" diff --git a/go/Makefile b/go/Makefile index 6616f9f785..b199e27f74 100644 --- a/go/Makefile +++ b/go/Makefile @@ -47,10 +47,25 @@ clean: build-glide-client: cargo build --release cbindgen --config cbindgen.toml --crate glide-rs --output lib.h --lang c - if [ "$$(uname)" = "Darwin" ]; then \ + @if [ "$$(uname)" = "Darwin" ] && [ "$$(arch)" = "arm64" ]; then \ + echo "Platform: aarch64-apple-darwin"; \ strip -x target/release/libglide_rs.a; \ - else \ + mkdir -p rustbin/aarch64-apple-darwin; \ + cp target/release/libglide_rs.a rustbin/aarch64-apple-darwin/; \ + elif [ "$$(uname)" = "Linux" ]; then \ strip --strip-unneeded target/release/libglide_rs.a; \ + if [ "$$(arch)" = "arm64" ] || [ "$$(arch)" = "aarch64" ]; then \ + echo "Platform: aarch64-unknown-linux-gnu"; \ + mkdir -p rustbin/aarch64-unknown-linux-gnu; \ + cp target/release/libglide_rs.a rustbin/aarch64-unknown-linux-gnu/; \ + elif [ "$$(arch)" = "x86_64" ]; then \ + echo "Platform: x86_64-unknown-linux-gnu"; \ + mkdir -p rustbin/x86_64-unknown-linux-gnu; \ + cp target/release/libglide_rs.a rustbin/x86_64-unknown-linux-gnu/; \ + fi; \ + else \ + echo "Unsupported platform: $(shell uname), $(shell arch)"; \ + exit 1; \ fi diff --git a/go/README.md b/go/README.md index 98ccd80876..51fce1d743 100644 --- a/go/README.md +++ b/go/README.md @@ -18,7 +18,7 @@ The release of Valkey GLIDE was tested on the following platforms: Linux: -- Ubuntu 24.04.1 (x86_64 and aarch64) +- Ubuntu 24.04.1 (x86_64/amd64 and arm64/aarch64) macOS: @@ -26,7 +26,7 @@ macOS: ## GO supported versions -| Go Version | +| Go Version | |----------------| | 1.20 | | 1.22 | @@ -120,3 +120,12 @@ func main() { ### Building & Testing Development instructions for local building & testing the package are in the [DEVELOPER.md](DEVELOPER.md) file. + +### Known issues + +When building an application on macos, a notice like this may appear: +``` +ld: warning: '...' has malformed LC_DYSYMTAB, expected 123 undefined symbols to start at index 17006, found 174 undefined symbols starting at index 68 +``` +It could be safely ignored. It is not an error, it could be suppressed by setting `LDFLAGS` for go as [described there](https://github.com/golang/go/issues/61229#issuecomment-1988965927). +We're working on fixing this issue, you can track it in [#3177](https://github.com/valkey-io/valkey-glide/issues/3177). diff --git a/go/THIRD_PARTY_LICENSES_GO b/go/THIRD_PARTY_LICENSES_GO index 48a15655ae..1103297e10 100644 --- a/go/THIRD_PARTY_LICENSES_GO +++ b/go/THIRD_PARTY_LICENSES_GO @@ -23878,7 +23878,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- -Package: smallvec:1.13.2 +Package: smallvec:1.14.0 The following copyrights and licenses were found in the source code of this package: diff --git a/go/api/base_client.go b/go/api/base_client.go index ff5f820d8a..fb095bbc66 100644 --- a/go/api/base_client.go +++ b/go/api/base_client.go @@ -8,7 +8,6 @@ package api // #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/../rustbin/x86_64-unknown-linux-gnu // #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-unknown-linux-gnu // #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-apple-darwin -// #cgo LDFLAGS: -L../target/release // #include "../lib.h" // // void successCallback(void *channelPtr, struct CommandResponse *message); @@ -120,6 +119,80 @@ func (client *baseClient) executeCommand(requestType C.RequestType, args []strin return client.executeCommandWithRoute(requestType, args, nil) } +func slotTypeToProtobuf(slotType config.SlotType) (protobuf.SlotTypes, error) { + switch slotType { + case config.SlotTypePrimary: + return protobuf.SlotTypes_Primary, nil + case config.SlotTypeReplica: + return protobuf.SlotTypes_Replica, nil + default: + return protobuf.SlotTypes_Primary, &errors.RequestError{Msg: "Invalid slot type"} + } +} + +func routeToProtobuf(route config.Route) (*protobuf.Routes, error) { + switch route := route.(type) { + case config.SimpleNodeRoute: + { + var simpleRoute protobuf.SimpleRoutes + switch route { + case config.AllNodes: + simpleRoute = protobuf.SimpleRoutes_AllNodes + case config.AllPrimaries: + simpleRoute = protobuf.SimpleRoutes_AllPrimaries + case config.RandomRoute: + simpleRoute = protobuf.SimpleRoutes_Random + default: + return nil, &errors.RequestError{Msg: "Invalid simple node route"} + } + return &protobuf.Routes{Value: &protobuf.Routes_SimpleRoutes{SimpleRoutes: simpleRoute}}, nil + } + case *config.SlotIdRoute: + { + slotType, err := slotTypeToProtobuf(route.SlotType) + if err != nil { + return nil, err + } + return &protobuf.Routes{ + Value: &protobuf.Routes_SlotIdRoute{ + SlotIdRoute: &protobuf.SlotIdRoute{ + SlotType: slotType, + SlotId: route.SlotID, + }, + }, + }, nil + } + case *config.SlotKeyRoute: + { + slotType, err := slotTypeToProtobuf(route.SlotType) + if err != nil { + return nil, err + } + return &protobuf.Routes{ + Value: &protobuf.Routes_SlotKeyRoute{ + SlotKeyRoute: &protobuf.SlotKeyRoute{ + SlotType: slotType, + SlotKey: route.SlotKey, + }, + }, + }, nil + } + case *config.ByAddressRoute: + { + return &protobuf.Routes{ + Value: &protobuf.Routes_ByAddressRoute{ + ByAddressRoute: &protobuf.ByAddressRoute{ + Host: route.Host, + Port: route.Port, + }, + }, + }, nil + } + default: + return nil, &errors.RequestError{Msg: "Invalid route type"} + } +} + func (client *baseClient) executeCommandWithRoute( requestType C.RequestType, args []string, @@ -142,7 +215,7 @@ func (client *baseClient) executeCommandWithRoute( var routeBytesPtr *C.uchar = nil var routeBytesCount C.uintptr_t = 0 if route != nil { - routeProto, err := route.ToRoutesProtobuf() + routeProto, err := routeToProtobuf(route) if err != nil { return nil, &errors.RequestError{Msg: "ExecuteCommand failed due to invalid route"} } @@ -232,8 +305,8 @@ func (client *baseClient) Set(key string, value string) (string, error) { // If SetOptions.returnOldValue is set, return the old value as a String. // // [valkey.io]: https://valkey.io/commands/set/ -func (client *baseClient) SetWithOptions(key string, value string, options *SetOptions) (Result[string], error) { - optionArgs, err := options.toArgs() +func (client *baseClient) SetWithOptions(key string, value string, options options.SetOptions) (Result[string], error) { + optionArgs, err := options.ToArgs() if err != nil { return CreateNilStringResult(), err } @@ -299,15 +372,15 @@ func (client *baseClient) GetEx(key string) (Result[string], error) { // Parameters: // // key - The key to be retrieved from the database. -// options - The [api.GetExOptions]. +// options - The [options.GetExOptions]. // // Return value: // // If key exists, returns the value of key as a Result[string]. Otherwise, return [api.CreateNilStringResult()]. // // [valkey.io]: https://valkey.io/commands/getex/ -func (client *baseClient) GetExWithOptions(key string, options *GetExOptions) (Result[string], error) { - optionArgs, err := options.toArgs() +func (client *baseClient) GetExWithOptions(key string, options options.GetExOptions) (Result[string], error) { + optionArgs, err := options.ToArgs() if err != nil { return CreateNilStringResult(), err } @@ -1028,7 +1101,7 @@ func (client *baseClient) HIncrByFloat(key string, field string, increment float func (client *baseClient) HScan(key string, cursor string) (string, []string, error) { result, err := client.executeCommand(C.HScan, []string{key, cursor}) if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } return handleScanResponse(result) } @@ -1042,7 +1115,7 @@ func (client *baseClient) HScan(key string, cursor string) (string, []string, er // // key - The key of the hash. // cursor - The cursor that points to the next iteration of results. A value of "0" indicates the start of the search. -// options - The [api.HashScanOptions]. +// options - The [options.HashScanOptions]. // // Return value: // @@ -1056,16 +1129,16 @@ func (client *baseClient) HScan(key string, cursor string) (string, []string, er func (client *baseClient) HScanWithOptions( key string, cursor string, - options *options.HashScanOptions, + options options.HashScanOptions, ) (string, []string, error) { optionArgs, err := options.ToArgs() if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } result, err := client.executeCommand(C.HScan, append([]string{key, cursor}, optionArgs...)) if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } return handleScanResponse(result) } @@ -1147,7 +1220,7 @@ func (client *baseClient) HRandFieldWithCount(key string, count int64) ([]string // // [valkey.io]: https://valkey.io/commands/hrandfield/ func (client *baseClient) HRandFieldWithCountWithValues(key string, count int64) ([][]string, error) { - result, err := client.executeCommand(C.HRandField, []string{key, utils.IntToString(count), options.WithValues}) + result, err := client.executeCommand(C.HRandField, []string{key, utils.IntToString(count), options.WithValuesKeyword}) if err != nil { return nil, err } @@ -1268,8 +1341,12 @@ func (client *baseClient) LPos(key string, element string) (Result[int64], error // The Result[int64] containing the index of element, or [api.CreateNilInt64Result()] if element is not in the list. // // [valkey.io]: https://valkey.io/commands/lpos/ -func (client *baseClient) LPosWithOptions(key string, element string, options *LPosOptions) (Result[int64], error) { - result, err := client.executeCommand(C.LPos, append([]string{key, element}, options.toArgs()...)) +func (client *baseClient) LPosWithOptions(key string, element string, options options.LPosOptions) (Result[int64], error) { + optionArgs, err := options.ToArgs() + if err != nil { + return CreateNilInt64Result(), err + } + result, err := client.executeCommand(C.LPos, append([]string{key, element}, optionArgs...)) if err != nil { return CreateNilInt64Result(), err } @@ -1293,7 +1370,7 @@ func (client *baseClient) LPosWithOptions(key string, element string, options *L // // [valkey.io]: https://valkey.io/commands/lpos/ func (client *baseClient) LPosCount(key string, element string, count int64) ([]int64, error) { - result, err := client.executeCommand(C.LPos, []string{key, element, CountKeyword, utils.IntToString(count)}) + result, err := client.executeCommand(C.LPos, []string{key, element, options.CountKeyword, utils.IntToString(count)}) if err != nil { return nil, err } @@ -1311,7 +1388,7 @@ func (client *baseClient) LPosCount(key string, element string, count int64) ([] // key - The name of the list. // element - The value to search for within the list. // count - The number of matches wanted. -// options - The LPos options. +// opts - The LPos options. // // Return value: // @@ -1322,11 +1399,15 @@ func (client *baseClient) LPosCountWithOptions( key string, element string, count int64, - options *LPosOptions, + opts options.LPosOptions, ) ([]int64, error) { + optionArgs, err := opts.ToArgs() + if err != nil { + return nil, err + } result, err := client.executeCommand( C.LPos, - append([]string{key, element, CountKeyword, utils.IntToString(count)}, options.toArgs()...), + append([]string{key, element, options.CountKeyword, utils.IntToString(count)}, optionArgs...), ) if err != nil { return nil, err @@ -1652,7 +1733,11 @@ func (client *baseClient) SInterCard(keys []string) (int64, error) { // // [valkey.io]: https://valkey.io/commands/sintercard/ func (client *baseClient) SInterCardLimit(keys []string, limit int64) (int64, error) { - args := utils.Concat([]string{utils.IntToString(int64(len(keys)))}, keys, []string{"LIMIT", utils.IntToString(limit)}) + args := utils.Concat( + []string{utils.IntToString(int64(len(keys)))}, + keys, + []string{options.LimitKeyword, utils.IntToString(limit)}, + ) result, err := client.executeCommand(C.SInterCard, args) if err != nil { @@ -1778,7 +1863,7 @@ func (client *baseClient) SUnion(keys []string) (map[string]struct{}, error) { func (client *baseClient) SScan(key string, cursor string) (string, []string, error) { result, err := client.executeCommand(C.SScan, []string{key, cursor}) if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } return handleScanResponse(result) } @@ -1807,16 +1892,16 @@ func (client *baseClient) SScan(key string, cursor string) (string, []string, er func (client *baseClient) SScanWithOptions( key string, cursor string, - options *options.BaseScanOptions, + options options.BaseScanOptions, ) (string, []string, error) { optionArgs, err := options.ToArgs() if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } result, err := client.executeCommand(C.SScan, append([]string{key, cursor}, optionArgs...)) if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } return handleScanResponse(result) } @@ -2042,7 +2127,7 @@ func (client *baseClient) RPopCount(key string, count int64) ([]string, error) { // Parameters: // // key - The key of the list. -// insertPosition - The relative position to insert into - either api.Before or api.After the pivot. +// insertPosition - The relative position to insert into - either options.Before or options.After the pivot. // pivot - An element of the list. // element - The new element to insert. // @@ -2055,11 +2140,11 @@ func (client *baseClient) RPopCount(key string, count int64) ([]string, error) { // [valkey.io]: https://valkey.io/commands/linsert/ func (client *baseClient) LInsert( key string, - insertPosition InsertPosition, + insertPosition options.InsertPosition, pivot string, element string, ) (int64, error) { - insertPositionStr, err := insertPosition.toString() + insertPositionStr, err := insertPosition.ToString() if err != nil { return defaultIntResponse, err } @@ -2198,15 +2283,15 @@ func (client *baseClient) LPushX(key string, elements []string) (int64, error) { // Parameters: // // keys - An array of keys to lists. -// listDirection - The direction based on which elements are popped from - see [api.ListDirection]. +// listDirection - The direction based on which elements are popped from - see [options.ListDirection]. // // Return value: // // A map of key name mapped array of popped element. // // [valkey.io]: https://valkey.io/commands/lmpop/ -func (client *baseClient) LMPop(keys []string, listDirection ListDirection) (map[string][]string, error) { - listDirectionStr, err := listDirection.toString() +func (client *baseClient) LMPop(keys []string, listDirection options.ListDirection) (map[string][]string, error) { + listDirectionStr, err := listDirection.ToString() if err != nil { return nil, err } @@ -2240,7 +2325,7 @@ func (client *baseClient) LMPop(keys []string, listDirection ListDirection) (map // Parameters: // // keys - An array of keys to lists. -// listDirection - The direction based on which elements are popped from - see [api.ListDirection]. +// listDirection - The direction based on which elements are popped from - see [options.ListDirection]. // count - The maximum number of popped elements. // // Return value: @@ -2250,10 +2335,10 @@ func (client *baseClient) LMPop(keys []string, listDirection ListDirection) (map // [valkey.io]: https://valkey.io/commands/lmpop/ func (client *baseClient) LMPopCount( keys []string, - listDirection ListDirection, + listDirection options.ListDirection, count int64, ) (map[string][]string, error) { - listDirectionStr, err := listDirection.toString() + listDirectionStr, err := listDirection.ToString() if err != nil { return nil, err } @@ -2267,7 +2352,7 @@ func (client *baseClient) LMPopCount( args := make([]string, 0, len(keys)+4) args = append(args, strconv.Itoa(len(keys))) args = append(args, keys...) - args = append(args, listDirectionStr, CountKeyword, utils.IntToString(count)) + args = append(args, listDirectionStr, options.CountKeyword, utils.IntToString(count)) result, err := client.executeCommand(C.LMPop, args) if err != nil { return nil, err @@ -2292,7 +2377,7 @@ func (client *baseClient) LMPopCount( // Parameters: // // keys - An array of keys to lists. -// listDirection - The direction based on which elements are popped from - see [api.ListDirection]. +// listDirection - The direction based on which elements are popped from - see [options.ListDirection]. // timeoutSecs - The number of seconds to wait for a blocking operation to complete. A value of 0 will block indefinitely. // // Return value: @@ -2304,10 +2389,10 @@ func (client *baseClient) LMPopCount( // [Blocking Commands]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#blocking-commands func (client *baseClient) BLMPop( keys []string, - listDirection ListDirection, + listDirection options.ListDirection, timeoutSecs float64, ) (map[string][]string, error) { - listDirectionStr, err := listDirection.toString() + listDirectionStr, err := listDirection.ToString() if err != nil { return nil, err } @@ -2346,7 +2431,7 @@ func (client *baseClient) BLMPop( // Parameters: // // keys - An array of keys to lists. -// listDirection - The direction based on which elements are popped from - see [api.ListDirection]. +// listDirection - The direction based on which elements are popped from - see [options.ListDirection]. // count - The maximum number of popped elements. // timeoutSecs - The number of seconds to wait for a blocking operation to complete. A value of 0 will block // @@ -2361,11 +2446,11 @@ func (client *baseClient) BLMPop( // [Blocking Commands]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#blocking-commands func (client *baseClient) BLMPopCount( keys []string, - listDirection ListDirection, + listDirection options.ListDirection, count int64, timeoutSecs float64, ) (map[string][]string, error) { - listDirectionStr, err := listDirection.toString() + listDirectionStr, err := listDirection.ToString() if err != nil { return nil, err } @@ -2379,7 +2464,7 @@ func (client *baseClient) BLMPopCount( args := make([]string, 0, len(keys)+5) args = append(args, utils.FloatToString(timeoutSecs), strconv.Itoa(len(keys))) args = append(args, keys...) - args = append(args, listDirectionStr, CountKeyword, utils.IntToString(count)) + args = append(args, listDirectionStr, options.CountKeyword, utils.IntToString(count)) result, err := client.executeCommand(C.BLMPop, args) if err != nil { return nil, err @@ -2435,14 +2520,14 @@ func (client *baseClient) LSet(key string, index int64, element string) (string, func (client *baseClient) LMove( source string, destination string, - whereFrom ListDirection, - whereTo ListDirection, + whereFrom options.ListDirection, + whereTo options.ListDirection, ) (Result[string], error) { - whereFromStr, err := whereFrom.toString() + whereFromStr, err := whereFrom.ToString() if err != nil { return CreateNilStringResult(), err } - whereToStr, err := whereTo.toString() + whereToStr, err := whereTo.ToString() if err != nil { return CreateNilStringResult(), err } @@ -2488,15 +2573,15 @@ func (client *baseClient) LMove( func (client *baseClient) BLMove( source string, destination string, - whereFrom ListDirection, - whereTo ListDirection, + whereFrom options.ListDirection, + whereTo options.ListDirection, timeoutSecs float64, ) (Result[string], error) { - whereFromStr, err := whereFrom.toString() + whereFromStr, err := whereFrom.ToString() if err != nil { return CreateNilStringResult(), err } - whereToStr, err := whereTo.toString() + whereToStr, err := whereTo.ToString() if err != nil { return CreateNilStringResult(), err } @@ -2605,8 +2690,9 @@ func (client *baseClient) Expire(key string, seconds int64) (bool, error) { // Parameters: // // key - The key to expire. -// seconds - Time in seconds for the key to expire -// option - The option to set expiry - NX, XX, GT, LT +// +// seconds - Time in seconds for the key to expire. +// option - The option to set expiry, see [options.ExpireCondition]. // // Return value: // @@ -2614,8 +2700,8 @@ func (client *baseClient) Expire(key string, seconds int64) (bool, error) { // or operation skipped due to the provided arguments. // // [valkey.io]: https://valkey.io/commands/expire/ -func (client *baseClient) ExpireWithOptions(key string, seconds int64, expireCondition ExpireCondition) (bool, error) { - expireConditionStr, err := expireCondition.toString() +func (client *baseClient) ExpireWithOptions(key string, seconds int64, expireCondition options.ExpireCondition) (bool, error) { + expireConditionStr, err := expireCondition.ToString() if err != nil { return defaultBoolResponse, err } @@ -2667,8 +2753,9 @@ func (client *baseClient) ExpireAt(key string, unixTimestampInSeconds int64) (bo // Parameters: // // key - The key to expire. -// unixTimestampInSeconds - Absolute Unix timestamp -// option - The option to set expiry - NX, XX, GT, LT +// +// unixTimestampInSeconds - Absolute Unix timestamp. +// option - The option to set expiry - see [options.ExpireCondition]. // // Return value: // @@ -2679,9 +2766,9 @@ func (client *baseClient) ExpireAt(key string, unixTimestampInSeconds int64) (bo func (client *baseClient) ExpireAtWithOptions( key string, unixTimestampInSeconds int64, - expireCondition ExpireCondition, + expireCondition options.ExpireCondition, ) (bool, error) { - expireConditionStr, err := expireCondition.toString() + expireConditionStr, err := expireCondition.ToString() if err != nil { return defaultBoolResponse, err } @@ -2710,7 +2797,7 @@ func (client *baseClient) ExpireAtWithOptions( // `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, // or operation skipped due to the provided arguments. // -// [valkey.io]: https://valkey.io/commands/pexpire/ +// [valkey.io]: https://valkey.io/commands/pexpire/ func (client *baseClient) PExpire(key string, milliseconds int64) (bool, error) { result, err := client.executeCommand(C.PExpire, []string{key, utils.IntToString(milliseconds)}) if err != nil { @@ -2728,20 +2815,20 @@ func (client *baseClient) PExpire(key string, milliseconds int64) (bool, error) // // key - The key to set timeout on it. // milliseconds - The timeout in milliseconds. -// option - The option to set expiry - NX, XX, GT, LT +// option - The option to set expiry, see [options.ExpireCondition]. // // Return value: // // `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, // or operation skipped due to the provided arguments. // -// [valkey.io]: https://valkey.io/commands/pexpire/ +// [valkey.io]: https://valkey.io/commands/pexpire/ func (client *baseClient) PExpireWithOptions( key string, milliseconds int64, - expireCondition ExpireCondition, + expireCondition options.ExpireCondition, ) (bool, error) { - expireConditionStr, err := expireCondition.toString() + expireConditionStr, err := expireCondition.ToString() if err != nil { return defaultBoolResponse, err } @@ -2770,7 +2857,7 @@ func (client *baseClient) PExpireWithOptions( // `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, // or operation skipped due to the provided arguments. // -// [valkey.io]: https://valkey.io/commands/pexpireat/ +// [valkey.io]: https://valkey.io/commands/pexpireat/ func (client *baseClient) PExpireAt(key string, unixTimestampInMilliSeconds int64) (bool, error) { result, err := client.executeCommand(C.PExpireAt, []string{key, utils.IntToString(unixTimestampInMilliSeconds)}) if err != nil { @@ -2790,20 +2877,20 @@ func (client *baseClient) PExpireAt(key string, unixTimestampInMilliSeconds int6 // // key - The key to set timeout on it. // unixMilliseconds - The timeout in an absolute Unix timestamp. -// option - The option to set expiry - NX, XX, GT, LT +// option - The option to set expiry, see [options.ExpireCondition]. // // Return value: // // `true` if the timeout was set. `false` if the timeout was not set. e.g. key doesn't exist, // or operation skipped due to the provided arguments. // -// [valkey.io]: https://valkey.io/commands/pexpireat/ +// [valkey.io]: https://valkey.io/commands/pexpireat/ func (client *baseClient) PExpireAtWithOptions( key string, unixTimestampInMilliSeconds int64, - expireCondition ExpireCondition, + expireCondition options.ExpireCondition, ) (bool, error) { - expireConditionStr, err := expireCondition.toString() + expireConditionStr, err := expireCondition.ToString() if err != nil { return defaultBoolResponse, err } @@ -3000,7 +3087,7 @@ func (client *baseClient) Unlink(keys []string) (int64, error) { // // If the key exists, the type of the stored value is returned. Otherwise, a "none" string is returned. // -// [valkey.io]: Https://valkey.io/commands/type/ +// [valkey.io]: https://valkey.io/commands/type/ func (client *baseClient) Type(key string) (string, error) { result, err := client.executeCommand(C.Type, []string{key}) if err != nil { @@ -3103,7 +3190,7 @@ func (client *baseClient) RenameNX(key string, newKey string) (bool, error) { // // [valkey.io]: https://valkey.io/commands/xadd/ func (client *baseClient) XAdd(key string, values [][]string) (Result[string], error) { - return client.XAddWithOptions(key, values, options.NewXAddOptions()) + return client.XAddWithOptions(key, values, *options.NewXAddOptions()) } // Adds an entry to the specified stream stored at `key`. If the `key` doesn't exist, the stream is created. @@ -3124,7 +3211,7 @@ func (client *baseClient) XAdd(key string, values [][]string) (Result[string], e func (client *baseClient) XAddWithOptions( key string, values [][]string, - options *options.XAddOptions, + options options.XAddOptions, ) (Result[string], error) { args := []string{} args = append(args, key) @@ -3169,7 +3256,7 @@ func (client *baseClient) XAddWithOptions( // // [valkey.io]: https://valkey.io/commands/xread/ func (client *baseClient) XRead(keysAndIds map[string]string) (map[string]map[string][][]string, error) { - return client.XReadWithOptions(keysAndIds, options.NewXReadOptions()) + return client.XReadWithOptions(keysAndIds, *options.NewXReadOptions()) } // Reads entries from the given streams. @@ -3183,7 +3270,7 @@ func (client *baseClient) XRead(keysAndIds map[string]string) (map[string]map[st // Parameters: // // keysAndIds - A map of keys and entry IDs to read from. -// options - Options detailing how to read the stream. +// opts - Options detailing how to read the stream. // // Return value: // @@ -3193,22 +3280,12 @@ func (client *baseClient) XRead(keysAndIds map[string]string) (map[string]map[st // [valkey.io]: https://valkey.io/commands/xread/ func (client *baseClient) XReadWithOptions( keysAndIds map[string]string, - options *options.XReadOptions, + opts options.XReadOptions, ) (map[string]map[string][][]string, error) { - args := make([]string, 0, 5+2*len(keysAndIds)) - optionArgs, _ := options.ToArgs() - args = append(args, optionArgs...) - - // Note: this loop iterates in an indeterminate order, but it is OK for that case - keys := make([]string, 0, len(keysAndIds)) - values := make([]string, 0, len(keysAndIds)) - for key := range keysAndIds { - keys = append(keys, key) - values = append(values, keysAndIds[key]) + args, err := createStreamCommandArgs(make([]string, 0, 5+2*len(keysAndIds)), keysAndIds, &opts) + if err != nil { + return nil, err } - args = append(args, "STREAMS") - args = append(args, keys...) - args = append(args, values...) result, err := client.executeCommand(C.XRead, args) if err != nil { @@ -3243,7 +3320,7 @@ func (client *baseClient) XReadGroup( consumer string, keysAndIds map[string]string, ) (map[string]map[string][][]string, error) { - return client.XReadGroupWithOptions(group, consumer, keysAndIds, options.NewXReadGroupOptions()) + return client.XReadGroupWithOptions(group, consumer, keysAndIds, *options.NewXReadGroupOptions()) } // Reads entries from the given streams owned by a consumer group. @@ -3259,7 +3336,7 @@ func (client *baseClient) XReadGroup( // group - The consumer group name. // consumer - The group consumer. // keysAndIds - A map of keys and entry IDs to read from. -// options - Options detailing how to read the stream. +// opts - Options detailing how to read the stream. // // Return value: // @@ -3271,9 +3348,9 @@ func (client *baseClient) XReadGroupWithOptions( group string, consumer string, keysAndIds map[string]string, - options *options.XReadGroupOptions, + opts options.XReadGroupOptions, ) (map[string]map[string][][]string, error) { - args, err := createStreamCommandArgs([]string{"GROUP", group, consumer}, keysAndIds, options) + args, err := createStreamCommandArgs([]string{options.GroupKeyword, group, consumer}, keysAndIds, &opts) if err != nil { return nil, err } @@ -3290,9 +3367,9 @@ func (client *baseClient) XReadGroupWithOptions( func createStreamCommandArgs( args []string, keysAndIds map[string]string, - options interface{ ToArgs() ([]string, error) }, + opts interface{ ToArgs() ([]string, error) }, ) ([]string, error) { - optionArgs, err := options.ToArgs() + optionArgs, err := opts.ToArgs() if err != nil { return nil, err } @@ -3304,7 +3381,7 @@ func createStreamCommandArgs( keys = append(keys, key) values = append(values, keysAndIds[key]) } - args = append(args, "STREAMS") + args = append(args, options.StreamsKeyword) args = append(args, keys...) args = append(args, values...) return args, nil @@ -3357,7 +3434,7 @@ func (client *baseClient) ZAdd( func (client *baseClient) ZAddWithOptions( key string, membersScoreMap map[string]float64, - opts *options.ZAddOptions, + opts options.ZAddOptions, ) (int64, error) { optionArgs, err := opts.ToArgs() if err != nil { @@ -3409,7 +3486,7 @@ func (client *baseClient) ZAddIncr( member string, increment float64, ) (Result[float64], error) { - options, err := options.NewZAddOptionsBuilder().SetIncr(true, increment, member) + options, err := options.NewZAddOptions().SetIncr(true, increment, member) if err != nil { return CreateNilFloat64Result(), err } @@ -3438,7 +3515,7 @@ func (client *baseClient) ZAddIncrWithOptions( key string, member string, increment float64, - opts *options.ZAddOptions, + opts options.ZAddOptions, ) (Result[float64], error) { incrOpts, err := opts.SetIncr(true, increment, member) if err != nil { @@ -3516,8 +3593,12 @@ func (client *baseClient) ZPopMin(key string) (map[string]float64, error) { // command returns an empty map. // // [valkey.io]: https://valkey.io/commands/zpopmin/ -func (client *baseClient) ZPopMinWithCount(key string, count int64) (map[string]float64, error) { - result, err := client.executeCommand(C.ZPopMin, []string{key, utils.IntToString(count)}) +func (client *baseClient) ZPopMinWithOptions(key string, options options.ZPopOptions) (map[string]float64, error) { + optArgs, err := options.ToArgs() + if err != nil { + return nil, err + } + result, err := client.executeCommand(C.ZPopMin, append([]string{key}, optArgs...)) if err != nil { return nil, err } @@ -3565,8 +3646,12 @@ func (client *baseClient) ZPopMax(key string) (map[string]float64, error) { // command returns an empty map. // // [valkey.io]: https://valkey.io/commands/zpopmin/ -func (client *baseClient) ZPopMaxWithCount(key string, count int64) (map[string]float64, error) { - result, err := client.executeCommand(C.ZPopMax, []string{key, utils.IntToString(count)}) +func (client *baseClient) ZPopMaxWithOptions(key string, options options.ZPopOptions) (map[string]float64, error) { + optArgs, err := options.ToArgs() + if err != nil { + return nil, err + } + result, err := client.executeCommand(C.ZPopMax, append([]string{key}, optArgs...)) if err != nil { return nil, err } @@ -3672,7 +3757,7 @@ func (client *baseClient) BZPopMin(keys []string, timeoutSecs float64) (Result[K // Parameters: // // keys - An array of keys to lists. -// scoreFilter - The element pop criteria - either [api.MIN] or [api.MAX] to pop members with the lowest/highest +// scoreFilter - The element pop criteria - either [options.MIN] or [options.MAX] to pop members with the lowest/highest // scores accordingly. // timeoutSecs - The number of seconds to wait for a blocking operation to complete. A value of `0` will block // indefinitely. @@ -3688,10 +3773,10 @@ func (client *baseClient) BZPopMin(keys []string, timeoutSecs float64) (Result[K // [Blocking Commands]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#blocking-commands func (client *baseClient) BZMPop( keys []string, - scoreFilter ScoreFilter, + scoreFilter options.ScoreFilter, timeoutSecs float64, ) (Result[KeyWithArrayOfMembersAndScores], error) { - scoreFilterStr, err := scoreFilter.toString() + scoreFilterStr, err := scoreFilter.ToString() if err != nil { return CreateNilKeyWithArrayOfMembersAndScoresResult(), err } @@ -3732,11 +3817,13 @@ func (client *baseClient) BZMPop( // Parameters: // // keys - An array of keys to lists. -// scoreFilter - The element pop criteria - either [api.MIN] or [api.MAX] to pop members with the lowest/highest +// scoreFilter - The element pop criteria - either [options.MIN] or [options.MAX] to pop members with the lowest/highest // scores accordingly. // count - The maximum number of popped elements. // timeoutSecs - The number of seconds to wait for a blocking operation to complete. A value of `0` will block indefinitely. // +// opts - Pop options, see [options.ZMPopOptions]. +// // Return value: // // An object containing the following elements: @@ -3748,11 +3835,11 @@ func (client *baseClient) BZMPop( // [Blocking Commands]: https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#blocking-commands func (client *baseClient) BZMPopWithOptions( keys []string, - scoreFilter ScoreFilter, + scoreFilter options.ScoreFilter, timeoutSecs float64, - opts *options.ZMPopOptions, + opts options.ZMPopOptions, ) (Result[KeyWithArrayOfMembersAndScores], error) { - scoreFilterStr, err := scoreFilter.toString() + scoreFilterStr, err := scoreFilter.ToString() if err != nil { return CreateNilKeyWithArrayOfMembersAndScoresResult(), err } @@ -3769,13 +3856,11 @@ func (client *baseClient) BZMPopWithOptions( args = append(args, utils.FloatToString(timeoutSecs), strconv.Itoa(len(keys))) args = append(args, keys...) args = append(args, scoreFilterStr) - if opts != nil { - optionArgs, err := opts.ToArgs() - if err != nil { - return CreateNilKeyWithArrayOfMembersAndScoresResult(), err - } - args = append(args, optionArgs...) + optionArgs, err := opts.ToArgs() + if err != nil { + return CreateNilKeyWithArrayOfMembersAndScoresResult(), err } + args = append(args, optionArgs...) result, err := client.executeCommand(C.BZMPop, args) if err != nil { return CreateNilKeyWithArrayOfMembersAndScoresResult(), err @@ -3808,7 +3893,11 @@ func (client *baseClient) BZMPopWithOptions( func (client *baseClient) ZRange(key string, rangeQuery options.ZRangeQuery) ([]string, error) { args := make([]string, 0, 10) args = append(args, key) - args = append(args, rangeQuery.ToArgs()...) + queryArgs, err := rangeQuery.ToArgs() + if err != nil { + return nil, err + } + args = append(args, queryArgs...) result, err := client.executeCommand(C.ZRange, args) if err != nil { return nil, err @@ -3841,8 +3930,12 @@ func (client *baseClient) ZRangeWithScores( ) (map[string]float64, error) { args := make([]string, 0, 10) args = append(args, key) - args = append(args, rangeQuery.ToArgs()...) - args = append(args, "WITHSCORES") + queryArgs, err := rangeQuery.ToArgs() + if err != nil { + return nil, err + } + args = append(args, queryArgs...) + args = append(args, options.WithScoresKeyword) result, err := client.executeCommand(C.ZRange, args) if err != nil { return nil, err @@ -3883,7 +3976,11 @@ func (client *baseClient) ZRangeStore( args := make([]string, 0, 10) args = append(args, destination) args = append(args, key) - args = append(args, rangeQuery.ToArgs()...) + rqArgs, err := rangeQuery.ToArgs() + if err != nil { + return defaultIntResponse, err + } + args = append(args, rqArgs...) result, err := client.executeCommand(C.ZRangeStore, args) if err != nil { return defaultIntResponse, err @@ -3928,7 +4025,7 @@ func (client *baseClient) Persist(key string) (bool, error) { // The number of members in the specified score range. // // [valkey.io]: https://valkey.io/commands/zcount/ -func (client *baseClient) ZCount(key string, rangeOptions *options.ZCountRange) (int64, error) { +func (client *baseClient) ZCount(key string, rangeOptions options.ZCountRange) (int64, error) { zCountRangeArgs, err := rangeOptions.ToArgs() if err != nil { return defaultIntResponse, err @@ -3984,7 +4081,7 @@ func (client *baseClient) ZRank(key string, member string) (Result[int64], error // // [valkey.io]: https://valkey.io/commands/zrank/ func (client *baseClient) ZRankWithScore(key string, member string) (Result[int64], Result[float64], error) { - result, err := client.executeCommand(C.ZRank, []string{key, member, options.WithScore}) + result, err := client.executeCommand(C.ZRank, []string{key, member, options.WithScoreKeyword}) if err != nil { return CreateNilInt64Result(), CreateNilFloat64Result(), err } @@ -4037,7 +4134,7 @@ func (client *baseClient) ZRevRank(key string, member string) (Result[int64], er // // [valkey.io]: https://valkey.io/commands/zrevrank/ func (client *baseClient) ZRevRankWithScore(key string, member string) (Result[int64], Result[float64], error) { - result, err := client.executeCommand(C.ZRevRank, []string{key, member, options.WithScore}) + result, err := client.executeCommand(C.ZRevRank, []string{key, member, options.WithScoreKeyword}) if err != nil { return CreateNilInt64Result(), CreateNilFloat64Result(), err } @@ -4058,7 +4155,7 @@ func (client *baseClient) ZRevRankWithScore(key string, member string) (Result[i // The number of entries deleted from the stream. // // [valkey.io]: https://valkey.io/commands/xtrim/ -func (client *baseClient) XTrim(key string, options *options.XTrimOptions) (int64, error) { +func (client *baseClient) XTrim(key string, options options.XTrimOptions) (int64, error) { xTrimArgs, err := options.ToArgs() if err != nil { return defaultIntResponse, err @@ -4126,7 +4223,7 @@ func (client *baseClient) XAutoClaim( minIdleTime int64, start string, ) (XAutoClaimResponse, error) { - return client.XAutoClaimWithOptions(key, group, consumer, minIdleTime, start, nil) + return client.XAutoClaimWithOptions(key, group, consumer, minIdleTime, start, *options.NewXAutoClaimOptions()) } // Transfers ownership of pending stream entries that match the specified criteria. @@ -4164,16 +4261,14 @@ func (client *baseClient) XAutoClaimWithOptions( consumer string, minIdleTime int64, start string, - options *options.XAutoClaimOptions, + options options.XAutoClaimOptions, ) (XAutoClaimResponse, error) { args := []string{key, group, consumer, utils.IntToString(minIdleTime), start} - if options != nil { - optArgs, err := options.ToArgs() - if err != nil { - return XAutoClaimResponse{}, err - } - args = append(args, optArgs...) + optArgs, err := options.ToArgs() + if err != nil { + return XAutoClaimResponse{}, err } + args = append(args, optArgs...) result, err := client.executeCommand(C.XAutoClaim, args) if err != nil { return XAutoClaimResponse{}, err @@ -4216,7 +4311,7 @@ func (client *baseClient) XAutoClaimJustId( minIdleTime int64, start string, ) (XAutoClaimJustIdResponse, error) { - return client.XAutoClaimJustIdWithOptions(key, group, consumer, minIdleTime, start, nil) + return client.XAutoClaimJustIdWithOptions(key, group, consumer, minIdleTime, start, *options.NewXAutoClaimOptions()) } // Transfers ownership of pending stream entries that match the specified criteria. @@ -4234,7 +4329,7 @@ func (client *baseClient) XAutoClaimJustId( // consumer - The group consumer. // minIdleTime - The minimum idle time for the message to be claimed. // start - Filters the claimed entries to those that have an ID equal or greater than the specified value. -// options - Options detailing how to read the stream. +// opts - Options detailing how to read the stream. // // Return value: // @@ -4254,17 +4349,15 @@ func (client *baseClient) XAutoClaimJustIdWithOptions( consumer string, minIdleTime int64, start string, - options *options.XAutoClaimOptions, + opts options.XAutoClaimOptions, ) (XAutoClaimJustIdResponse, error) { args := []string{key, group, consumer, utils.IntToString(minIdleTime), start} - if options != nil { - optArgs, err := options.ToArgs() - if err != nil { - return XAutoClaimJustIdResponse{}, err - } - args = append(args, optArgs...) + optArgs, err := opts.ToArgs() + if err != nil { + return XAutoClaimJustIdResponse{}, err } - args = append(args, "JUSTID") + args = append(args, optArgs...) + args = append(args, options.JustIdKeyword) result, err := client.executeCommand(C.XAutoClaim, args) if err != nil { return XAutoClaimJustIdResponse{}, err @@ -4340,7 +4433,7 @@ func (client *baseClient) ZScore(key string, member string) (Result[float64], er func (client *baseClient) ZScan(key string, cursor string) (string, []string, error) { result, err := client.executeCommand(C.ZScan, []string{key, cursor}) if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } return handleScanResponse(result) } @@ -4361,22 +4454,22 @@ func (client *baseClient) ZScan(key string, cursor string) (string, []string, er // returned on the last iteration of the sorted set. // The second return value is always an array of the subset of the sorted set held in `key`. // The array is a flattened series of `string` pairs, where the value is at even indices and the score is at odd indices. -// If `ZScanOptionsBuilder#noScores` is to `true`, the second return value will only contain the members without scores. +// If [ZScanOptions.noScores] is to `true`, the second return value will only contain the members without scores. // // [valkey.io]: https://valkey.io/commands/zscan/ func (client *baseClient) ZScanWithOptions( key string, cursor string, - options *options.ZScanOptions, + options options.ZScanOptions, ) (string, []string, error) { optionArgs, err := options.ToArgs() if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } result, err := client.executeCommand(C.ZScan, append([]string{key, cursor}, optionArgs...)) if err != nil { - return "", nil, err + return defaultStringResponse, nil, err } return handleScanResponse(result) } @@ -4434,7 +4527,7 @@ func (client *baseClient) XPending(key string, group string) (XPendingSummary, e func (client *baseClient) XPendingWithOptions( key string, group string, - opts *options.XPendingOptions, + opts options.XPendingOptions, ) ([]XPendingDetail, error) { optionArgs, _ := opts.ToArgs() args := append([]string{key, group}, optionArgs...) @@ -4463,7 +4556,7 @@ func (client *baseClient) XPendingWithOptions( // // [valkey.io]: https://valkey.io/commands/xgroup-create/ func (client *baseClient) XGroupCreate(key string, group string, id string) (string, error) { - return client.XGroupCreateWithOptions(key, group, id, options.NewXGroupCreateOptions()) + return client.XGroupCreateWithOptions(key, group, id, *options.NewXGroupCreateOptions()) } // Creates a new consumer group uniquely identified by `group` for the stream stored at `key`. @@ -4487,7 +4580,7 @@ func (client *baseClient) XGroupCreateWithOptions( key string, group string, id string, - opts *options.XGroupCreateOptions, + opts options.XGroupCreateOptions, ) (string, error) { optionArgs, _ := opts.ToArgs() args := append([]string{key, group, id}, optionArgs...) @@ -4513,7 +4606,7 @@ func (client *baseClient) XGroupCreateWithOptions( // // [valkey.io]: https://valkey.io/commands/restore/ func (client *baseClient) Restore(key string, ttl int64, value string) (Result[string], error) { - return client.RestoreWithOptions(key, ttl, value, NewRestoreOptionsBuilder()) + return client.RestoreWithOptions(key, ttl, value, *options.NewRestoreOptions()) } // Create a key associated with a value that is obtained by @@ -4524,7 +4617,7 @@ func (client *baseClient) Restore(key string, ttl int64, value string) (Result[s // key - The key to create. // ttl - The expiry time (in milliseconds). If 0, the key will persist. // value - The serialized value to deserialize and assign to key. -// restoreOptions - Set restore options with replace and absolute TTL modifiers, object idletime and frequency +// restoreOptions - Set restore options with replace and absolute TTL modifiers, object idletime and frequency. // // Return value: // @@ -4532,9 +4625,9 @@ func (client *baseClient) Restore(key string, ttl int64, value string) (Result[s // // [valkey.io]: https://valkey.io/commands/restore/ func (client *baseClient) RestoreWithOptions(key string, ttl int64, - value string, options *RestoreOptions, + value string, options options.RestoreOptions, ) (Result[string], error) { - optionArgs, err := options.toArgs() + optionArgs, err := options.ToArgs() if err != nil { return CreateNilStringResult(), err } @@ -4556,7 +4649,7 @@ func (client *baseClient) RestoreWithOptions(key string, ttl int64, // // Return value: // -// The serialized value of the data stored at key +// The serialized value of the data stored at key. // If key does not exist, null will be returned. // // [valkey.io]: https://valkey.io/commands/dump/ @@ -4581,7 +4674,7 @@ func (client *baseClient) Dump(key string) (Result[string], error) { // Return value: // // If key exists, returns the internal encoding of the object stored at -// key as a String. Otherwise, returns null. +// key as a String. Otherwise, returns `null`. // // [valkey.io]: https://valkey.io/commands/object-encoding/ func (client *baseClient) ObjectEncoding(key string) (Result[string], error) { @@ -4650,7 +4743,7 @@ func (client *baseClient) XGroupDestroy(key string, group string) (bool, error) // // [valkey.io]: https://valkey.io/commands/xgroup-setid/ func (client *baseClient) XGroupSetId(key string, group string, id string) (string, error) { - return client.XGroupSetIdWithOptions(key, group, id, options.NewXGroupSetIdOptionsOptions()) + return client.XGroupSetIdWithOptions(key, group, id, *options.NewXGroupSetIdOptionsOptions()) } // Sets the last delivered ID for a consumer group. @@ -4673,7 +4766,7 @@ func (client *baseClient) XGroupSetIdWithOptions( key string, group string, id string, - opts *options.XGroupSetIdOptions, + opts options.XGroupSetIdOptions, ) (string, error) { optionArgs, _ := opts.ToArgs() args := append([]string{key, group, id}, optionArgs...) @@ -4702,8 +4795,12 @@ func (client *baseClient) XGroupSetIdWithOptions( // // [valkey.io]: https://valkey.io/commands/zremrangebylex/ func (client *baseClient) ZRemRangeByLex(key string, rangeQuery options.RangeByLex) (int64, error) { + queryArgs, err := rangeQuery.ToArgsRemRange() + if err != nil { + return defaultIntResponse, err + } result, err := client.executeCommand( - C.ZRemRangeByLex, append([]string{key}, rangeQuery.ToArgsRemRange()...)) + C.ZRemRangeByLex, append([]string{key}, queryArgs...)) if err != nil { return defaultIntResponse, err } @@ -4730,7 +4827,7 @@ func (client *baseClient) ZRemRangeByLex(key string, rangeQuery options.RangeByL func (client *baseClient) ZRemRangeByRank(key string, start int64, stop int64) (int64, error) { result, err := client.executeCommand(C.ZRemRangeByRank, []string{key, utils.IntToString(start), utils.IntToString(stop)}) if err != nil { - return 0, err + return defaultIntResponse, err } return handleIntResponse(result) } @@ -4753,9 +4850,13 @@ func (client *baseClient) ZRemRangeByRank(key string, start int64, stop int64) ( // // [valkey.io]: https://valkey.io/commands/zremrangebyscore/ func (client *baseClient) ZRemRangeByScore(key string, rangeQuery options.RangeByScore) (int64, error) { - result, err := client.executeCommand(C.ZRemRangeByScore, append([]string{key}, rangeQuery.ToArgsRemRange()...)) + queryArgs, err := rangeQuery.ToArgsRemRange() + if err != nil { + return defaultIntResponse, err + } + result, err := client.executeCommand(C.ZRemRangeByScore, append([]string{key}, queryArgs...)) if err != nil { - return 0, err + return defaultIntResponse, err } return handleIntResponse(result) } @@ -4823,7 +4924,7 @@ func (client *baseClient) ZRandMemberWithCount(key string, count int64) ([]strin // // [valkey.io]: https://valkey.io/commands/zrandmember/ func (client *baseClient) ZRandMemberWithCountWithScores(key string, count int64) ([]MemberAndScore, error) { - result, err := client.executeCommand(C.ZRandMember, []string{key, utils.IntToString(count), options.WithScores}) + result, err := client.executeCommand(C.ZRandMember, []string{key, utils.IntToString(count), options.WithScoresKeyword}) if err != nil { return nil, err } @@ -4962,8 +5063,11 @@ func (client *baseClient) Sort(key string) ([]Result[string], error) { // An Array of sorted elements. // // [valkey.io]: https://valkey.io/commands/sort/ -func (client *baseClient) SortWithOptions(key string, options *options.SortOptions) ([]Result[string], error) { - optionArgs := options.ToArgs() +func (client *baseClient) SortWithOptions(key string, options options.SortOptions) ([]Result[string], error) { + optionArgs, err := options.ToArgs() + if err != nil { + return nil, err + } result, err := client.executeCommand(C.Sort, append([]string{key}, optionArgs...)) if err != nil { return nil, err @@ -5019,8 +5123,11 @@ func (client *baseClient) SortReadOnly(key string) ([]Result[string], error) { // An Array of sorted elements. // // [valkey.io]: https://valkey.io/commands/sort_ro/ -func (client *baseClient) SortReadOnlyWithOptions(key string, options *options.SortOptions) ([]Result[string], error) { - optionArgs := options.ToArgs() +func (client *baseClient) SortReadOnlyWithOptions(key string, options options.SortOptions) ([]Result[string], error) { + optionArgs, err := options.ToArgs() + if err != nil { + return nil, err + } result, err := client.executeCommand(C.SortReadOnly, append([]string{key}, optionArgs...)) if err != nil { return nil, err @@ -5055,7 +5162,7 @@ func (client *baseClient) SortReadOnlyWithOptions(key string, options *options.S // // [valkey.io]: https://valkey.io/commands/sort/ func (client *baseClient) SortStore(key string, destination string) (int64, error) { - result, err := client.executeCommand(C.Sort, []string{key, "STORE", destination}) + result, err := client.executeCommand(C.Sort, []string{key, options.StoreKeyword, destination}) if err != nil { return defaultIntResponse, err } @@ -5084,7 +5191,8 @@ func (client *baseClient) SortStore(key string, destination string) (int64, erro // // key - The key of the list, set, or sorted set to be sorted. // destination - The key where the sorted result will be stored. -// sortOptions - The SortOptions type. +// +// opts - The [options.SortOptions] type. // // Return value: // @@ -5094,10 +5202,13 @@ func (client *baseClient) SortStore(key string, destination string) (int64, erro func (client *baseClient) SortStoreWithOptions( key string, destination string, - options *options.SortOptions, + opts options.SortOptions, ) (int64, error) { - optionArgs := options.ToArgs() - result, err := client.executeCommand(C.Sort, append([]string{key, "STORE", destination}, optionArgs...)) + optionArgs, err := opts.ToArgs() + if err != nil { + return defaultIntResponse, err + } + result, err := client.executeCommand(C.Sort, append([]string{key, options.StoreKeyword, destination}, optionArgs...)) if err != nil { return defaultIntResponse, err } @@ -5293,7 +5404,7 @@ func (client *baseClient) BitCount(key string) (int64, error) { // Returns zero if the key is missing as it is treated as an empty string. // // [valkey.io]: https://valkey.io/commands/bitcount/ -func (client *baseClient) BitCountWithOptions(key string, opts *options.BitCountOptions) (int64, error) { +func (client *baseClient) BitCountWithOptions(key string, opts options.BitCountOptions) (int64, error) { optionArgs, err := opts.ToArgs() if err != nil { return defaultIntResponse, err @@ -5331,7 +5442,7 @@ func (client *baseClient) XClaim( minIdleTime int64, ids []string, ) (map[string][][]string, error) { - return client.XClaimWithOptions(key, group, consumer, minIdleTime, ids, nil) + return client.XClaimWithOptions(key, group, consumer, minIdleTime, ids, *options.NewXClaimOptions()) } // Changes the ownership of a pending message. @@ -5359,16 +5470,14 @@ func (client *baseClient) XClaimWithOptions( consumer string, minIdleTime int64, ids []string, - opts *options.StreamClaimOptions, + opts options.XClaimOptions, ) (map[string][][]string, error) { args := append([]string{key, group, consumer, utils.IntToString(minIdleTime)}, ids...) - if opts != nil { - optionArgs, err := opts.ToArgs() - if err != nil { - return nil, err - } - args = append(args, optionArgs...) + optionArgs, err := opts.ToArgs() + if err != nil { + return nil, err } + args = append(args, optionArgs...) result, err := client.executeCommand(C.XClaim, args) if err != nil { return nil, err @@ -5402,7 +5511,7 @@ func (client *baseClient) XClaimJustId( minIdleTime int64, ids []string, ) ([]string, error) { - return client.XClaimJustIdWithOptions(key, group, consumer, minIdleTime, ids, nil) + return client.XClaimJustIdWithOptions(key, group, consumer, minIdleTime, ids, *options.NewXClaimOptions()) } // Changes the ownership of a pending message. This function returns an `array` with @@ -5430,17 +5539,15 @@ func (client *baseClient) XClaimJustIdWithOptions( consumer string, minIdleTime int64, ids []string, - opts *options.StreamClaimOptions, + opts options.XClaimOptions, ) ([]string, error) { args := append([]string{key, group, consumer, utils.IntToString(minIdleTime)}, ids...) - if opts != nil { - optionArgs, err := opts.ToArgs() - if err != nil { - return nil, err - } - args = append(args, optionArgs...) + optionArgs, err := opts.ToArgs() + if err != nil { + return nil, err } - args = append(args, options.JUST_ID_VALKEY_API) + args = append(args, optionArgs...) + args = append(args, options.JustIdKeyword) result, err := client.executeCommand(C.XClaim, args) if err != nil { return nil, err @@ -5495,9 +5602,9 @@ func (client *baseClient) Copy(source string, destination string) (bool, error) func (client *baseClient) CopyWithOptions( source string, destination string, - options *CopyOptions, + options options.CopyOptions, ) (bool, error) { - optionArgs, err := options.toArgs() + optionArgs, err := options.ToArgs() if err != nil { return defaultBoolResponse, err } @@ -5538,7 +5645,7 @@ func (client *baseClient) XRange( start options.StreamBoundary, end options.StreamBoundary, ) ([]XRangeResponse, error) { - return client.XRangeWithOptions(key, start, end, nil) + return client.XRangeWithOptions(key, start, end, *options.NewXRangeOptions()) } // Returns stream entries matching a given range of IDs. @@ -5566,16 +5673,14 @@ func (client *baseClient) XRangeWithOptions( key string, start options.StreamBoundary, end options.StreamBoundary, - opts *options.StreamRangeOptions, + opts options.XRangeOptions, ) ([]XRangeResponse, error) { args := []string{key, string(start), string(end)} - if opts != nil { - optionArgs, err := opts.ToArgs() - if err != nil { - return nil, err - } - args = append(args, optionArgs...) + optionArgs, err := opts.ToArgs() + if err != nil { + return nil, err } + args = append(args, optionArgs...) result, err := client.executeCommand(C.XRange, args) if err != nil { return nil, err @@ -5609,7 +5714,7 @@ func (client *baseClient) XRevRange( start options.StreamBoundary, end options.StreamBoundary, ) ([]XRangeResponse, error) { - return client.XRevRangeWithOptions(key, start, end, nil) + return client.XRevRangeWithOptions(key, start, end, *options.NewXRangeOptions()) } // Returns stream entries matching a given range of IDs in reverse order. @@ -5639,16 +5744,14 @@ func (client *baseClient) XRevRangeWithOptions( key string, start options.StreamBoundary, end options.StreamBoundary, - opts *options.StreamRangeOptions, + opts options.XRangeOptions, ) ([]XRangeResponse, error) { args := []string{key, string(start), string(end)} - if opts != nil { - optionArgs, err := opts.ToArgs() - if err != nil { - return nil, err - } - args = append(args, optionArgs...) + optionArgs, err := opts.ToArgs() + if err != nil { + return nil, err } + args = append(args, optionArgs...) result, err := client.executeCommand(C.XRevRange, args) if err != nil { return nil, err @@ -5832,7 +5935,10 @@ func (client *baseClient) Time() ([]string, error) { // // [valkey.io]: https://valkey.io/commands/zinter/ func (client *baseClient) ZInter(keys options.KeyArray) ([]string, error) { - args := keys.ToArgs() + args, err := keys.ToArgs() + if err != nil { + return nil, err + } result, err := client.executeCommand(C.ZInter, args) if err != nil { return nil, err @@ -5865,15 +5971,18 @@ func (client *baseClient) ZInter(keys options.KeyArray) ([]string, error) { // [valkey.io]: https://valkey.io/commands/zinter/ func (client *baseClient) ZInterWithScores( keysOrWeightedKeys options.KeysOrWeightedKeys, - zInterOptions *options.ZInterOptions, + zInterOptions options.ZInterOptions, ) (map[string]float64, error) { - args := keysOrWeightedKeys.ToArgs() + args, err := keysOrWeightedKeys.ToArgs() + if err != nil { + return nil, err + } optionsArgs, err := zInterOptions.ToArgs() if err != nil { return nil, err } args = append(args, optionsArgs...) - args = append(args, options.WithScores) + args = append(args, options.WithScoresKeyword) result, err := client.executeCommand(C.ZInter, args) if err != nil { return nil, err @@ -5881,10 +5990,85 @@ func (client *baseClient) ZInterWithScores( return handleStringDoubleMapResponse(result) } +// Computes the intersection of sorted sets given by the specified `keysOrWeightedKeys` +// and stores the result in `destination`. If `destination` already exists, it is overwritten. +// Otherwise, a new sorted set will be created. +// +// Note: +// +// When in cluster mode, all keys must map to the same hash slot. +// +// See [valkey.io] for details. +// +// Parameters: +// +// destination - The destination key for the result. +// keysOrWeightedKeys - The keys or weighted keys of the sorted sets, see - [options.KeysOrWeightedKeys]. +// - Use `options.NewKeyArray()` for keys only. +// - Use `options.NewWeightedKeys()` for weighted keys with score multipliers. +// +// Return value: +// +// The number of elements in the resulting sorted set stored at destination. +// +// [valkey.io]: https://valkey.io/commands/zinterstore/ +func (client *baseClient) ZInterStore(destination string, keysOrWeightedKeys options.KeysOrWeightedKeys) (int64, error) { + return client.ZInterStoreWithOptions(destination, keysOrWeightedKeys, *options.NewZInterOptions()) +} + +// Computes the intersection of sorted sets given by the specified `keysOrWeightedKeys` +// and stores the result in `destination`. If `destination` already exists, it is overwritten. +// Otherwise, a new sorted set will be created. +// +// Note: +// +// When in cluster mode, all keys must map to the same hash slot. +// +// See [valkey.io] for details. +// +// Parameters: +// +// destination - The destination key for the result. +// keysOrWeightedKeys - The keys or weighted keys of the sorted sets, see - [options.KeysOrWeightedKeys]. +// - Use `options.NewKeyArray()` for keys only. +// - Use `options.NewWeightedKeys()` for weighted keys with score multipliers. +// options - The options for the ZInterStore command, see - [options.ZInterOptions]. +// Optional `aggregate` option specifies the aggregation strategy to apply when combining the scores of +// elements. +// +// Return value: +// +// The number of elements in the resulting sorted set stored at destination. +// +// [valkey.io]: https://valkey.io/commands/zinterstore/ +func (client *baseClient) ZInterStoreWithOptions( + destination string, + keysOrWeightedKeys options.KeysOrWeightedKeys, + zInterOptions options.ZInterOptions, +) (int64, error) { + args, err := keysOrWeightedKeys.ToArgs() + if err != nil { + return defaultIntResponse, err + } + args = append([]string{destination}, args...) + optionsArgs, err := zInterOptions.ToArgs() + if err != nil { + return defaultIntResponse, err + } + args = append(args, optionsArgs...) + result, err := client.executeCommand(C.ZInterStore, args) + if err != nil { + return defaultIntResponse, err + } + return handleIntResponse(result) +} + // Returns the difference between the first sorted set and all the successive sorted sets. // To get the elements with their scores, see `ZDiffWithScores` // -// When in cluster mode, all `keys` must map to the same hash slot. +// Note: +// +// When in cluster mode, all `keys` must map to the same hash slot. // // Available for Valkey 6.2 and above. // @@ -5930,7 +6114,7 @@ func (client *baseClient) ZDiff(keys []string) ([]string, error) { func (client *baseClient) ZDiffWithScores(keys []string) (map[string]float64, error) { args := append([]string{}, strconv.Itoa(len(keys))) args = append(args, keys...) - result, err := client.executeCommand(C.ZDiff, append(args, options.WithScores)) + result, err := client.executeCommand(C.ZDiff, append(args, options.WithScoresKeyword)) if err != nil { return nil, err } @@ -5941,7 +6125,9 @@ func (client *baseClient) ZDiffWithScores(keys []string) (map[string]float64, er // `keys` and stores the difference as a sorted set to `destination`, // overwriting it if it already exists. Non-existent keys are treated as empty sets. // -// Note: When in cluster mode, `destination` and all `keys` must map to the same hash slot. +// Note: +// +// When in cluster mode, `destination` and all `keys` must map to the same hash slot. // // Available for Valkey 6.2 and above. // @@ -5968,77 +6154,6 @@ func (client *baseClient) ZDiffStore(destination string, keys []string) (int64, return handleIntResponse(result) } -// Computes the intersection of sorted sets given by the specified `keysOrWeightedKeys` -// and stores the result in `destination`. If `destination` already exists, it is overwritten. -// Otherwise, a new sorted set will be created. -// -// Note: -// -// When in cluster mode, all keys must map to the same hash slot. -// -// See [valkey.io] for details. -// -// Parameters: -// -// destination - The destination key for the result. -// keysOrWeightedKeys - The keys or weighted keys of the sorted sets, see - [options.KeysOrWeightedKeys]. -// - Use `options.NewKeyArray()` for keys only. -// - Use `options.NewWeightedKeys()` for weighted keys with score multipliers. -// -// Return value: -// -// The number of elements in the resulting sorted set stored at destination. -// -// [valkey.io]: https://valkey.io/commands/zinterstore/ -func (client *baseClient) ZInterStore(destination string, keysOrWeightedKeys options.KeysOrWeightedKeys) (int64, error) { - return client.ZInterStoreWithOptions(destination, keysOrWeightedKeys, nil) -} - -// Computes the intersection of sorted sets given by the specified `keysOrWeightedKeys` -// and stores the result in `destination`. If `destination` already exists, it is overwritten. -// Otherwise, a new sorted set will be created. -// -// Note: -// -// When in cluster mode, all keys must map to the same hash slot. -// -// See [valkey.io] for details. -// -// Parameters: -// -// destination - The destination key for the result. -// keysOrWeightedKeys - The keys or weighted keys of the sorted sets, see - [options.KeysOrWeightedKeys]. -// - Use `options.NewKeyArray()` for keys only. -// - Use `options.NewWeightedKeys()` for weighted keys with score multipliers. -// options - The options for the ZInterStore command, see - [options.ZInterOptions]. -// Optional `aggregate` option specifies the aggregation strategy to apply when combining the scores of -// elements. -// -// Return value: -// -// The number of elements in the resulting sorted set stored at destination. -// -// [valkey.io]: https://valkey.io/commands/zinterstore/ -func (client *baseClient) ZInterStoreWithOptions( - destination string, - keysOrWeightedKeys options.KeysOrWeightedKeys, - zInterOptions *options.ZInterOptions, -) (int64, error) { - args := append([]string{destination}, keysOrWeightedKeys.ToArgs()...) - if zInterOptions != nil { - optionsArgs, err := zInterOptions.ToArgs() - if err != nil { - return defaultIntResponse, err - } - args = append(args, optionsArgs...) - } - result, err := client.executeCommand(C.ZInterStore, args) - if err != nil { - return defaultIntResponse, err - } - return handleIntResponse(result) -} - // Returns the union of members from sorted sets specified by the given `keys`. // To get the elements with their scores, see `ZUnionWithScores`. // @@ -6060,7 +6175,10 @@ func (client *baseClient) ZInterStoreWithOptions( // // [valkey.io]: https://valkey.io/commands/zunion/ func (client *baseClient) ZUnion(keys options.KeyArray) ([]string, error) { - args := keys.ToArgs() + args, err := keys.ToArgs() + if err != nil { + return nil, err + } result, err := client.executeCommand(C.ZUnion, args) if err != nil { return nil, err @@ -6095,13 +6213,16 @@ func (client *baseClient) ZUnionWithScores( keysOrWeightedKeys options.KeysOrWeightedKeys, zUnionOptions *options.ZUnionOptions, ) (map[string]float64, error) { - args := keysOrWeightedKeys.ToArgs() + args, err := keysOrWeightedKeys.ToArgs() + if err != nil { + return nil, err + } optionsArgs, err := zUnionOptions.ToArgs() if err != nil { return nil, err } args = append(args, optionsArgs...) - args = append(args, options.WithScores) + args = append(args, options.WithScoresKeyword) result, err := client.executeCommand(C.ZUnion, args) if err != nil { return nil, err @@ -6169,7 +6290,11 @@ func (client *baseClient) ZUnionStoreWithOptions( keysOrWeightedKeys options.KeysOrWeightedKeys, zUnionOptions *options.ZUnionOptions, ) (int64, error) { - args := append([]string{destination}, keysOrWeightedKeys.ToArgs()...) + keysArgs, err := keysOrWeightedKeys.ToArgs() + if err != nil { + return defaultIntResponse, err + } + args := append([]string{destination}, keysArgs...) if zUnionOptions != nil { optionsArgs, err := zUnionOptions.ToArgs() if err != nil { diff --git a/go/api/bitmap_commands.go b/go/api/bitmap_commands.go index dda97ac921..6cdec5475e 100644 --- a/go/api/bitmap_commands.go +++ b/go/api/bitmap_commands.go @@ -16,7 +16,7 @@ type BitmapCommands interface { BitCount(key string) (int64, error) - BitCountWithOptions(key string, options *options.BitCountOptions) (int64, error) + BitCountWithOptions(key string, options options.BitCountOptions) (int64, error) BitField(key string, subCommands []options.BitFieldSubCommands) ([]Result[int64], error) diff --git a/go/api/bitmap_commands_test.go b/go/api/bitmap_commands_test.go index c85edd6a15..c1f8ed4310 100644 --- a/go/api/bitmap_commands_test.go +++ b/go/api/bitmap_commands_test.go @@ -94,11 +94,11 @@ func ExampleGlideClusterClient_BitCount() { func ExampleGlideClient_BitCountWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function - options := options.NewBitCountOptionsBuilder(). + options := options.NewBitCountOptions(). SetStart(1). SetEnd(1). SetBitmapIndexType(options.BYTE) - result, err := client.BitCountWithOptions("my_key", options) + result, err := client.BitCountWithOptions("my_key", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -110,11 +110,11 @@ func ExampleGlideClient_BitCountWithOptions() { func ExampleGlideClusterClient_BitCountWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function - options := options.NewBitCountOptionsBuilder(). + options := options.NewBitCountOptions(). SetStart(1). SetEnd(1). SetBitmapIndexType(options.BYTE) - result, err := client.BitCountWithOptions("my_key", options) + result, err := client.BitCountWithOptions("my_key", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } diff --git a/go/api/config/request_routing_config.go b/go/api/config/request_routing_config.go index 89c5cd8698..efd743bf23 100644 --- a/go/api/config/request_routing_config.go +++ b/go/api/config/request_routing_config.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/valkey-io/valkey-glide/go/api/errors" - "github.com/valkey-io/valkey-glide/go/protobuf" ) // Request routing basic interface. Please use one of the following: @@ -17,7 +16,6 @@ import ( // - [config.SlotKeyRoute] // - [config.ByAddressRoute] type Route interface { - ToRoutesProtobuf() (*protobuf.Routes, error) IsMultiNode() bool } @@ -38,20 +36,6 @@ const ( RandomRoute ) -func (simpleNodeRoute SimpleNodeRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { - simpleRouteProto, err := mapSimpleNodeRoute(simpleNodeRoute) - if err != nil { - return nil, err - } - - request := &protobuf.Routes{ - Value: &protobuf.Routes_SimpleRoutes{ - SimpleRoutes: simpleRouteProto, - }, - } - return request, nil -} - func (route SimpleNodeRoute) IsMultiNode() bool { return route != RandomRoute } @@ -61,19 +45,6 @@ func (snr SimpleNodeRoute) ToPtr() *Route { return &a } -func mapSimpleNodeRoute(simpleNodeRoute SimpleNodeRoute) (protobuf.SimpleRoutes, error) { - switch simpleNodeRoute { - case AllNodes: - return protobuf.SimpleRoutes_AllNodes, nil - case AllPrimaries: - return protobuf.SimpleRoutes_AllPrimaries, nil - case RandomRoute: - return protobuf.SimpleRoutes_Random, nil - default: - return protobuf.SimpleRoutes_Random, &errors.RequestError{Msg: "Invalid simple node route"} - } -} - // Defines type of the node being addressed. type SlotType int @@ -84,22 +55,11 @@ const ( SlotTypeReplica ) -func mapSlotType(slotType SlotType) (protobuf.SlotTypes, error) { - switch slotType { - case SlotTypePrimary: - return protobuf.SlotTypes_Primary, nil - case SlotTypeReplica: - return protobuf.SlotTypes_Replica, nil - default: - return protobuf.SlotTypes_Primary, &errors.RequestError{Msg: "Invalid slot type"} - } -} - // Request routing configuration overrides the [api.ReadFrom] connection configuration. // If SlotTypeReplica is used, the request will be routed to a replica, even if the strategy is ReadFrom [api.PreferReplica]. type SlotIdRoute struct { - slotType SlotType - slotID int32 + SlotType SlotType + SlotID int32 notMultiNode } @@ -107,61 +67,27 @@ type SlotIdRoute struct { // - slotId: Slot number. There are 16384 slots in a Valkey cluster, and each shard manages a slot range. Unless the slot is // known, it's better to route using [api.SlotTypePrimary]. func NewSlotIdRoute(slotType SlotType, slotId int32) *SlotIdRoute { - return &SlotIdRoute{slotType: slotType, slotID: slotId} -} - -func (slotIdRoute *SlotIdRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { - slotType, err := mapSlotType(slotIdRoute.slotType) - if err != nil { - return nil, err - } - - request := &protobuf.Routes{ - Value: &protobuf.Routes_SlotIdRoute{ - SlotIdRoute: &protobuf.SlotIdRoute{ - SlotType: slotType, - SlotId: slotIdRoute.slotID, - }, - }, - } - return request, nil + return &SlotIdRoute{SlotType: slotType, SlotID: slotId} } // Request routing configuration overrides the [api.ReadFrom] connection configuration. // If SlotTypeReplica is used, the request will be routed to a replica, even if the strategy is ReadFrom [api.PreferReplica]. type SlotKeyRoute struct { - slotType SlotType - slotKey string + SlotType SlotType + SlotKey string notMultiNode } // - slotType: Defines type of the node being addressed. // - slotKey: The request will be sent to nodes managing this key. func NewSlotKeyRoute(slotType SlotType, slotKey string) *SlotKeyRoute { - return &SlotKeyRoute{slotType: slotType, slotKey: slotKey} -} - -func (slotKeyRoute *SlotKeyRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { - slotType, err := mapSlotType(slotKeyRoute.slotType) - if err != nil { - return nil, err - } - - request := &protobuf.Routes{ - Value: &protobuf.Routes_SlotKeyRoute{ - SlotKeyRoute: &protobuf.SlotKeyRoute{ - SlotType: slotType, - SlotKey: slotKeyRoute.slotKey, - }, - }, - } - return request, nil + return &SlotKeyRoute{SlotType: slotType, SlotKey: slotKey} } // Routes a request to a node by its address. type ByAddressRoute struct { - host string - port int32 + Host string + Port int32 notMultiNode } @@ -170,7 +96,7 @@ type ByAddressRoute struct { // preferred endpoint as shown in the output of the CLUSTER SLOTS command. // - port: The port to access the node. If port is not provided, host is assumed to be in the format "address:port". func NewByAddressRoute(host string, port int32) *ByAddressRoute { - return &ByAddressRoute{host: host, port: port} + return &ByAddressRoute{Host: host, Port: port} } // Create a route using address string formatted as "address:port". @@ -193,17 +119,5 @@ func NewByAddressRouteWithHost(host string) (*ByAddressRoute, error) { } } - return &ByAddressRoute{host: split[0], port: int32(port)}, nil -} - -func (byAddressRoute *ByAddressRoute) ToRoutesProtobuf() (*protobuf.Routes, error) { - request := &protobuf.Routes{ - Value: &protobuf.Routes_ByAddressRoute{ - ByAddressRoute: &protobuf.ByAddressRoute{ - Host: byAddressRoute.host, - Port: byAddressRoute.port, - }, - }, - } - return request, nil + return &ByAddressRoute{Host: split[0], Port: int32(port)}, nil } diff --git a/go/api/connection_management_cluster_commands_test.go b/go/api/connection_management_cluster_commands_test.go index 101aebf3cc..9e6380ef9d 100644 --- a/go/api/connection_management_cluster_commands_test.go +++ b/go/api/connection_management_cluster_commands_test.go @@ -25,7 +25,7 @@ func ExampleGlideClusterClient_PingWithOptions() { PingOptions: &options.PingOptions{ Message: "hello", }, - Route: nil, + RouteOption: nil, } result, err := client.PingWithOptions(options) if err != nil { diff --git a/go/api/errors/errors.go b/go/api/errors/errors.go index 94bdcedf83..b974e4dab8 100644 --- a/go/api/errors/errors.go +++ b/go/api/errors/errors.go @@ -2,13 +2,6 @@ package errors -// #cgo LDFLAGS: -lglide_rs -// #cgo !windows LDFLAGS: -lm -// #cgo darwin LDFLAGS: -framework Security -// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/../rustbin/x86_64-unknown-linux-gnu -// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-unknown-linux-gnu -// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-apple-darwin -// #cgo LDFLAGS: -L../target/release // #include "../../lib.h" import "C" diff --git a/go/api/generic_base_commands.go b/go/api/generic_base_commands.go index 64214642c1..9cec14fbb2 100644 --- a/go/api/generic_base_commands.go +++ b/go/api/generic_base_commands.go @@ -16,19 +16,19 @@ type GenericBaseCommands interface { Expire(key string, seconds int64) (bool, error) - ExpireWithOptions(key string, seconds int64, expireCondition ExpireCondition) (bool, error) + ExpireWithOptions(key string, seconds int64, expireCondition options.ExpireCondition) (bool, error) ExpireAt(key string, unixTimestampInSeconds int64) (bool, error) - ExpireAtWithOptions(key string, unixTimestampInSeconds int64, expireCondition ExpireCondition) (bool, error) + ExpireAtWithOptions(key string, unixTimestampInSeconds int64, expireCondition options.ExpireCondition) (bool, error) PExpire(key string, milliseconds int64) (bool, error) - PExpireWithOptions(key string, milliseconds int64, expireCondition ExpireCondition) (bool, error) + PExpireWithOptions(key string, milliseconds int64, expireCondition options.ExpireCondition) (bool, error) PExpireAt(key string, unixTimestampInMilliSeconds int64) (bool, error) - PExpireAtWithOptions(key string, unixTimestampInMilliSeconds int64, expireCondition ExpireCondition) (bool, error) + PExpireAtWithOptions(key string, unixTimestampInMilliSeconds int64, expireCondition options.ExpireCondition) (bool, error) ExpireTime(key string) (int64, error) @@ -52,7 +52,7 @@ type GenericBaseCommands interface { Restore(key string, ttl int64, value string) (Result[string], error) - RestoreWithOptions(key string, ttl int64, value string, option *RestoreOptions) (Result[string], error) + RestoreWithOptions(key string, ttl int64, value string, option options.RestoreOptions) (Result[string], error) ObjectEncoding(key string) (Result[string], error) @@ -66,19 +66,19 @@ type GenericBaseCommands interface { Sort(key string) ([]Result[string], error) - SortWithOptions(key string, sortOptions *options.SortOptions) ([]Result[string], error) + SortWithOptions(key string, sortOptions options.SortOptions) ([]Result[string], error) SortStore(key string, destination string) (int64, error) - SortStoreWithOptions(key string, destination string, sortOptions *options.SortOptions) (int64, error) + SortStoreWithOptions(key string, destination string, sortOptions options.SortOptions) (int64, error) SortReadOnly(key string) ([]Result[string], error) - SortReadOnlyWithOptions(key string, sortOptions *options.SortOptions) ([]Result[string], error) + SortReadOnlyWithOptions(key string, sortOptions options.SortOptions) ([]Result[string], error) Wait(numberOfReplicas int64, timeout int64) (int64, error) Copy(source string, destination string) (bool, error) - CopyWithOptions(source string, destination string, option *CopyOptions) (bool, error) + CopyWithOptions(source string, destination string, option options.CopyOptions) (bool, error) } diff --git a/go/api/generic_base_commands_test.go b/go/api/generic_base_commands_test.go index cb4fa48f05..3686a4f5b9 100644 --- a/go/api/generic_base_commands_test.go +++ b/go/api/generic_base_commands_test.go @@ -120,7 +120,7 @@ func ExampleGlideClusterClient_Expire() { func ExampleGlideClient_ExpireWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.ExpireWithOptions("key", 1, HasNoExpiry) + result1, err := client.ExpireWithOptions("key", 1, options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -135,7 +135,7 @@ func ExampleGlideClient_ExpireWithOptions() { func ExampleGlideClusterClient_ExpireWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.ExpireWithOptions("key", 1, HasNoExpiry) + result1, err := client.ExpireWithOptions("key", 1, options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -180,7 +180,7 @@ func ExampleGlideClusterClient_ExpireAt() { func ExampleGlideClient_ExpireAtWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.ExpireAtWithOptions("key", time.Now().Unix()+1, HasNoExpiry) + result1, err := client.ExpireAtWithOptions("key", time.Now().Unix()+1, options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -195,7 +195,7 @@ func ExampleGlideClient_ExpireAtWithOptions() { func ExampleGlideClusterClient_ExpireAtWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.ExpireAtWithOptions("key", time.Now().Unix()+1, HasNoExpiry) + result1, err := client.ExpireAtWithOptions("key", time.Now().Unix()+1, options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -240,7 +240,7 @@ func ExampleGlideClusterClient_PExpire() { func ExampleGlideClient_PExpireWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.PExpireWithOptions("key", int64(5*1000), HasNoExpiry) + result1, err := client.PExpireWithOptions("key", int64(5*1000), options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -255,7 +255,7 @@ func ExampleGlideClient_PExpireWithOptions() { func ExampleGlideClusterClient_PExpireWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.PExpireWithOptions("key", int64(5*1000), HasNoExpiry) + result1, err := client.PExpireWithOptions("key", int64(5*1000), options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -300,7 +300,7 @@ func ExampleGlideClusterClient_PExpireAt() { func ExampleGlideClient_PExpireAtWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.PExpireAtWithOptions("key", time.Now().Unix()*1000, HasNoExpiry) + result1, err := client.PExpireAtWithOptions("key", time.Now().Unix()*1000, options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -315,7 +315,7 @@ func ExampleGlideClient_PExpireAtWithOptions() { func ExampleGlideClusterClient_PExpireAtWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.Set("key", "someValue") - result1, err := client.PExpireAtWithOptions("key", time.Now().Unix()*1000, HasNoExpiry) + result1, err := client.PExpireAtWithOptions("key", time.Now().Unix()*1000, options.HasNoExpiry) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -696,8 +696,8 @@ func ExampleGlideClient_RestoreWithOptions() { result, err := client.Set("key1", "someValue") dump, err := client.Dump("key1") result1, err := client.Del([]string{"key1"}) - result2, err := client.RestoreWithOptions("key1", 0, dump.Value(), - NewRestoreOptionsBuilder().SetReplace().SetABSTTL().SetEviction(FREQ, 10)) + opts := options.NewRestoreOptions().SetReplace().SetABSTTL().SetEviction(options.FREQ, 10) + result2, err := client.RestoreWithOptions("key1", 0, dump.Value(), *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -716,8 +716,8 @@ func ExampleGlideClusterClient_RestoreWithOptions() { result, err := client.Set("key1", "someValue") dump, err := client.Dump("key1") result1, err := client.Del([]string{"key1"}) - result2, err := client.RestoreWithOptions("key1", 0, dump.Value(), - NewRestoreOptionsBuilder().SetReplace().SetABSTTL().SetEviction(FREQ, 10)) + opts := options.NewRestoreOptions().SetReplace().SetABSTTL().SetEviction(options.FREQ, 10) + result2, err := client.RestoreWithOptions("key1", 0, dump.Value(), *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -929,7 +929,7 @@ func ExampleGlideClient_SortWithOptions() { client.Set("weight_item2", "1") client.Set("weight_item3", "2") result, err := client.LPush("key1", []string{"item1", "item2", "item3"}) - result1, err := client.SortWithOptions("key1", opts) + result1, err := client.SortWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -945,7 +945,7 @@ func ExampleGlideClusterClient_SortWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function opts := options.NewSortOptions().SetIsAlpha(false).SetOrderBy(options.ASC) result, err := client.LPush("key1", []string{"3", "1", "2"}) - result1, err := client.SortWithOptions("key1", opts) + result1, err := client.SortWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -994,7 +994,7 @@ func ExampleGlideClient_SortStoreWithOptions() { client.Set("weight_item2", "1") client.Set("weight_item3", "2") result, err := client.LPush("key1", []string{"item1", "item2", "item3"}) - result1, err := client.SortStoreWithOptions("key1", "key1_store", opts) + result1, err := client.SortStoreWithOptions("key1", "key1_store", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1010,7 +1010,7 @@ func ExampleGlideClusterClient_SortStoreWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function opts := options.NewSortOptions().SetIsAlpha(false).SetOrderBy(options.ASC) result, err := client.LPush("{key}1", []string{"3", "1", "2"}) - result1, err := client.SortStoreWithOptions("{key}1", "{key}2", opts) + result1, err := client.SortStoreWithOptions("{key}1", "{key}2", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1059,7 +1059,7 @@ func ExampleGlideClient_SortReadOnlyWithOptions() { client.Set("weight_item2", "1") client.Set("weight_item3", "2") result, err := client.LPush("key1", []string{"item1", "item2", "item3"}) - result1, err := client.SortReadOnlyWithOptions("key1", opts) + result1, err := client.SortReadOnlyWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1075,7 +1075,7 @@ func ExampleGlideClusterClient_SortReadOnlyWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function opts := options.NewSortOptions().SetIsAlpha(false).SetOrderBy(options.ASC) result, err := client.LPush("key1", []string{"3", "1", "2"}) - result1, err := client.SortReadOnlyWithOptions("key1", opts) + result1, err := client.SortReadOnlyWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1155,8 +1155,8 @@ func ExampleGlideClient_CopyWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function client.Set("key1", "someValue") - opts := NewCopyOptionsBuilder().SetReplace() - client.CopyWithOptions("key1", "key2", opts) + opts := options.NewCopyOptions().SetReplace() + client.CopyWithOptions("key1", "key2", *opts) result, err := client.Get("key2") if err != nil { @@ -1172,8 +1172,8 @@ func ExampleGlideClusterClient_CopyWithOptions() { client.Set("{key}1", "someValue") - opts := NewCopyOptionsBuilder().SetReplace() - client.CopyWithOptions("{key}1", "{key}2", opts) + opts := options.NewCopyOptions().SetReplace() + client.CopyWithOptions("{key}1", "{key}2", *opts) result, err := client.Get("{key}2") if err != nil { diff --git a/go/api/glide_client.go b/go/api/glide_client.go index eb0a19567e..3918b634fb 100644 --- a/go/api/glide_client.go +++ b/go/api/glide_client.go @@ -2,13 +2,6 @@ package api -// #cgo LDFLAGS: -lglide_rs -// #cgo !windows LDFLAGS: -lm -// #cgo darwin LDFLAGS: -framework Security -// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/../rustbin/x86_64-unknown-linux-gnu -// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-unknown-linux-gnu -// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-apple-darwin -// #cgo LDFLAGS: -L../target/release // #include "../lib.h" import "C" @@ -148,7 +141,7 @@ func (client *GlideClient) Select(index int64) (string, error) { // // [valkey.io]: https://valkey.io/commands/info/ func (client *GlideClient) Info() (string, error) { - return client.InfoWithOptions(InfoOptions{[]Section{}}) + return client.InfoWithOptions(options.InfoOptions{Sections: []options.Section{}}) } // Gets information and statistics about the server. @@ -164,8 +157,12 @@ func (client *GlideClient) Info() (string, error) { // A string containing the information for the sections requested. // // [valkey.io]: https://valkey.io/commands/info/ -func (client *GlideClient) InfoWithOptions(options InfoOptions) (string, error) { - result, err := client.executeCommand(C.Info, options.toArgs()) +func (client *GlideClient) InfoWithOptions(options options.InfoOptions) (string, error) { + optionArgs, err := options.ToArgs() + if err != nil { + return defaultStringResponse, err + } + result, err := client.executeCommand(C.Info, optionArgs) if err != nil { return defaultStringResponse, err } @@ -231,7 +228,11 @@ func (client *GlideClient) Ping() (string, error) { // // [valkey.io]: https://valkey.io/commands/ping/ func (client *GlideClient) PingWithOptions(pingOptions options.PingOptions) (string, error) { - result, err := client.executeCommand(C.Ping, pingOptions.ToArgs()) + optionArgs, err := pingOptions.ToArgs() + if err != nil { + return defaultStringResponse, err + } + result, err := client.executeCommand(C.Ping, optionArgs) if err != nil { return defaultStringResponse, err } diff --git a/go/api/glide_cluster_client.go b/go/api/glide_cluster_client.go index 9a6980394f..d897d73f28 100644 --- a/go/api/glide_cluster_client.go +++ b/go/api/glide_cluster_client.go @@ -2,13 +2,6 @@ package api -// #cgo LDFLAGS: -lglide_rs -// #cgo !windows LDFLAGS: -lm -// #cgo darwin LDFLAGS: -framework Security -// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/../rustbin/x86_64-unknown-linux-gnu -// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-unknown-linux-gnu -// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-apple-darwin -// #cgo LDFLAGS: -L../target/release // #include "../lib.h" import "C" @@ -115,9 +108,13 @@ func (client *GlideClusterClient) Info() (map[string]string, error) { // When a single node route is given, command returns a string containing the information for the sections requested. // // [valkey.io]: https://valkey.io/commands/info/ -func (client *GlideClusterClient) InfoWithOptions(options ClusterInfoOptions) (ClusterValue[string], error) { - if options.Route == nil { - response, err := client.executeCommand(C.Info, options.toArgs()) +func (client *GlideClusterClient) InfoWithOptions(options options.ClusterInfoOptions) (ClusterValue[string], error) { + optionArgs, err := options.ToArgs() + if err != nil { + return createEmptyClusterValue[string](), err + } + if options.RouteOption == nil || options.RouteOption.Route == nil { + response, err := client.executeCommand(C.Info, optionArgs) if err != nil { return createEmptyClusterValue[string](), err } @@ -127,11 +124,11 @@ func (client *GlideClusterClient) InfoWithOptions(options ClusterInfoOptions) (C } return createClusterMultiValue[string](data), nil } - response, err := client.executeCommandWithRoute(C.Info, options.toArgs(), *options.Route) + response, err := client.executeCommandWithRoute(C.Info, optionArgs, options.Route) if err != nil { return createEmptyClusterValue[string](), err } - if (*options.Route).IsMultiNode() { + if options.Route.IsMultiNode() { data, err := handleStringToStringMapResponse(response) if err != nil { return createEmptyClusterValue[string](), err @@ -182,7 +179,7 @@ func (client *GlideClusterClient) CustomCommandWithRoute( // // Return value: // -// Returns "PONG". +// Returns "PONG". // // [valkey.io]: https://valkey.io/commands/ping/ func (client *GlideClusterClient) Ping() (string, error) { @@ -198,7 +195,7 @@ func (client *GlideClusterClient) Ping() (string, error) { // // Parameters: // -// pingOptions - The PingOptions type. +// pingOptions - The [ClusterPingOptions] type. // // Return value: // @@ -206,27 +203,26 @@ func (client *GlideClusterClient) Ping() (string, error) { // // For example: // -// route := config.Route(config.RandomRoute) -// opts := options.ClusterPingOptions{ -// PingOptions: &options.PingOptions{ -// Message: "Hello", -// }, -// Route: &route, -// } +// route := options.RouteOption{config.RandomRoute} +// opts := options.ClusterPingOptions{ &options.PingOptions{ "Hello" }, &route } // result, err := clusterClient.PingWithOptions(opts) // fmt.Println(result) // Output: Hello // // [valkey.io]: https://valkey.io/commands/ping/ func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPingOptions) (string, error) { - if pingOptions.Route == nil { - response, err := client.executeCommand(C.Ping, pingOptions.ToArgs()) + args, err := pingOptions.ToArgs() + if err != nil { + return defaultStringResponse, err + } + if pingOptions.RouteOption == nil || pingOptions.RouteOption.Route == nil { + response, err := client.executeCommand(C.Ping, args) if err != nil { return defaultStringResponse, err } return handleStringResponse(response) } - response, err := client.executeCommandWithRoute(C.Ping, pingOptions.ToArgs(), *pingOptions.Route) + response, err := client.executeCommandWithRoute(C.Ping, args, pingOptions.Route) if err != nil { return defaultStringResponse, err } @@ -241,14 +237,13 @@ func (client *GlideClusterClient) PingWithOptions(pingOptions options.ClusterPin // // Parameters: // -// options - The TimeOptions type. +// options - The [RouteOption] type. // // Return value: // // The current server time as a String array with two elements: A UNIX TIME and the amount // of microseconds already elapsed in the current second. // The returned array is in a [UNIX TIME, Microseconds already elapsed] format. -// // [valkey.io]: https://valkey.io/commands/time/ func (client *GlideClusterClient) TimeWithOptions(opts options.RouteOption) (ClusterValue[[]string], error) { result, err := client.executeCommandWithRoute(C.Time, []string{}, opts.Route) @@ -260,11 +255,9 @@ func (client *GlideClusterClient) TimeWithOptions(opts options.RouteOption) (Clu // Returns the number of keys in the database. // -// See [valkey.io] for details. -// // Parameters: // -// options - The options for DBSize. +// options - The [RouteOption] type. // // Return value: // @@ -284,7 +277,7 @@ func (client *GlideClusterClient) DBSizeWithOptions(opts options.RouteOption) (i // // Parameters: // -// message - The provided message. +// echoOptions - The [ClusterEchoOptions] type. // // Return value: // @@ -292,12 +285,19 @@ func (client *GlideClusterClient) DBSizeWithOptions(opts options.RouteOption) (i // // [valkey.io]: https://valkey.io/commands/echo/ func (client *GlideClusterClient) EchoWithOptions(echoOptions options.ClusterEchoOptions) (ClusterValue[string], error) { - response, err := client.executeCommandWithRoute(C.Echo, echoOptions.ToArgs(), - echoOptions.RouteOption.Route) + args, err := echoOptions.ToArgs() + if err != nil { + return createEmptyClusterValue[string](), err + } + var route config.Route + if echoOptions.RouteOption != nil && echoOptions.RouteOption.Route != nil { + route = echoOptions.RouteOption.Route + } + response, err := client.executeCommandWithRoute(C.Echo, args, route) if err != nil { return createEmptyClusterValue[string](), err } - if echoOptions.RouteOption.Route != nil && + if echoOptions.RouteOption != nil && echoOptions.RouteOption.Route != nil && (echoOptions.RouteOption.Route).IsMultiNode() { data, err := handleStringToStringMapResponse(response) if err != nil { diff --git a/go/api/hash_commands.go b/go/api/hash_commands.go index 94c0b2a810..6a06d1de12 100644 --- a/go/api/hash_commands.go +++ b/go/api/hash_commands.go @@ -44,5 +44,5 @@ type HashCommands interface { HRandFieldWithCountWithValues(key string, count int64) ([][]string, error) - HScanWithOptions(key string, cursor string, options *options.HashScanOptions) (string, []string, error) + HScanWithOptions(key string, cursor string, options options.HashScanOptions) (string, []string, error) } diff --git a/go/api/hash_commands_test.go b/go/api/hash_commands_test.go index dc6701c471..27c8323570 100644 --- a/go/api/hash_commands_test.go +++ b/go/api/hash_commands_test.go @@ -736,8 +736,8 @@ func ExampleGlideClient_HScanWithOptions() { } result, err := client.HSet("my_hash", fields) - opts := options.NewHashScanOptionsBuilder().SetMatch("a") - resCursor, resCollection, err := client.HScanWithOptions("my_hash", "0", opts) + opts := options.NewHashScanOptions().SetMatch("a") + resCursor, resCollection, err := client.HScanWithOptions("my_hash", "0", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -762,8 +762,8 @@ func ExampleGlideClusterClient_HScanWithOptions() { } result, err := client.HSet("my_hash", fields) - opts := options.NewHashScanOptionsBuilder().SetMatch("a") - resCursor, resCollection, err := client.HScanWithOptions("my_hash", "0", opts) + opts := options.NewHashScanOptions().SetMatch("a") + resCursor, resCollection, err := client.HScanWithOptions("my_hash", "0", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } diff --git a/go/api/list_commands.go b/go/api/list_commands.go index d1f688bb5c..57dfa9754d 100644 --- a/go/api/list_commands.go +++ b/go/api/list_commands.go @@ -2,6 +2,10 @@ package api +import ( + "github.com/valkey-io/valkey-glide/go/api/options" +) + // Supports commands and transactions for the "List" group of commands for standalone and cluster clients. // // See [valkey.io] for details. @@ -16,11 +20,11 @@ type ListCommands interface { LPos(key string, element string) (Result[int64], error) - LPosWithOptions(key string, element string, options *LPosOptions) (Result[int64], error) + LPosWithOptions(key string, element string, options options.LPosOptions) (Result[int64], error) LPosCount(key string, element string, count int64) ([]int64, error) - LPosCountWithOptions(key string, element string, count int64, options *LPosOptions) ([]int64, error) + LPosCountWithOptions(key string, element string, count int64, options options.LPosOptions) ([]int64, error) RPush(key string, elements []string) (int64, error) @@ -38,7 +42,7 @@ type ListCommands interface { RPopCount(key string, count int64) ([]string, error) - LInsert(key string, insertPosition InsertPosition, pivot string, element string) (int64, error) + LInsert(key string, insertPosition options.InsertPosition, pivot string, element string) (int64, error) BLPop(keys []string, timeoutSecs float64) ([]string, error) @@ -48,28 +52,33 @@ type ListCommands interface { LPushX(key string, elements []string) (int64, error) - LMPop(keys []string, listDirection ListDirection) (map[string][]string, error) + LMPop(keys []string, listDirection options.ListDirection) (map[string][]string, error) - LMPopCount(keys []string, listDirection ListDirection, count int64) (map[string][]string, error) + LMPopCount(keys []string, listDirection options.ListDirection, count int64) (map[string][]string, error) - BLMPop(keys []string, listDirection ListDirection, timeoutSecs float64) (map[string][]string, error) + BLMPop(keys []string, listDirection options.ListDirection, timeoutSecs float64) (map[string][]string, error) BLMPopCount( keys []string, - listDirection ListDirection, + listDirection options.ListDirection, count int64, timeoutSecs float64, ) (map[string][]string, error) LSet(key string, index int64, element string) (string, error) - LMove(source string, destination string, whereFrom ListDirection, whereTo ListDirection) (Result[string], error) + LMove( + source string, + destination string, + whereFrom options.ListDirection, + whereTo options.ListDirection, + ) (Result[string], error) BLMove( source string, destination string, - whereFrom ListDirection, - whereTo ListDirection, + whereFrom options.ListDirection, + whereTo options.ListDirection, timeoutSecs float64, ) (Result[string], error) } diff --git a/go/api/list_commands_test.go b/go/api/list_commands_test.go index eda839fe15..8e8602340c 100644 --- a/go/api/list_commands_test.go +++ b/go/api/list_commands_test.go @@ -4,6 +4,8 @@ package api import ( "fmt" + + "github.com/valkey-io/valkey-glide/go/api/options" ) func ExampleGlideClient_LPush() { @@ -136,7 +138,7 @@ func ExampleGlideClient_LPosWithOptions() { result1, err := client.LPosWithOptions( "my_list", "e", - NewLPosOptionsBuilder().SetRank(2), + *options.NewLPosOptions().SetRank(2), ) // (Returns the second occurrence of the element "e") if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -155,7 +157,7 @@ func ExampleGlideClusterClient_LPosWithOptions() { result1, err := client.LPosWithOptions( "my_list", "e", - NewLPosOptionsBuilder().SetRank(2), + *options.NewLPosOptions().SetRank(2), ) // (Returns the second occurrence of the element "e") if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -201,9 +203,9 @@ func ExampleGlideClusterClient_LPosCount() { func ExampleGlideClient_LPosCountWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.RPush("my_list", []string{"a", "b", "c", "d", "e", "e", "e"}) - result1, err := client.LPosCountWithOptions("my_list", "e", 1, NewLPosOptionsBuilder().SetRank(2)) + result1, err := client.LPosCountWithOptions("my_list", "e", 1, *options.NewLPosOptions().SetRank(2)) result2, err := client.LPosCountWithOptions("my_list", "e", 3, - NewLPosOptionsBuilder().SetRank(2).SetMaxLen(1000)) + *options.NewLPosOptions().SetRank(2).SetMaxLen(1000)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -220,9 +222,9 @@ func ExampleGlideClient_LPosCountWithOptions() { func ExampleGlideClusterClient_LPosCountWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.RPush("my_list", []string{"a", "b", "c", "d", "e", "e", "e"}) - result1, err := client.LPosCountWithOptions("my_list", "e", 1, NewLPosOptionsBuilder().SetRank(2)) + result1, err := client.LPosCountWithOptions("my_list", "e", 1, *options.NewLPosOptions().SetRank(2)) result2, err := client.LPosCountWithOptions("my_list", "e", 3, - NewLPosOptionsBuilder().SetRank(2).SetMaxLen(1000)) + *options.NewLPosOptions().SetRank(2).SetMaxLen(1000)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -492,7 +494,7 @@ func ExampleGlideClient_LInsert() { var client *GlideClient = getExampleGlideClient() // example helper function client.Del([]string{"my_list"}) result, err := client.RPush("my_list", []string{"hello", "world"}) - result1, err := client.LInsert("my_list", Before, "world", "there") + result1, err := client.LInsert("my_list", options.Before, "world", "there") if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -508,7 +510,7 @@ func ExampleGlideClusterClient_LInsert() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function client.Del([]string{"my_list"}) result, err := client.RPush("my_list", []string{"hello", "world"}) - result1, err := client.LInsert("my_list", Before, "world", "there") + result1, err := client.LInsert("my_list", options.Before, "world", "there") if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -669,7 +671,7 @@ func ExampleGlideClusterClient_LPushX() { func ExampleGlideClient_LMPop() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.LMPop([]string{"my_list"}, Left) + result1, err := client.LMPop([]string{"my_list"}, options.Left) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -684,7 +686,7 @@ func ExampleGlideClient_LMPop() { func ExampleGlideClusterClient_LMPop() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.LMPop([]string{"my_list"}, Left) + result1, err := client.LMPop([]string{"my_list"}, options.Left) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -699,7 +701,7 @@ func ExampleGlideClusterClient_LMPop() { func ExampleGlideClient_LMPopCount() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.LMPopCount([]string{"my_list"}, Left, 2) + result1, err := client.LMPopCount([]string{"my_list"}, options.Left, 2) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -714,7 +716,7 @@ func ExampleGlideClient_LMPopCount() { func ExampleGlideClusterClient_LMPopCount() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.LMPopCount([]string{"my_list"}, Left, 2) + result1, err := client.LMPopCount([]string{"my_list"}, options.Left, 2) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -729,7 +731,7 @@ func ExampleGlideClusterClient_LMPopCount() { func ExampleGlideClient_BLMPop() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.BLMPop([]string{"my_list"}, Left, 0.1) + result1, err := client.BLMPop([]string{"my_list"}, options.Left, 0.1) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -744,7 +746,7 @@ func ExampleGlideClient_BLMPop() { func ExampleGlideClusterClient_BLMPop() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.BLMPop([]string{"my_list"}, Left, 0.1) + result1, err := client.BLMPop([]string{"my_list"}, options.Left, 0.1) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -759,7 +761,7 @@ func ExampleGlideClusterClient_BLMPop() { func ExampleGlideClient_BLMPopCount() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.BLMPopCount([]string{"my_list"}, Left, 2, 0.1) + result1, err := client.BLMPopCount([]string{"my_list"}, options.Left, 2, 0.1) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -774,7 +776,7 @@ func ExampleGlideClient_BLMPopCount() { func ExampleGlideClusterClient_BLMPopCount() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.LPush("my_list", []string{"one", "two", "three"}) - result1, err := client.BLMPopCount([]string{"my_list"}, Left, 2, 0.1) + result1, err := client.BLMPopCount([]string{"my_list"}, options.Left, 2, 0.1) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -828,7 +830,7 @@ func ExampleGlideClient_LMove() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.LPush("my_list1", []string{"two", "one"}) result1, err := client.LPush("my_list2", []string{"four", "three"}) - result2, err := client.LMove("my_list1", "my_list2", Left, Left) + result2, err := client.LMove("my_list1", "my_list2", options.Left, options.Left) result3, err := client.LRange("my_list1", 0, -1) result4, err := client.LRange("my_list2", 0, -1) if err != nil { @@ -852,7 +854,7 @@ func ExampleGlideClusterClient_LMove() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.LPush("{list}-1", []string{"two", "one"}) result1, err := client.LPush("{list}-2", []string{"four", "three"}) - result2, err := client.LMove("{list}-1", "{list}-2", Left, Left) + result2, err := client.LMove("{list}-1", "{list}-2", options.Left, options.Left) result3, err := client.LRange("{list}-1", 0, -1) result4, err := client.LRange("{list}-2", 0, -1) if err != nil { @@ -876,7 +878,7 @@ func ExampleGlideClient_BLMove() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.LPush("my_list1", []string{"two", "one"}) result1, err := client.LPush("my_list2", []string{"four", "three"}) - result2, err := client.BLMove("my_list1", "my_list2", Left, Left, 0.1) + result2, err := client.BLMove("my_list1", "my_list2", options.Left, options.Left, 0.1) result3, err := client.LRange("my_list1", 0, -1) result4, err := client.LRange("my_list2", 0, -1) if err != nil { @@ -900,7 +902,7 @@ func ExampleGlideClusterClient_BLMove() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.LPush("{list}-1", []string{"two", "one"}) result1, err := client.LPush("{list}-2", []string{"four", "three"}) - result2, err := client.BLMove("{list}-1", "{list}-2", Left, Left, 0.1) + result2, err := client.BLMove("{list}-1", "{list}-2", options.Left, options.Left, 0.1) result3, err := client.LRange("{list}-1", 0, -1) result4, err := client.LRange("{list}-2", 0, -1) if err != nil { diff --git a/go/api/options/base_scan_options.go b/go/api/options/base_scan_options.go index 77cf06da76..e9684048d8 100644 --- a/go/api/options/base_scan_options.go +++ b/go/api/options/base_scan_options.go @@ -13,7 +13,7 @@ type BaseScanOptions struct { count int64 } -func NewBaseScanOptionsBuilder() *BaseScanOptions { +func NewBaseScanOptions() *BaseScanOptions { return &BaseScanOptions{} } diff --git a/go/api/options/bitcount_options.go b/go/api/options/bitcount_options.go index acd6939db9..da688220db 100644 --- a/go/api/options/bitcount_options.go +++ b/go/api/options/bitcount_options.go @@ -20,7 +20,7 @@ type BitCountOptions struct { bitMapIndexType BitmapIndexType } -func NewBitCountOptionsBuilder() *BitCountOptions { +func NewBitCountOptions() *BitCountOptions { return &BitCountOptions{} } diff --git a/go/api/options/bitfield_options.go b/go/api/options/bitfield_options.go index 650c1c0d90..e55b5a5e8c 100644 --- a/go/api/options/bitfield_options.go +++ b/go/api/options/bitfield_options.go @@ -1,3 +1,5 @@ +// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 + package options import ( @@ -30,6 +32,13 @@ const ( FAIL OverflowType = "FAIL" ) +const ( + get string = "GET" + set string = "SET" + incrBy string = "INCRBY" + overFlow string = "OVERFLOW" +) + // BitFieldGet represents a GET operation to get the value in the binary // representation of the string stored in key based on EncType and Offset. type BitFieldGet struct { @@ -50,7 +59,7 @@ func NewBitFieldGet(encType EncType, bits int64, offset int64) *BitFieldGet { // ToArgs converts the GET command to arguments func (cmd *BitFieldGet) ToArgs() ([]string, error) { - args := []string{"GET"} + args := []string{get} args = append(args, string(cmd.EncType)+utils.IntToString(cmd.Bits)) if cmd.UseHash { args = append(args, "#"+utils.IntToString(cmd.Offset)) @@ -84,7 +93,7 @@ func NewBitFieldSet(encType EncType, bits int64, offset int64, value int64) *Bit // ToArgs converts the SET command to arguments func (cmd *BitFieldSet) ToArgs() ([]string, error) { - args := []string{"SET"} + args := []string{set} args = append(args, string(cmd.EncType)+utils.IntToString(cmd.Bits)) if cmd.UseHash { args = append(args, "#"+utils.IntToString(cmd.Offset)) @@ -117,7 +126,7 @@ func NewBitFieldIncrBy(encType EncType, bits int64, offset int64, increment int6 // ToArgs converts the INCRBY command to arguments func (cmd *BitFieldIncrBy) ToArgs() ([]string, error) { - args := []string{"INCRBY"} + args := []string{incrBy} args = append(args, string(cmd.EncType)+utils.IntToString(cmd.Bits)) if cmd.UseHash { args = append(args, "#"+utils.IntToString(cmd.Offset)) @@ -143,5 +152,5 @@ func NewBitFieldOverflow(overflow OverflowType) *BitFieldOverflow { // ToArgs converts the OVERFLOW command to arguments func (cmd *BitFieldOverflow) ToArgs() ([]string, error) { - return []string{"OVERFLOW", string(cmd.Overflow)}, nil + return []string{overFlow, string(cmd.Overflow)}, nil } diff --git a/go/api/command_options.go b/go/api/options/command_options.go similarity index 61% rename from go/api/command_options.go rename to go/api/options/command_options.go index a6bb290ed0..530777fbb9 100644 --- a/go/api/command_options.go +++ b/go/api/options/command_options.go @@ -1,11 +1,10 @@ // Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 -package api +package options import ( "strconv" - "github.com/valkey-io/valkey-glide/go/api/config" "github.com/valkey-io/valkey-glide/go/api/errors" "github.com/valkey-io/valkey-glide/go/utils" ) @@ -30,7 +29,7 @@ type SetOptions struct { Expiry *Expiry } -func NewSetOptionsBuilder() *SetOptions { +func NewSetOptions() *SetOptions { return &SetOptions{} } @@ -87,7 +86,7 @@ func (setOptions *SetOptions) SetExpiry(expiry *Expiry) *SetOptions { return setOptions } -func (opts *SetOptions) toArgs() ([]string, error) { +func (opts *SetOptions) ToArgs() ([]string, error) { args := []string{} var err error if opts.ConditionalSet != "" { @@ -126,7 +125,7 @@ type GetExOptions struct { Expiry *Expiry } -func NewGetExOptionsBuilder() *GetExOptions { +func NewGetExOptions() *GetExOptions { return &GetExOptions{} } @@ -135,7 +134,7 @@ func (getExOptions *GetExOptions) SetExpiry(expiry *Expiry) *GetExOptions { return getExOptions } -func (opts *GetExOptions) toArgs() ([]string, error) { +func (opts *GetExOptions) ToArgs() ([]string, error) { args := []string{} var err error @@ -153,37 +152,7 @@ func (opts *GetExOptions) toArgs() ([]string, error) { return args, err } -const returnOldValue = "GET" - -// A ConditionalSet defines whether a new value should be set or not. -type ConditionalSet string - -const ( - // OnlyIfExists only sets the key if it already exists. Equivalent to "XX" in the valkey API. - OnlyIfExists ConditionalSet = "XX" - // OnlyIfDoesNotExist only sets the key if it does not already exist. Equivalent to "NX" in the valkey API. - OnlyIfDoesNotExist ConditionalSet = "NX" - // OnlyIfEquals only sets the key if it already exists and the value is equal to the given value. Equivalent to "IFEQ" in - // the valkey API. - // - // since Valkey 8.1 and above. - OnlyIfEquals ConditionalSet = "IFEQ" -) - -type ExpireCondition string - -const ( - // HasExistingExpiry only sets the key if it already exists. Equivalent to "XX" in the valkey API. - HasExistingExpiry ExpireCondition = "XX" - // HasNoExpiry only sets the key if it does not already exist. Equivalent to "NX" in the valkey API. - HasNoExpiry ExpireCondition = "NX" - // NewExpiryGreaterThanCurrent only sets the key if its greater than current. Equivalent to "GT" in the valkey API. - NewExpiryGreaterThanCurrent ExpireCondition = "GT" - // NewExpiryLessThanCurrent only sets the key if its lesser than current. Equivalent to "LT" in the valkey API. - NewExpiryLessThanCurrent ExpireCondition = "LT" -) - -func (expireCondition ExpireCondition) toString() (string, error) { +func (expireCondition ExpireCondition) ToString() (string, error) { switch expireCondition { case HasExistingExpiry: return string(HasExistingExpiry), nil @@ -204,7 +173,7 @@ type Expiry struct { Count uint64 } -func NewExpiryBuilder() *Expiry { +func NewExpiry() *Expiry { return &Expiry{} } @@ -218,18 +187,6 @@ func (ex *Expiry) SetCount(count uint64) *Expiry { return ex } -// An ExpiryType is used to configure the type of expiration for a value. -type ExpiryType string - -const ( - KeepExisting ExpiryType = "KEEPTTL" // keep the existing expiration of the value - Seconds ExpiryType = "EX" // expire the value after [api.Expiry.Count] seconds - Milliseconds ExpiryType = "PX" // expire the value after [api.Expiry.Count] milliseconds - UnixSeconds ExpiryType = "EXAT" // expire the value after the Unix time specified by [api.Expiry.Count], in seconds - UnixMilliseconds ExpiryType = "PXAT" // expire the value after the Unix time specified by [api.Expiry.Count], in milliseconds - Persist ExpiryType = "PERSIST" // Remove the expiry associated with the key -) - // LPosOptions represents optional arguments for the [api.ListCommands.LPosWithOptions] and // [api.ListCommands.LPosCountWithOptions] commands. // @@ -247,7 +204,7 @@ type LPosOptions struct { MaxLen int64 } -func NewLPosOptionsBuilder() *LPosOptions { +func NewLPosOptions() *LPosOptions { return &LPosOptions{} } @@ -263,7 +220,7 @@ func (lposOptions *LPosOptions) SetMaxLen(maxLen int64) *LPosOptions { return lposOptions } -func (opts *LPosOptions) toArgs() []string { +func (opts *LPosOptions) ToArgs() ([]string, error) { args := []string{} if opts.IsRankSet { args = append(args, RankKeyword, utils.IntToString(opts.Rank)) @@ -273,31 +230,10 @@ func (opts *LPosOptions) toArgs() []string { args = append(args, MaxLenKeyword, utils.IntToString(opts.MaxLen)) } - return args + return args, nil } -const ( - CountKeyword string = "COUNT" // Valkey API keyword used to extract specific number of matching indices from a list. - RankKeyword string = "RANK" // Valkey API keyword use to determine the rank of the match to return. - MaxLenKeyword string = "MAXLEN" // Valkey API keyword used to determine the maximum number of list items to compare. - MatchKeyword string = "MATCH" // Valkey API keyword used to indicate the match filter. -) - -// A InsertPosition defines where to insert new elements into a list. -// -// See [valkey.io] -// -// [valkey.io]: https://valkey.io/commands/linsert/ -type InsertPosition string - -const ( - // Insert new element before the pivot. - Before InsertPosition = "BEFORE" - // Insert new element after the pivot. - After InsertPosition = "AFTER" -) - -func (insertPosition InsertPosition) toString() (string, error) { +func (insertPosition InsertPosition) ToString() (string, error) { switch insertPosition { case Before: return string(Before), nil @@ -308,17 +244,7 @@ func (insertPosition InsertPosition) toString() (string, error) { } } -// Enumeration representing element popping or adding direction for the [api.ListCommands]. -type ListDirection string - -const ( - // Represents the option that elements should be popped from or added to the left side of a list. - Left ListDirection = "LEFT" - // Represents the option that elements should be popped from or added to the right side of a list. - Right ListDirection = "RIGHT" -) - -func (listDirection ListDirection) toString() (string, error) { +func (listDirection ListDirection) ToString() (string, error) { switch listDirection { case Left: return string(Left), nil @@ -329,18 +255,7 @@ func (listDirection ListDirection) toString() (string, error) { } } -// Mandatory option for [ZMPop] and for [BZMPop]. -// Defines which elements to pop from the sorted set. -type ScoreFilter string - -const ( - // Pop elements with the highest scores. - MAX ScoreFilter = "MAX" - // Pop elements with the lowest scores. - MIN ScoreFilter = "MIN" -) - -func (scoreFilter ScoreFilter) toString() (string, error) { +func (scoreFilter ScoreFilter) ToString() (string, error) { switch scoreFilter { case MAX: return string(MAX), nil @@ -351,7 +266,7 @@ func (scoreFilter ScoreFilter) toString() (string, error) { } } -// Optional arguments to Restore(key string, ttl int64, value string, option *RestoreOptions) +// Optional arguments to Restore(key string, ttl int64, value string, option RestoreOptions) // // Note IDLETIME and FREQ modifiers cannot be set at the same time. // @@ -365,27 +280,19 @@ type RestoreOptions struct { eviction Eviction } -func NewRestoreOptionsBuilder() *RestoreOptions { +func NewRestoreOptions() *RestoreOptions { return &RestoreOptions{} } -const ( - // Subcommand string to replace existing key. - Replace_keyword = "REPLACE" - - // Subcommand string to represent absolute timestamp (in milliseconds) for TTL. - ABSTTL_keyword string = "ABSTTL" -) - // Custom setter methods to replace existing key. func (restoreOption *RestoreOptions) SetReplace() *RestoreOptions { - restoreOption.replace = Replace_keyword + restoreOption.replace = ReplaceKeyword return restoreOption } // Custom setter methods to represent absolute timestamp (in milliseconds) for TTL. func (restoreOption *RestoreOptions) SetABSTTL() *RestoreOptions { - restoreOption.absTTL = ABSTTL_keyword + restoreOption.absTTL = ABSTTLKeyword return restoreOption } @@ -397,15 +304,6 @@ type Eviction struct { Count int64 } -type EvictionType string - -const ( - // It represents the idletime of object - IDLETIME EvictionType = "IDLETIME" - // It represents the frequency of object - FREQ EvictionType = "FREQ" -) - // Custom setter methods set the idletime/frequency of object. func (restoreOption *RestoreOptions) SetEviction(evictionType EvictionType, count int64) *RestoreOptions { restoreOption.eviction.Type = evictionType @@ -413,7 +311,7 @@ func (restoreOption *RestoreOptions) SetEviction(evictionType EvictionType, coun return restoreOption } -func (opts *RestoreOptions) toArgs() ([]string, error) { +func (opts *RestoreOptions) ToArgs() ([]string, error) { args := []string{} var err error if opts.replace != "" { @@ -428,45 +326,6 @@ func (opts *RestoreOptions) toArgs() ([]string, error) { return args, err } -type Section string - -const ( - // SERVER: General information about the server - Server Section = "server" - // CLIENTS: Client connections section - Clients Section = "clients" - // MEMORY: Memory consumption related information - Memory Section = "memory" - // PERSISTENCE: RDB and AOF related information - Persistence Section = "persistence" - // STATS: General statistics - Stats Section = "stats" - // REPLICATION: Master/replica replication information - Replication Section = "replication" - // CPU: CPU consumption statistics - Cpu Section = "cpu" - // COMMANDSTATS: Valkey command statistics - Commandstats Section = "commandstats" - // LATENCYSTATS: Valkey command latency percentile distribution statistics - Latencystats Section = "latencystats" - // SENTINEL: Valkey Sentinel section (only applicable to Sentinel instances) - Sentinel Section = "sentinel" - // CLUSTER: Valkey Cluster section - Cluster Section = "cluster" - // MODULES: Modules section - Modules Section = "modules" - // KEYSPACE: Database related statistics - Keyspace Section = "keyspace" - // ERRORSTATS: Valkey error statistics - Errorstats Section = "errorstats" - // ALL: Return all sections (excluding module generated ones) - All Section = "all" - // DEFAULT: Return only the default set of sections - Default Section = "default" - // EVERYTHING: Includes all and modules - Everything Section = "everything" -) - // Optional arguments for `Info` for standalone client type InfoOptions struct { // A list of [Section] values specifying which sections of information to retrieve. @@ -478,24 +337,21 @@ type InfoOptions struct { // Optional arguments for `Info` for cluster client type ClusterInfoOptions struct { *InfoOptions - // Specifies the routing configuration for the command. - // The client will route the command to the nodes defined by `Route`. - // The command will be routed to all primary nodes, unless `Route` is provided. - Route *config.Route + *RouteOption } -func (opts *InfoOptions) toArgs() []string { +func (opts *InfoOptions) ToArgs() ([]string, error) { if opts == nil { - return []string{} + return []string{}, nil } args := make([]string, 0, len(opts.Sections)) for _, section := range opts.Sections { args = append(args, string(section)) } - return args + return args, nil } -// Optional arguments to Copy(source string, destination string, option *CopyOptions) +// Optional arguments to Copy(source string, destination string, option CopyOptions) // // [valkey.io]: https://valkey.io/commands/Copy/ type CopyOptions struct { @@ -505,7 +361,7 @@ type CopyOptions struct { dbDestination int64 } -func NewCopyOptionsBuilder() *CopyOptions { +func NewCopyOptions() *CopyOptions { return &CopyOptions{replace: false} } @@ -521,14 +377,33 @@ func (copyOption *CopyOptions) SetDBDestination(destinationDB int64) *CopyOption return copyOption } -func (opts *CopyOptions) toArgs() ([]string, error) { +func (opts *CopyOptions) ToArgs() ([]string, error) { args := []string{} var err error if opts.replace { - args = append(args, string("REPLACE")) + args = append(args, string(ReplaceKeyword)) } if opts.dbDestination >= 0 { args = append(args, "DB", utils.IntToString(opts.dbDestination)) } return args, err } + +// Optional arguments for `ZPopMin` and `ZPopMax` commands. +type ZPopOptions struct { + count int64 +} + +func NewZPopOptions() *ZPopOptions { + return &ZPopOptions{} +} + +// The maximum number of popped elements. If not specified, pops one member. +func (opts *ZPopOptions) SetCount(count int64) *ZPopOptions { + opts.count = count + return opts +} + +func (opts *ZPopOptions) ToArgs() ([]string, error) { + return []string{utils.IntToString(opts.count)}, nil +} diff --git a/go/api/options/constants.go b/go/api/options/constants.go index 13040e868b..55ce62452b 100644 --- a/go/api/options/constants.go +++ b/go/api/options/constants.go @@ -3,16 +3,37 @@ package options const ( - CountKeyword string = "COUNT" // Valkey API keyword used to extract specific number of matching indices from a list. - FullKeyword string = "FULL" // Valkey API keyword used in XINFO STREAM - MatchKeyword string = "MATCH" // Valkey API keyword used to indicate the match filter. - NoValue string = "NOVALUE" // Valkey API keyword for the no value option for hcsan command. - WithScore string = "WITHSCORE" // Valkey API keyword for the with score option for zrank and zrevrank commands. - WithScores string = "WITHSCORES" // Valkey API keyword for ZRandMember and ZDiff command to return scores along with members. - NoScores string = "NOSCORES" // Valkey API keyword for the no scores option for zscan command. - WithValues string = "WITHVALUES" // Valkey API keyword to query hash values along their names in `HRANDFIELD`. - AggregateKeyWord string = "AGGREGATE" // Valkey API keyword for the aggregate option for multiple commands. - WeightsKeyword string = "WEIGHTS" // Valkey API keyword for the weights option for multiple commands. + CountKeyword string = "COUNT" // Valkey API keyword used to extract specific number of matching indices from a list. + FullKeyword string = "FULL" // Valkey API keyword used in XINFO STREAM + MatchKeyword string = "MATCH" // Valkey API keyword used to indicate the match filter. + NoValueKeyword string = "NOVALUE" // Valkey API keyword for the no value option for hcsan command. + WithScoreKeyword string = "WITHSCORE" // Valkey API keyword for the with score option for zrank and zrevrank commands. + WithScoresKeyword string = "WITHSCORES" // Valkey API keyword for ZRandMember and ZDiff command to return scores along with members. + NoScoresKeyword string = "NOSCORES" // Valkey API keyword for the no scores option for zscan command. + WithValuesKeyword string = "WITHVALUES" // Valkey API keyword to query hash values along their names in `HRANDFIELD`. + AggregateKeyWord string = "AGGREGATE" // Valkey API keyword for the aggregate option for multiple commands. + WeightsKeyword string = "WEIGHTS" // Valkey API keyword for the weights option for multiple commands. + RankKeyword string = "RANK" // Valkey API keyword use to determine the rank of the match to return. + MaxLenKeyword string = "MAXLEN" // Valkey API keyword used to determine the maximum number of list items to compare. + ReplaceKeyword string = "REPLACE" // Subcommand string to replace existing key. + ABSTTLKeyword string = "ABSTTL" // Subcommand string to represent absolute timestamp (in milliseconds) for TTL. + StoreKeyword string = "STORE" + DbKeyword string = "DB" + /// Valkey API keywords for stream commands + IdleKeyword string = "IDLE" // ValKey API string to designate IDLE time in milliseconds + TimeKeyword string = "TIME" // ValKey API string to designate TIME time in unix-milliseconds + RetryCountKeyword string = "RETRYCOUNT" // ValKey API string to designate RETRYCOUNT + ForceKeyword string = "FORCE" // ValKey API string to designate FORCE + JustIdKeyword string = "JUSTID" // ValKey API string to designate JUSTID + EntriesReadKeyword string = "ENTRIESREAD" + MakeStreamKeyword string = "MKSTREAM" + NoMakeStreamKeyword string = "NOMKSTREAM" + BlockKeyword string = "BLOCK" + NoAckKeyword string = "NOACK" + LimitKeyword string = "LIMIT" + MinIdKeyword string = "MINID" + GroupKeyword string = "GROUP" + StreamsKeyword string = "STREAMS" ) type InfBoundary string @@ -23,3 +44,135 @@ const ( // The lowest bound in the sorted set NegativeInfinity InfBoundary = "-" ) + +const returnOldValue = "GET" + +// A ConditionalSet defines whether a new value should be set or not. +type ConditionalSet string + +const ( + // OnlyIfExists only sets the key if it already exists. Equivalent to "XX" in the valkey API. + OnlyIfExists ConditionalSet = "XX" + // OnlyIfDoesNotExist only sets the key if it does not already exist. Equivalent to "NX" in the valkey API. + OnlyIfDoesNotExist ConditionalSet = "NX" + // OnlyIfEquals only sets the key if it already exists and the value is equal to the given value. Equivalent to "IFEQ" in + // the valkey API. + // + // since Valkey 8.1 and above. + OnlyIfEquals ConditionalSet = "IFEQ" +) + +type ExpireCondition string + +const ( + // HasExistingExpiry only sets the key if it already exists. Equivalent to "XX" in the valkey API. + HasExistingExpiry ExpireCondition = "XX" + // HasNoExpiry only sets the key if it does not already exist. Equivalent to "NX" in the valkey API. + HasNoExpiry ExpireCondition = "NX" + // NewExpiryGreaterThanCurrent only sets the key if its greater than current. Equivalent to "GT" in the valkey API. + NewExpiryGreaterThanCurrent ExpireCondition = "GT" + // NewExpiryLessThanCurrent only sets the key if its lesser than current. Equivalent to "LT" in the valkey API. + NewExpiryLessThanCurrent ExpireCondition = "LT" +) + +// An ExpiryType is used to configure the type of expiration for a value. +type ExpiryType string + +const ( + // Keep the existing expiration of the value. + KeepExisting ExpiryType = "KEEPTTL" + // Expire the value after [options.Expiry.Count] seconds + Seconds ExpiryType = "EX" + // Expire the value after [options.Expiry.Count] milliseconds. + Milliseconds ExpiryType = "PX" + // Expire the value after the Unix time specified by [options.Expiry.Count], in seconds. + UnixSeconds ExpiryType = "EXAT" + // Expire the value after the Unix time specified by [options.Expiry.Count], in milliseconds. + UnixMilliseconds ExpiryType = "PXAT" + // Remove the expiry associated with the key. + Persist ExpiryType = "PERSIST" +) + +// A InsertPosition defines where to insert new elements into a list. +// +// See [valkey.io] +// +// [valkey.io]: https://valkey.io/commands/linsert/ +type InsertPosition string + +const ( + // Insert new element before the pivot. + Before InsertPosition = "BEFORE" + // Insert new element after the pivot. + After InsertPosition = "AFTER" +) + +// Enumeration representing element popping or adding direction for the [api.ListCommands]. +type ListDirection string + +const ( + // Represents the option that elements should be popped from or added to the left side of a list. + Left ListDirection = "LEFT" + // Represents the option that elements should be popped from or added to the right side of a list. + Right ListDirection = "RIGHT" +) + +// Mandatory parameter for [ZMPop] and for [BZMPop]. +// Defines which elements to pop from the sorted set. +type ScoreFilter string + +const ( + // Pop elements with the highest scores. + MAX ScoreFilter = "MAX" + // Pop elements with the lowest scores. + MIN ScoreFilter = "MIN" +) + +type EvictionType string + +const ( + // It represents the idletime of object. + IDLETIME EvictionType = "IDLETIME" + // It represents the frequency of object. + FREQ EvictionType = "FREQ" +) + +// Enumeration representing information section which could be queried by `INFO` command. +type Section string + +const ( + // SERVER: General information about the server + Server Section = "server" + // CLIENTS: Client connections section + Clients Section = "clients" + // MEMORY: Memory consumption related information + Memory Section = "memory" + // PERSISTENCE: RDB and AOF related information + Persistence Section = "persistence" + // STATS: General statistics + Stats Section = "stats" + // REPLICATION: Master/replica replication information + Replication Section = "replication" + // CPU: CPU consumption statistics + Cpu Section = "cpu" + // COMMANDSTATS: Valkey command statistics + Commandstats Section = "commandstats" + // LATENCYSTATS: Valkey command latency percentile distribution statistics + Latencystats Section = "latencystats" + // SENTINEL: Valkey Sentinel section (only applicable to Sentinel instances) + Sentinel Section = "sentinel" + // CLUSTER: Valkey Cluster section + Cluster Section = "cluster" + // MODULES: Modules section + Modules Section = "modules" + // KEYSPACE: Database related statistics + Keyspace Section = "keyspace" + // ERRORSTATS: Valkey error statistics + Errorstats Section = "errorstats" + // ALL: Return all sections (excluding module generated ones) + All Section = "all" + // DEFAULT: Return only the default set of sections + Default Section = "default" + // EVERYTHING: Includes all and modules + Everything Section = "everything" +) diff --git a/go/api/options/echo_options.go b/go/api/options/echo_options.go index 383f46a6ce..2b56f6ec5e 100644 --- a/go/api/options/echo_options.go +++ b/go/api/options/echo_options.go @@ -10,18 +10,16 @@ type EchoOptions struct { // Optional arguments for `Echo` for cluster client type ClusterEchoOptions struct { *EchoOptions - // Specifies the routing configuration for the command. - // The client will route the command to the nodes defined by *Route*. *RouteOption } -func (opts *EchoOptions) ToArgs() []string { +func (opts *EchoOptions) ToArgs() ([]string, error) { if opts == nil { - return []string{} + return []string{}, nil } args := []string{} if opts.Message != "" { args = append(args, opts.Message) } - return args + return args, nil } diff --git a/go/api/options/hscan_options.go b/go/api/options/hscan_options.go index a90b2d369a..c3f12b864d 100644 --- a/go/api/options/hscan_options.go +++ b/go/api/options/hscan_options.go @@ -8,7 +8,7 @@ type HashScanOptions struct { noValue bool } -func NewHashScanOptionsBuilder() *HashScanOptions { +func NewHashScanOptions() *HashScanOptions { return &HashScanOptions{} } @@ -37,7 +37,7 @@ func (options *HashScanOptions) ToArgs() ([]string, error) { args = append(args, baseArgs...) if options.noValue { - args = append(args, NoValue) + args = append(args, NoValueKeyword) } return args, err } diff --git a/go/api/options/ping_options.go b/go/api/options/ping_options.go index 984de736d5..c9d02babe6 100644 --- a/go/api/options/ping_options.go +++ b/go/api/options/ping_options.go @@ -2,10 +2,6 @@ package options -import ( - "github.com/valkey-io/valkey-glide/go/api/config" -) - // Optional arguments for `Ping` for standalone client type PingOptions struct { Message string @@ -14,18 +10,16 @@ type PingOptions struct { // Optional arguments for `Ping` for cluster client type ClusterPingOptions struct { *PingOptions - // Specifies the routing configuration for the command. - // The client will route the command to the nodes defined by *Route*. - Route *config.Route + *RouteOption } -func (opts *PingOptions) ToArgs() []string { +func (opts *PingOptions) ToArgs() ([]string, error) { if opts == nil { - return []string{} + return []string{}, nil } args := []string{} if opts.Message != "" { args = append(args, opts.Message) } - return args + return args, nil } diff --git a/go/api/options/sort_options.go b/go/api/options/sort_options.go index 935c82956a..e0ea2f3dfa 100644 --- a/go/api/options/sort_options.go +++ b/go/api/options/sort_options.go @@ -100,7 +100,7 @@ func (opts *SortOptions) AddGetPattern(getPattern string) *SortOptions { } // ToArgs creates the arguments to be used in SORT and SORT_RO commands. -func (opts *SortOptions) ToArgs() []string { +func (opts *SortOptions) ToArgs() ([]string, error) { var args []string if opts.SortLimit != nil { @@ -127,5 +127,5 @@ func (opts *SortOptions) ToArgs() []string { for _, getPattern := range opts.GetPatterns { args = append(args, GET_COMMAND_STRING, getPattern) } - return args + return args, nil } diff --git a/go/api/options/stream_options.go b/go/api/options/stream_options.go index 26e9e2ebe6..760a1b6003 100644 --- a/go/api/options/stream_options.go +++ b/go/api/options/stream_options.go @@ -48,7 +48,7 @@ func (xao *XAddOptions) SetTrimOptions(options *XTrimOptions) *XAddOptions { func (xao *XAddOptions) ToArgs() ([]string, error) { args := []string{} if xao.makeStream == triStateBoolFalse { - args = append(args, "NOMKSTREAM") + args = append(args, NoMakeStreamKeyword) } if xao.trimOptions != nil { moreArgs, err := xao.trimOptions.ToArgs() @@ -75,12 +75,12 @@ type XTrimOptions struct { // Option to trim the stream according to minimum ID. func NewXTrimOptionsWithMinId(threshold string) *XTrimOptions { - return &XTrimOptions{threshold: threshold, method: "MINID"} + return &XTrimOptions{threshold: threshold, method: MinIdKeyword} } // Option to trim the stream according to maximum stream length. func NewXTrimOptionsWithMaxLen(threshold int64) *XTrimOptions { - return &XTrimOptions{threshold: utils.IntToString(threshold), method: "MAXLEN"} + return &XTrimOptions{threshold: utils.IntToString(threshold), method: MaxLenKeyword} } // Match exactly on the threshold. @@ -111,23 +111,31 @@ func (xTrimOptions *XTrimOptions) ToArgs() ([]string, error) { } args = append(args, xTrimOptions.threshold) if xTrimOptions.limit > 0 { - args = append(args, "LIMIT", utils.IntToString(xTrimOptions.limit)) + args = append(args, LimitKeyword, utils.IntToString(xTrimOptions.limit)) } return args, nil } // Optional arguments for `XAutoClaim` in [StreamCommands] type XAutoClaimOptions struct { - count int64 + count *int64 } -// Option to trim the stream according to minimum ID. -func NewXAutoClaimOptionsWithCount(count int64) *XAutoClaimOptions { - return &XAutoClaimOptions{count} +func NewXAutoClaimOptions() *XAutoClaimOptions { + return &XAutoClaimOptions{nil} +} + +// Set the number of claimed entries. +func (xacp *XAutoClaimOptions) SetCount(count int64) *XAutoClaimOptions { + xacp.count = &count + return xacp } func (xacp *XAutoClaimOptions) ToArgs() ([]string, error) { - return []string{"COUNT", utils.IntToString(xacp.count)}, nil + if xacp.count == nil { + return []string{}, nil + } + return []string{CountKeyword, utils.IntToString(*xacp.count)}, nil } // Optional arguments for `XRead` in [StreamCommands] @@ -156,10 +164,10 @@ func (xro *XReadOptions) SetBlock(block int64) *XReadOptions { func (xro *XReadOptions) ToArgs() ([]string, error) { args := []string{} if xro.count >= 0 { - args = append(args, "COUNT", utils.IntToString(xro.count)) + args = append(args, CountKeyword, utils.IntToString(xro.count)) } if xro.block >= 0 { - args = append(args, "BLOCK", utils.IntToString(xro.block)) + args = append(args, BlockKeyword, utils.IntToString(xro.block)) } return args, nil } @@ -198,13 +206,13 @@ func (xrgo *XReadGroupOptions) SetNoAck() *XReadGroupOptions { func (xrgo *XReadGroupOptions) ToArgs() ([]string, error) { args := []string{} if xrgo.count >= 0 { - args = append(args, "COUNT", utils.IntToString(xrgo.count)) + args = append(args, CountKeyword, utils.IntToString(xrgo.count)) } if xrgo.block >= 0 { - args = append(args, "BLOCK", utils.IntToString(xrgo.block)) + args = append(args, BlockKeyword, utils.IntToString(xrgo.block)) } if xrgo.noAck { - args = append(args, "NOACK") + args = append(args, NoAckKeyword) } return args, nil } @@ -220,11 +228,11 @@ type XPendingOptions struct { // Create new empty `XPendingOptions`. The `start`, `end` and `count` arguments are required. func NewXPendingOptions(start string, end string, count int64) *XPendingOptions { - options := &XPendingOptions{} + options := XPendingOptions{} options.start = start options.end = end options.count = count - return options + return &options } // SetMinIdleTime sets the minimum idle time for the XPendingOptions. @@ -247,7 +255,7 @@ func (xpo *XPendingOptions) ToArgs() ([]string, error) { args := []string{} if xpo.minIdleTime > 0 { - args = append(args, "IDLE") + args = append(args, IdleKeyword) args = append(args, utils.IntToString(xpo.minIdleTime)) } @@ -265,12 +273,12 @@ func (xpo *XPendingOptions) ToArgs() ([]string, error) { // Optional arguments for `XGroupCreate` in [StreamCommands] type XGroupCreateOptions struct { mkStream bool - entriesRead int64 + entriesRead *int64 } // Create new empty `XGroupCreateOptions` func NewXGroupCreateOptions() *XGroupCreateOptions { - return &XGroupCreateOptions{false, -1} + return &XGroupCreateOptions{false, nil} } // Once set and if the stream doesn't exist, creates a new stream with a length of `0`. @@ -280,7 +288,7 @@ func (xgco *XGroupCreateOptions) SetMakeStream() *XGroupCreateOptions { } func (xgco *XGroupCreateOptions) SetEntriesRead(entriesRead int64) *XGroupCreateOptions { - xgco.entriesRead = entriesRead + xgco.entriesRead = &entriesRead return xgco } @@ -289,11 +297,11 @@ func (xgco *XGroupCreateOptions) ToArgs() ([]string, error) { // if minIdleTime is set, we need to add an `IDLE` argument along with the minIdleTime if xgco.mkStream { - args = append(args, "MKSTREAM") + args = append(args, MakeStreamKeyword) } - if xgco.entriesRead > -1 { - args = append(args, "ENTRIESREAD", utils.IntToString(xgco.entriesRead)) + if xgco.entriesRead != nil { + args = append(args, EntriesReadKeyword, utils.IntToString(*xgco.entriesRead)) } return args, nil @@ -321,79 +329,65 @@ func (xgsio *XGroupSetIdOptions) ToArgs() ([]string, error) { var args []string if xgsio.entriesRead > -1 { - args = append(args, "ENTRIESREAD", utils.IntToString(xgsio.entriesRead)) + args = append(args, EntriesReadKeyword, utils.IntToString(xgsio.entriesRead)) } return args, nil } // Optional arguments for `XClaim` in [StreamCommands] -type StreamClaimOptions struct { +type XClaimOptions struct { idleTime int64 idleUnixTime int64 retryCount int64 isForce bool } -func NewStreamClaimOptions() *StreamClaimOptions { - return &StreamClaimOptions{} +func NewXClaimOptions() *XClaimOptions { + return &XClaimOptions{} } // Set the idle time in milliseconds. -func (sco *StreamClaimOptions) SetIdleTime(idleTime int64) *StreamClaimOptions { - sco.idleTime = idleTime - return sco +func (xco *XClaimOptions) SetIdleTime(idleTime int64) *XClaimOptions { + xco.idleTime = idleTime + return xco } // Set the idle time in unix-milliseconds. -func (sco *StreamClaimOptions) SetIdleUnixTime(idleUnixTime int64) *StreamClaimOptions { - sco.idleUnixTime = idleUnixTime - return sco +func (xco *XClaimOptions) SetIdleUnixTime(idleUnixTime int64) *XClaimOptions { + xco.idleUnixTime = idleUnixTime + return xco } // Set the retry count. -func (sco *StreamClaimOptions) SetRetryCount(retryCount int64) *StreamClaimOptions { - sco.retryCount = retryCount - return sco +func (xco *XClaimOptions) SetRetryCount(retryCount int64) *XClaimOptions { + xco.retryCount = retryCount + return xco } // Set the force flag. -func (sco *StreamClaimOptions) SetForce() *StreamClaimOptions { - sco.isForce = true - return sco +func (xco *XClaimOptions) SetForce() *XClaimOptions { + xco.isForce = true + return xco } -// Valkey API keywords for stream claim options -const ( - // ValKey API string to designate IDLE time in milliseconds - IDLE_VALKEY_API string = "IDLE" - // ValKey API string to designate TIME time in unix-milliseconds - TIME_VALKEY_API string = "TIME" - // ValKey API string to designate RETRYCOUNT - RETRY_COUNT_VALKEY_API string = "RETRYCOUNT" - // ValKey API string to designate FORCE - FORCE_VALKEY_API string = "FORCE" - // ValKey API string to designate JUSTID - JUST_ID_VALKEY_API string = "JUSTID" -) - -func (sco *StreamClaimOptions) ToArgs() ([]string, error) { +func (sco *XClaimOptions) ToArgs() ([]string, error) { optionArgs := []string{} if sco.idleTime > 0 { - optionArgs = append(optionArgs, IDLE_VALKEY_API, utils.IntToString(sco.idleTime)) + optionArgs = append(optionArgs, IdleKeyword, utils.IntToString(sco.idleTime)) } if sco.idleUnixTime > 0 { - optionArgs = append(optionArgs, TIME_VALKEY_API, utils.IntToString(sco.idleUnixTime)) + optionArgs = append(optionArgs, TimeKeyword, utils.IntToString(sco.idleUnixTime)) } if sco.retryCount > 0 { - optionArgs = append(optionArgs, RETRY_COUNT_VALKEY_API, utils.IntToString(sco.retryCount)) + optionArgs = append(optionArgs, RetryCountKeyword, utils.IntToString(sco.retryCount)) } if sco.isForce { - optionArgs = append(optionArgs, FORCE_VALKEY_API) + optionArgs = append(optionArgs, ForceKeyword) } return optionArgs, nil @@ -442,27 +436,25 @@ func NewInfiniteStreamBoundary(bound InfBoundary) StreamBoundary { } // Optional arguments for `XRange` and `XRevRange` in [StreamCommands] -type StreamRangeOptions struct { - count int64 - countIsSet bool +type XRangeOptions struct { + count *int64 } -func NewStreamRangeOptions() *StreamRangeOptions { - return &StreamRangeOptions{} +func NewXRangeOptions() *XRangeOptions { + return &XRangeOptions{} } // Set the count. -func (sro *StreamRangeOptions) SetCount(count int64) *StreamRangeOptions { - sro.count = count - sro.countIsSet = true +func (sro *XRangeOptions) SetCount(count int64) *XRangeOptions { + sro.count = &count return sro } -func (sro *StreamRangeOptions) ToArgs() ([]string, error) { +func (sro *XRangeOptions) ToArgs() ([]string, error) { var args []string - if sro.countIsSet { - args = append(args, CountKeyword, utils.IntToString(sro.count)) + if sro.count != nil { + args = append(args, CountKeyword, utils.IntToString(*sro.count)) } return args, nil diff --git a/go/api/options/weight_aggregate_options.go b/go/api/options/weight_aggregate_options.go index 6c26556d18..c18c082f30 100644 --- a/go/api/options/weight_aggregate_options.go +++ b/go/api/options/weight_aggregate_options.go @@ -14,15 +14,15 @@ const ( ) // converts the Aggregate to its Valkey API representation -func (a Aggregate) ToArgs() []string { - return []string{AggregateKeyWord, string(a)} +func (a Aggregate) ToArgs() ([]string, error) { + return []string{AggregateKeyWord, string(a)}, nil } // This is a basic interface. Please use one of the following implementations: // - KeyArray // - WeightedKeys type KeysOrWeightedKeys interface { - ToArgs() []string + ToArgs() ([]string, error) } // represents a list of keys of the sorted sets involved in the aggregation operation @@ -31,10 +31,10 @@ type KeyArray struct { } // converts the KeyArray to its Valkey API representation -func (k KeyArray) ToArgs() []string { +func (k KeyArray) ToArgs() ([]string, error) { args := []string{utils.IntToString(int64(len(k.Keys)))} args = append(args, k.Keys...) - return args + return args, nil } type KeyWeightPair struct { @@ -48,7 +48,7 @@ type WeightedKeys struct { } // converts the WeightedKeys to its Valkey API representation -func (w WeightedKeys) ToArgs() []string { +func (w WeightedKeys) ToArgs() ([]string, error) { keys := make([]string, 0, len(w.KeyWeightPairs)) weights := make([]string, 0, len(w.KeyWeightPairs)) args := make([]string, 0) @@ -60,5 +60,5 @@ func (w WeightedKeys) ToArgs() []string { args = append(args, keys...) args = append(args, WeightsKeyword) args = append(args, weights...) - return args + return args, nil } diff --git a/go/api/options/zadd_options.go b/go/api/options/zadd_options.go index 491addb3e2..ce2d75a417 100644 --- a/go/api/options/zadd_options.go +++ b/go/api/options/zadd_options.go @@ -10,7 +10,7 @@ import ( // Optional arguments to `ZAdd` in [SortedSetCommands] type ZAddOptions struct { - conditionalChange ConditionalChange + conditionalChange ConditionalSet updateOptions UpdateOptions changed bool incr bool @@ -18,12 +18,12 @@ type ZAddOptions struct { member string } -func NewZAddOptionsBuilder() *ZAddOptions { +func NewZAddOptions() *ZAddOptions { return &ZAddOptions{} } // `conditionalChange` defines conditions for updating or adding elements with `ZADD` command. -func (options *ZAddOptions) SetConditionalChange(c ConditionalChange) *ZAddOptions { +func (options *ZAddOptions) SetConditionalChange(c ConditionalSet) *ZAddOptions { options.conditionalChange = c return options } @@ -78,16 +78,6 @@ func (opts *ZAddOptions) ToArgs() ([]string, error) { return args, err } -// A ConditionalSet defines whether a new value should be set or not. -type ConditionalChange string - -const ( - // Only update elements that already exist. Don't add new elements. Equivalent to "XX" in the Valkey API. - OnlyIfExists ConditionalChange = "XX" - // Only add new elements. Don't update already existing elements. Equivalent to "NX" in the Valkey API. - OnlyIfDoesNotExist ConditionalChange = "NX" -) - type UpdateOptions string const ( diff --git a/go/api/options/zcount_options.go b/go/api/options/zcount_options.go index d28cd49c33..817624ba2a 100644 --- a/go/api/options/zcount_options.go +++ b/go/api/options/zcount_options.go @@ -14,7 +14,7 @@ type ZCountRange struct { } // Create a new Zcount range. -func NewZCountRangeBuilder(min scoreBoundary, max scoreBoundary) *ZCountRange { +func NewZCountRange(min scoreBoundary, max scoreBoundary) *ZCountRange { return &ZCountRange{min, max} } diff --git a/go/api/options/zinter_options.go b/go/api/options/zinter_options.go index 0b0728886d..49b662bf02 100644 --- a/go/api/options/zinter_options.go +++ b/go/api/options/zinter_options.go @@ -7,7 +7,7 @@ type ZInterOptions struct { aggregate Aggregate } -func NewZInterOptionsBuilder() *ZInterOptions { +func NewZInterOptions() *ZInterOptions { return &ZInterOptions{} } @@ -18,11 +18,9 @@ func (options *ZInterOptions) SetAggregate(aggregate Aggregate) *ZInterOptions { } func (options *ZInterOptions) ToArgs() ([]string, error) { - args := []string{} - if options.aggregate != "" { - args = append(args, options.aggregate.ToArgs()...) + return options.aggregate.ToArgs() } - return args, nil + return []string{}, nil } diff --git a/go/api/options/zmpop_options.go b/go/api/options/zmpop_options.go index 013784ed5d..324b95d5e0 100644 --- a/go/api/options/zmpop_options.go +++ b/go/api/options/zmpop_options.go @@ -27,7 +27,7 @@ func (zmpo *ZMPopOptions) ToArgs() ([]string, error) { var args []string if zmpo.countIsSet { - args = append(args, "COUNT", utils.IntToString(zmpo.count)) + args = append(args, CountKeyword, utils.IntToString(zmpo.count)) } return args, nil diff --git a/go/api/options/zrange_options.go b/go/api/options/zrange_options.go index 068dc61652..5645c4e3ff 100644 --- a/go/api/options/zrange_options.go +++ b/go/api/options/zrange_options.go @@ -11,7 +11,7 @@ import ( // - For range queries by lexicographical order, use `RangeByLex`. // - For range queries by score, use `RangeByScore`. type ZRangeQuery interface { - ToArgs() []string + ToArgs() ([]string, error) } type ZRemRangeQuery interface { @@ -85,8 +85,8 @@ type Limit struct { count int64 } -func (limit *Limit) toArgs() []string { - return []string{"LIMIT", utils.IntToString(limit.offset), utils.IntToString(limit.count)} +func (limit *Limit) toArgs() ([]string, error) { + return []string{"LIMIT", utils.IntToString(limit.offset), utils.IntToString(limit.count)}, nil } // Queries a range of elements from a sorted set by theirs index. @@ -105,13 +105,13 @@ func (rbi *RangeByIndex) SetReverse() *RangeByIndex { return rbi } -func (rbi *RangeByIndex) ToArgs() []string { +func (rbi *RangeByIndex) ToArgs() ([]string, error) { args := make([]string, 0, 3) args = append(args, utils.IntToString(rbi.start), utils.IntToString(rbi.end)) if rbi.reverse { args = append(args, "REV") } - return args + return args, nil } // Queries a range of elements from a sorted set by theirs score. @@ -136,20 +136,24 @@ func (rbs *RangeByScore) SetLimit(offset, count int64) *RangeByScore { return rbs } -func (rbs *RangeByScore) ToArgs() []string { +func (rbs *RangeByScore) ToArgs() ([]string, error) { args := make([]string, 0, 7) args = append(args, string(rbs.start), string(rbs.end), "BYSCORE") if rbs.reverse { args = append(args, "REV") } if rbs.Limit != nil { - args = append(args, rbs.Limit.toArgs()...) + limitArgs, err := rbs.Limit.toArgs() + if err != nil { + return nil, err + } + args = append(args, limitArgs...) } - return args + return args, nil } -func (rbs *RangeByScore) ToArgsRemRange() []string { - return []string{string(rbs.start), string(rbs.end)} +func (rbs *RangeByScore) ToArgsRemRange() ([]string, error) { + return []string{string(rbs.start), string(rbs.end)}, nil } // Queries a range of elements from a sorted set by theirs lexicographical order. @@ -174,20 +178,24 @@ func (rbl *RangeByLex) SetLimit(offset, count int64) *RangeByLex { return rbl } -func (rbl *RangeByLex) ToArgs() []string { +func (rbl *RangeByLex) ToArgs() ([]string, error) { args := make([]string, 0, 7) args = append(args, string(rbl.start), string(rbl.end), "BYLEX") if rbl.reverse { args = append(args, "REV") } if rbl.Limit != nil { - args = append(args, rbl.Limit.toArgs()...) + limitArgs, err := rbl.Limit.toArgs() + if err != nil { + return nil, err + } + args = append(args, limitArgs...) } - return args + return args, nil } -func (rbl *RangeByLex) ToArgsRemRange() []string { - return []string{string(rbl.start), string(rbl.end)} +func (rbl *RangeByLex) ToArgsRemRange() ([]string, error) { + return []string{string(rbl.start), string(rbl.end)}, nil } // Query for `ZRangeWithScores` in [SortedSetCommands] @@ -197,7 +205,7 @@ type ZRangeQueryWithScores interface { // A dummy interface to distinguish queries for `ZRange` and `ZRangeWithScores` // `ZRangeWithScores` does not support BYLEX dummy() - ToArgs() []string + ToArgs() ([]string, error) } func (q *RangeByIndex) dummy() {} diff --git a/go/api/options/zscan_options.go b/go/api/options/zscan_options.go index 54fc4f3259..b831572259 100644 --- a/go/api/options/zscan_options.go +++ b/go/api/options/zscan_options.go @@ -8,7 +8,7 @@ type ZScanOptions struct { noScores bool } -func NewZScanOptionsBuilder() *ZScanOptions { +func NewZScanOptions() *ZScanOptions { return &ZScanOptions{} } @@ -38,7 +38,7 @@ func (options *ZScanOptions) ToArgs() ([]string, error) { args = append(args, baseArgs...) if options.noScores { - args = append(args, NoScores) + args = append(args, NoScoresKeyword) } return args, err } diff --git a/go/api/options/zunion_options.go b/go/api/options/zunion_options.go index 64839a9593..d45c72a813 100644 --- a/go/api/options/zunion_options.go +++ b/go/api/options/zunion_options.go @@ -17,11 +17,9 @@ func (options *ZUnionOptions) SetAggregate(aggregate Aggregate) *ZUnionOptions { } func (options *ZUnionOptions) ToArgs() ([]string, error) { - args := []string{} - if options.aggregate != "" { - args = append(args, options.aggregate.ToArgs()...) + return options.aggregate.ToArgs() } - return args, nil + return []string{}, nil } diff --git a/go/integTest/request_routing_config_test.go b/go/api/request_routing_config_test.go similarity index 62% rename from go/integTest/request_routing_config_test.go rename to go/api/request_routing_config_test.go index 8b78f2f8d0..cd2d00651e 100644 --- a/go/integTest/request_routing_config_test.go +++ b/go/api/request_routing_config_test.go @@ -1,33 +1,32 @@ // Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 -package integTest +package api import ( "fmt" "testing" "github.com/stretchr/testify/assert" - "github.com/valkey-io/valkey-glide/go/api" "github.com/valkey-io/valkey-glide/go/api/config" "github.com/valkey-io/valkey-glide/go/protobuf" ) func TestSimpleNodeRoute(t *testing.T) { - routeConfig := config.AllNodes + route := config.AllNodes expected := &protobuf.Routes{ Value: &protobuf.Routes_SimpleRoutes{ SimpleRoutes: protobuf.SimpleRoutes_AllNodes, }, } - result, err := routeConfig.ToRoutesProtobuf() + result, err := routeToProtobuf(route) assert.Equal(t, expected, result) assert.Nil(t, err) } func TestSlotIdRoute(t *testing.T) { - routeConfig := config.NewSlotIdRoute(config.SlotTypePrimary, int32(100)) + route := config.NewSlotIdRoute(config.SlotTypePrimary, int32(100)) expected := &protobuf.Routes{ Value: &protobuf.Routes_SlotIdRoute{ SlotIdRoute: &protobuf.SlotIdRoute{ @@ -37,14 +36,14 @@ func TestSlotIdRoute(t *testing.T) { }, } - result, err := routeConfig.ToRoutesProtobuf() + result, err := routeToProtobuf(route) assert.Equal(t, expected, result) assert.Nil(t, err) } func TestSlotKeyRoute(t *testing.T) { - routeConfig := config.NewSlotKeyRoute(config.SlotTypePrimary, "Slot1") + route := config.NewSlotKeyRoute(config.SlotTypePrimary, "Slot1") expected := &protobuf.Routes{ Value: &protobuf.Routes_SlotKeyRoute{ SlotKeyRoute: &protobuf.SlotKeyRoute{ @@ -54,46 +53,46 @@ func TestSlotKeyRoute(t *testing.T) { }, } - result, err := routeConfig.ToRoutesProtobuf() + result, err := routeToProtobuf(route) assert.Equal(t, expected, result) assert.Nil(t, err) } func TestByAddressRoute(t *testing.T) { - routeConfig := config.NewByAddressRoute(api.DefaultHost, int32(api.DefaultPort)) + route := config.NewByAddressRoute(DefaultHost, DefaultPort) expected := &protobuf.Routes{ Value: &protobuf.Routes_ByAddressRoute{ - ByAddressRoute: &protobuf.ByAddressRoute{Host: api.DefaultHost, Port: api.DefaultPort}, + ByAddressRoute: &protobuf.ByAddressRoute{Host: DefaultHost, Port: DefaultPort}, }, } - result, err := routeConfig.ToRoutesProtobuf() + result, err := routeToProtobuf(route) assert.Equal(t, expected, result) assert.Nil(t, err) } func TestByAddressRouteWithHost(t *testing.T) { - routeConfig, _ := config.NewByAddressRouteWithHost(fmt.Sprintf("%s:%d", api.DefaultHost, api.DefaultPort)) + route, _ := config.NewByAddressRouteWithHost(fmt.Sprintf("%s:%d", DefaultHost, DefaultPort)) expected := &protobuf.Routes{ Value: &protobuf.Routes_ByAddressRoute{ - ByAddressRoute: &protobuf.ByAddressRoute{Host: api.DefaultHost, Port: api.DefaultPort}, + ByAddressRoute: &protobuf.ByAddressRoute{Host: DefaultHost, Port: DefaultPort}, }, } - result, err := routeConfig.ToRoutesProtobuf() + result, err := routeToProtobuf(route) assert.Equal(t, expected, result) assert.Nil(t, err) } func TestByAddressRoute_MultiplePorts(t *testing.T) { - _, err := config.NewByAddressRouteWithHost(fmt.Sprintf("%s:%d:%d", api.DefaultHost, api.DefaultPort, api.DefaultPort+1)) + _, err := config.NewByAddressRouteWithHost(fmt.Sprintf("%s:%d:%d", DefaultHost, DefaultPort, DefaultPort+1)) assert.NotNil(t, err) } func TestByAddressRoute_InvalidHost(t *testing.T) { - _, err := config.NewByAddressRouteWithHost(api.DefaultHost) + _, err := config.NewByAddressRouteWithHost(DefaultHost) assert.NotNil(t, err) } diff --git a/go/api/response_handlers.go b/go/api/response_handlers.go index e1030e0b7d..7fbe3bb478 100644 --- a/go/api/response_handlers.go +++ b/go/api/response_handlers.go @@ -2,13 +2,6 @@ package api -// #cgo LDFLAGS: -lglide_rs -// #cgo !windows LDFLAGS: -lm -// #cgo darwin LDFLAGS: -framework Security -// #cgo linux,amd64 LDFLAGS: -L${SRCDIR}/../rustbin/x86_64-unknown-linux-gnu -// #cgo linux,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-unknown-linux-gnu -// #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../rustbin/aarch64-apple-darwin -// #cgo LDFLAGS: -L../target/release // #include "../lib.h" import "C" @@ -1238,7 +1231,6 @@ func handleTimeClusterResponse(response *C.struct_CommandResponse) (ClusterValue for nodeName, nodeTimes := range mapData { multiNodeTimes[nodeName] = nodeTimes } - return createClusterMultiValue(multiNodeTimes), nil } diff --git a/go/api/server_management_cluster_commands.go b/go/api/server_management_cluster_commands.go index a4094103da..5c9654547c 100644 --- a/go/api/server_management_cluster_commands.go +++ b/go/api/server_management_cluster_commands.go @@ -12,7 +12,7 @@ import "github.com/valkey-io/valkey-glide/go/api/options" type ServerManagementClusterCommands interface { Info() (map[string]string, error) - InfoWithOptions(options ClusterInfoOptions) (ClusterValue[string], error) + InfoWithOptions(options options.ClusterInfoOptions) (ClusterValue[string], error) TimeWithOptions(routeOption options.RouteOption) (ClusterValue[[]string], error) diff --git a/go/api/server_management_cluster_commands_test.go b/go/api/server_management_cluster_commands_test.go index 08d6ca9114..6235e23e91 100644 --- a/go/api/server_management_cluster_commands_test.go +++ b/go/api/server_management_cluster_commands_test.go @@ -28,8 +28,8 @@ func ExampleGlideClusterClient_Info() { func ExampleGlideClusterClient_InfoWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function - opts := ClusterInfoOptions{ - InfoOptions: &InfoOptions{Sections: []Section{Cluster}}, + opts := options.ClusterInfoOptions{ + InfoOptions: &options.InfoOptions{Sections: []options.Section{options.Cluster}}, } response, err := client.InfoWithOptions(opts) diff --git a/go/api/server_management_commands.go b/go/api/server_management_commands.go index 48ded7974f..fa8d45f951 100644 --- a/go/api/server_management_commands.go +++ b/go/api/server_management_commands.go @@ -2,6 +2,10 @@ package api +import ( + "github.com/valkey-io/valkey-glide/go/api/options" +) + // ServerManagementCommands supports commands for the "Server Management" group for a standalone client. // // See [valkey.io] for details. @@ -16,7 +20,7 @@ type ServerManagementCommands interface { Info() (string, error) - InfoWithOptions(options InfoOptions) (string, error) + InfoWithOptions(options options.InfoOptions) (string, error) DBSize() (int64, error) diff --git a/go/api/server_management_commands_test.go b/go/api/server_management_commands_test.go index a4d19b2614..3fda546886 100644 --- a/go/api/server_management_commands_test.go +++ b/go/api/server_management_commands_test.go @@ -6,6 +6,8 @@ import ( "fmt" "strconv" "time" + + "github.com/valkey-io/valkey-glide/go/api/options" ) func ExampleGlideClient_Select() { @@ -102,7 +104,7 @@ func ExampleGlideClient_Info() { func ExampleGlideClient_InfoWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function - opts := InfoOptions{Sections: []Section{Server}} + opts := options.InfoOptions{Sections: []options.Section{options.Server}} response, err := client.InfoWithOptions(opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) diff --git a/go/api/set_commands.go b/go/api/set_commands.go index caf93d4a39..9d98036921 100644 --- a/go/api/set_commands.go +++ b/go/api/set_commands.go @@ -44,7 +44,7 @@ type SetCommands interface { SScan(key string, cursor string) (string, []string, error) - SScanWithOptions(key string, cursor string, options *options.BaseScanOptions) (string, []string, error) + SScanWithOptions(key string, cursor string, options options.BaseScanOptions) (string, []string, error) SMove(source string, destination string, member string) (bool, error) } diff --git a/go/api/set_commands_test.go b/go/api/set_commands_test.go index da98daeca7..d4db553726 100644 --- a/go/api/set_commands_test.go +++ b/go/api/set_commands_test.go @@ -533,8 +533,8 @@ func ExampleGlideClient_SScanWithOptions() { key := "my_set" client.SAdd(key, []string{"member1", "member2", "item3"}) cursor := "0" - options := options.NewBaseScanOptionsBuilder().SetMatch("mem*") - result, nextCursor, err := client.SScanWithOptions(key, cursor, options) + options := options.NewBaseScanOptions().SetMatch("mem*") + result, nextCursor, err := client.SScanWithOptions(key, cursor, *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -547,8 +547,8 @@ func ExampleGlideClusterClient_SScanWithOptions() { key := "my_set" client.SAdd(key, []string{"member1", "member2", "item3"}) cursor := "0" - options := options.NewBaseScanOptionsBuilder().SetMatch("mem*") - result, nextCursor, err := client.SScanWithOptions(key, cursor, options) + options := options.NewBaseScanOptions().SetMatch("mem*") + result, nextCursor, err := client.SScanWithOptions(key, cursor, *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } diff --git a/go/api/sorted_set_commands.go b/go/api/sorted_set_commands.go index 78ab496357..7b9fbfa5ac 100644 --- a/go/api/sorted_set_commands.go +++ b/go/api/sorted_set_commands.go @@ -14,21 +14,21 @@ import ( type SortedSetCommands interface { ZAdd(key string, membersScoreMap map[string]float64) (int64, error) - ZAddWithOptions(key string, membersScoreMap map[string]float64, opts *options.ZAddOptions) (int64, error) + ZAddWithOptions(key string, membersScoreMap map[string]float64, opts options.ZAddOptions) (int64, error) ZAddIncr(key string, member string, increment float64) (Result[float64], error) - ZAddIncrWithOptions(key string, member string, increment float64, opts *options.ZAddOptions) (Result[float64], error) + ZAddIncrWithOptions(key string, member string, increment float64, opts options.ZAddOptions) (Result[float64], error) ZIncrBy(key string, increment float64, member string) (float64, error) ZPopMin(key string) (map[string]float64, error) - ZPopMinWithCount(key string, count int64) (map[string]float64, error) + ZPopMinWithOptions(key string, options options.ZPopOptions) (map[string]float64, error) ZPopMax(key string) (map[string]float64, error) - ZPopMaxWithCount(key string, count int64) (map[string]float64, error) + ZPopMaxWithOptions(key string, options options.ZPopOptions) (map[string]float64, error) ZRem(key string, members []string) (int64, error) @@ -36,13 +36,13 @@ type SortedSetCommands interface { BZPopMin(keys []string, timeoutSecs float64) (Result[KeyWithMemberAndScore], error) - BZMPop(keys []string, scoreFilter ScoreFilter, timeoutSecs float64) (Result[KeyWithArrayOfMembersAndScores], error) + BZMPop(keys []string, scoreFilter options.ScoreFilter, timeoutSecs float64) (Result[KeyWithArrayOfMembersAndScores], error) BZMPopWithOptions( keys []string, - scoreFilter ScoreFilter, + scoreFilter options.ScoreFilter, timeoutSecs float64, - options *options.ZMPopOptions, + options options.ZMPopOptions, ) (Result[KeyWithArrayOfMembersAndScores], error) ZRange(key string, rangeQuery options.ZRangeQuery) ([]string, error) @@ -61,11 +61,11 @@ type SortedSetCommands interface { ZScore(key string, member string) (Result[float64], error) - ZCount(key string, rangeOptions *options.ZCountRange) (int64, error) + ZCount(key string, rangeOptions options.ZCountRange) (int64, error) ZScan(key string, cursor string) (string, []string, error) - ZScanWithOptions(key string, cursor string, options *options.ZScanOptions) (string, []string, error) + ZScanWithOptions(key string, cursor string, options options.ZScanOptions) (string, []string, error) ZRemRangeByLex(key string, rangeQuery options.RangeByLex) (int64, error) @@ -89,14 +89,14 @@ type SortedSetCommands interface { ZInter(keys options.KeyArray) ([]string, error) - ZInterWithScores(keysOrWeightedKeys options.KeysOrWeightedKeys, options *options.ZInterOptions) (map[string]float64, error) + ZInterWithScores(keysOrWeightedKeys options.KeysOrWeightedKeys, options options.ZInterOptions) (map[string]float64, error) ZInterStore(destination string, keysOrWeightedKeys options.KeysOrWeightedKeys) (int64, error) ZInterStoreWithOptions( destination string, keysOrWeightedKeys options.KeysOrWeightedKeys, - options *options.ZInterOptions, + options options.ZInterOptions, ) (int64, error) ZUnion(keys options.KeyArray) ([]string, error) diff --git a/go/api/sorted_set_commands_test.go b/go/api/sorted_set_commands_test.go index 1f1634bb92..6028e31b3c 100644 --- a/go/api/sorted_set_commands_test.go +++ b/go/api/sorted_set_commands_test.go @@ -36,11 +36,11 @@ func ExampleGlideClusterClient_ZAdd() { func ExampleGlideClient_ZAddWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function - opts, err := options.NewZAddOptionsBuilder().SetChanged(true) + opts, err := options.NewZAddOptions().SetChanged(true) result, err := client.ZAddWithOptions( "key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}, - opts, + *opts, ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -53,11 +53,11 @@ func ExampleGlideClient_ZAddWithOptions() { func ExampleGlideClusterClient_ZAddWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function - opts, err := options.NewZAddOptionsBuilder().SetChanged(true) + opts, err := options.NewZAddOptions().SetChanged(true) result, err := client.ZAddWithOptions( "key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}, - opts, + *opts, ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -96,8 +96,8 @@ func ExampleGlideClusterClient_ZAddIncr() { func ExampleGlideClient_ZAddIncrWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function - opts, err := options.NewZAddOptionsBuilder().SetChanged(true) // should return an error - result, err := client.ZAddIncrWithOptions("key1", "one", 1.0, opts) + opts, err := options.NewZAddOptions().SetChanged(true) // should return an error + result, err := client.ZAddIncrWithOptions("key1", "one", 1.0, *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -111,8 +111,8 @@ func ExampleGlideClient_ZAddIncrWithOptions() { func ExampleGlideClusterClient_ZAddIncrWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function - opts, err := options.NewZAddOptionsBuilder().SetChanged(true) // should return an error - result, err := client.ZAddIncrWithOptions("key1", "one", 1.0, opts) + opts, err := options.NewZAddOptions().SetChanged(true) // should return an error + result, err := client.ZAddIncrWithOptions("key1", "one", 1.0, *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -187,11 +187,12 @@ func ExampleGlideClusterClient_ZPopMin() { // map[one:1] } -func ExampleGlideClient_ZPopMinWithCount() { +func ExampleGlideClient_ZPopMinWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}) - result1, err := client.ZPopMinWithCount("key1", 2) + opts := options.NewZPopOptions().SetCount(2) + result1, err := client.ZPopMinWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -203,11 +204,12 @@ func ExampleGlideClient_ZPopMinWithCount() { // map[one:1 two:2] } -func ExampleGlideClusterClient_ZPopMinWithCount() { +func ExampleGlideClusterClient_ZPopMinWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}) - result1, err := client.ZPopMinWithCount("key1", 2) + opts := options.NewZPopOptions().SetCount(2) + result1, err := client.ZPopMinWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -251,11 +253,12 @@ func ExampleGlideClusterClient_ZPopMax() { // map[three:3] } -func ExampleGlideClient_ZPopMaxWithCount() { +func ExampleGlideClient_ZPopMaxWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}) - result1, err := client.ZPopMaxWithCount("key1", 2) + opts := options.NewZPopOptions().SetCount(2) + result1, err := client.ZPopMaxWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -267,11 +270,12 @@ func ExampleGlideClient_ZPopMaxWithCount() { // map[three:3 two:2] } -func ExampleGlideClusterClient_ZPopMaxWithCount() { +func ExampleGlideClusterClient_ZPopMaxWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0}) - result1, err := client.ZPopMaxWithCount("key1", 2) + opts := options.NewZPopOptions().SetCount(2) + result1, err := client.ZPopMaxWithOptions("key1", *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -686,12 +690,12 @@ func ExampleGlideClusterClient_ZScore() { func ExampleGlideClient_ZCount() { var client *GlideClient = getExampleGlideClient() // example helper function - zCountRange := options.NewZCountRangeBuilder( + zCountRange := options.NewZCountRange( options.NewInclusiveScoreBoundary(2.0), options.NewInfiniteScoreBoundary(options.PositiveInfinity), ) result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0, "four": 4.0}) - result1, err := client.ZCount("key1", zCountRange) + result1, err := client.ZCount("key1", *zCountRange) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -706,12 +710,12 @@ func ExampleGlideClient_ZCount() { func ExampleGlideClusterClient_ZCount() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function - zCountRange := options.NewZCountRangeBuilder( + zCountRange := options.NewZCountRange( options.NewInclusiveScoreBoundary(2.0), options.NewInfiniteScoreBoundary(options.PositiveInfinity), ) result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0, "four": 4.0}) - result1, err := client.ZCount("key1", zCountRange) + result1, err := client.ZCount("key1", *zCountRange) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -763,8 +767,7 @@ func ExampleGlideClient_ZScanWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0, "four": 4.0}) - resCursor, resCol, err := client.ZScanWithOptions("key1", "0", - options.NewZScanOptionsBuilder().SetMatch("*")) + resCursor, resCol, err := client.ZScanWithOptions("key1", "0", *options.NewZScanOptions().SetMatch("*")) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -782,8 +785,7 @@ func ExampleGlideClusterClient_ZScanWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function result, err := client.ZAdd("key1", map[string]float64{"one": 1.0, "two": 2.0, "three": 3.0, "four": 4.0}) - resCursor, resCol, err := client.ZScanWithOptions("key1", "0", - options.NewZScanOptionsBuilder().SetMatch("*")) + resCursor, resCol, err := client.ZScanWithOptions("key1", "0", *options.NewZScanOptions().SetMatch("*")) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -909,7 +911,7 @@ func ExampleGlideClient_BZMPop() { var client *GlideClient = getExampleGlideClient() // example helper function client.ZAdd("key1", map[string]float64{"a": 1.0, "b": 2.0, "c": 3.0, "d": 4.0}) - result, err := client.BZMPop([]string{"key1"}, MAX, float64(0.5)) + result, err := client.BZMPop([]string{"key1"}, options.MAX, float64(0.5)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -922,7 +924,7 @@ func ExampleGlideClusterClient_BZMPop() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function client.ZAdd("key1", map[string]float64{"a": 1.0, "b": 2.0, "c": 3.0, "d": 4.0}) - result, err := client.BZMPop([]string{"key1"}, MAX, float64(0.5)) + result, err := client.BZMPop([]string{"key1"}, options.MAX, float64(0.5)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -936,7 +938,7 @@ func ExampleGlideClient_BZMPopWithOptions() { client.ZAdd("key1", map[string]float64{"a": 1.0, "b": 2.0, "c": 3.0, "d": 4.0}) - result, err := client.BZMPopWithOptions([]string{"key1"}, MAX, 0.1, options.NewZMPopOptions().SetCount(1)) + result, err := client.BZMPopWithOptions([]string{"key1"}, options.MAX, 0.1, *options.NewZMPopOptions().SetCount(2)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -963,7 +965,7 @@ func ExampleGlideClusterClient_BZMPopWithOptions() { client.ZAdd("key1", map[string]float64{"a": 1.0, "b": 2.0, "c": 3.0, "d": 4.0}) - result, err := client.BZMPopWithOptions([]string{"key1"}, MAX, 0.1, options.NewZMPopOptions().SetCount(1)) + result, err := client.BZMPopWithOptions([]string{"key1"}, options.MAX, 0.1, *options.NewZMPopOptions().SetCount(1)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1136,7 +1138,7 @@ func ExampleGlideClient_ZInterWithScores() { options.KeyArray{ Keys: []string{"key1", "key2"}, }, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1154,7 +1156,7 @@ func ExampleGlideClusterClient_ZInterWithScores() { options.KeyArray{ Keys: []string{"{key}1", "{key}2"}, }, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1206,7 +1208,7 @@ func ExampleGlideClient_ZInterStoreWithOptions() { options.KeyArray{ Keys: []string{"key1", "key2"}, }, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1226,7 +1228,7 @@ func ExampleGlideClusterClient_ZInterStoreWithOptions() { options.KeyArray{ Keys: []string{"{key}1", "{key}2"}, }, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) diff --git a/go/api/stream_commands.go b/go/api/stream_commands.go index 6a312a0186..8f0aa5bc74 100644 --- a/go/api/stream_commands.go +++ b/go/api/stream_commands.go @@ -12,9 +12,9 @@ import "github.com/valkey-io/valkey-glide/go/api/options" type StreamCommands interface { XAdd(key string, values [][]string) (Result[string], error) - XAddWithOptions(key string, values [][]string, options *options.XAddOptions) (Result[string], error) + XAddWithOptions(key string, values [][]string, options options.XAddOptions) (Result[string], error) - XTrim(key string, options *options.XTrimOptions) (int64, error) + XTrim(key string, options options.XTrimOptions) (int64, error) XLen(key string) (int64, error) @@ -26,7 +26,7 @@ type StreamCommands interface { consumer string, minIdleTime int64, start string, - options *options.XAutoClaimOptions, + options options.XAutoClaimOptions, ) (XAutoClaimResponse, error) XAutoClaimJustId( @@ -43,7 +43,7 @@ type StreamCommands interface { consumer string, minIdleTime int64, start string, - options *options.XAutoClaimOptions, + options options.XAutoClaimOptions, ) (XAutoClaimJustIdResponse, error) XReadGroup(group string, consumer string, keysAndIds map[string]string) (map[string]map[string][][]string, error) @@ -52,26 +52,26 @@ type StreamCommands interface { group string, consumer string, keysAndIds map[string]string, - options *options.XReadGroupOptions, + options options.XReadGroupOptions, ) (map[string]map[string][][]string, error) XRead(keysAndIds map[string]string) (map[string]map[string][][]string, error) - XReadWithOptions(keysAndIds map[string]string, options *options.XReadOptions) (map[string]map[string][][]string, error) + XReadWithOptions(keysAndIds map[string]string, options options.XReadOptions) (map[string]map[string][][]string, error) XDel(key string, ids []string) (int64, error) XPending(key string, group string) (XPendingSummary, error) - XPendingWithOptions(key string, group string, options *options.XPendingOptions) ([]XPendingDetail, error) + XPendingWithOptions(key string, group string, options options.XPendingOptions) ([]XPendingDetail, error) XGroupSetId(key string, group string, id string) (string, error) - XGroupSetIdWithOptions(key string, group string, id string, opts *options.XGroupSetIdOptions) (string, error) + XGroupSetIdWithOptions(key string, group string, id string, opts options.XGroupSetIdOptions) (string, error) XGroupCreate(key string, group string, id string) (string, error) - XGroupCreateWithOptions(key string, group string, id string, opts *options.XGroupCreateOptions) (string, error) + XGroupCreateWithOptions(key string, group string, id string, opts options.XGroupCreateOptions) (string, error) XGroupDestroy(key string, group string) (bool, error) @@ -95,7 +95,7 @@ type StreamCommands interface { consumer string, minIdleTime int64, ids []string, - options *options.StreamClaimOptions, + options options.XClaimOptions, ) (map[string][][]string, error) XClaimJustId(key string, group string, consumer string, minIdleTime int64, ids []string) ([]string, error) @@ -106,7 +106,7 @@ type StreamCommands interface { consumer string, minIdleTime int64, ids []string, - options *options.StreamClaimOptions, + options options.XClaimOptions, ) ([]string, error) XInfoStream(key string) (map[string]any, error) @@ -119,7 +119,7 @@ type StreamCommands interface { key string, start options.StreamBoundary, end options.StreamBoundary, - options *options.StreamRangeOptions, + options options.XRangeOptions, ) ([]XRangeResponse, error) XRevRange(key string, start options.StreamBoundary, end options.StreamBoundary) ([]XRangeResponse, error) @@ -128,6 +128,6 @@ type StreamCommands interface { key string, start options.StreamBoundary, end options.StreamBoundary, - options *options.StreamRangeOptions, + options options.XRangeOptions, ) ([]XRangeResponse, error) } diff --git a/go/api/stream_commands_test.go b/go/api/stream_commands_test.go index 37d803b3ed..d48c6df683 100644 --- a/go/api/stream_commands_test.go +++ b/go/api/stream_commands_test.go @@ -59,7 +59,7 @@ func ExampleGlideClient_XAddWithOptions() { {"key1", "value1"}, {"key2", "value2"}, } - result, err := client.XAddWithOptions("mystream", values, options) + result, err := client.XAddWithOptions("mystream", values, *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -77,7 +77,7 @@ func ExampleGlideClusterClient_XAddWithOptions() { {"key1", "value1"}, {"key2", "value2"}, } - result, err := client.XAddWithOptions("mystream", values, options) + result, err := client.XAddWithOptions("mystream", values, *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -92,7 +92,7 @@ func ExampleGlideClient_XTrim() { client.XAdd("mystream", [][]string{{"field1", "foo4"}, {"field2", "bar4"}}) client.XAdd("mystream", [][]string{{"field3", "foo4"}, {"field4", "bar4"}}) - count, err := client.XTrim("mystream", options.NewXTrimOptionsWithMaxLen(0).SetExactTrimming()) + count, err := client.XTrim("mystream", *options.NewXTrimOptionsWithMaxLen(0).SetExactTrimming()) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -107,7 +107,7 @@ func ExampleGlideClusterClient_XTrim() { client.XAdd("mystream", [][]string{{"field1", "foo4"}, {"field2", "bar4"}}) client.XAdd("mystream", [][]string{{"field3", "foo4"}, {"field4", "bar4"}}) - count, err := client.XTrim("mystream", options.NewXTrimOptionsWithMaxLen(0).SetExactTrimming()) + count, err := client.XTrim("mystream", *options.NewXTrimOptionsWithMaxLen(0).SetExactTrimming()) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -148,17 +148,17 @@ func ExampleGlideClient_XAutoClaim() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) @@ -178,17 +178,17 @@ func ExampleGlideClusterClient_XAutoClaim() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) @@ -208,22 +208,22 @@ func ExampleGlideClient_XAutoClaimWithOptions() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) - options := options.NewXAutoClaimOptionsWithCount(1) - response, err := client.XAutoClaimWithOptions(key, group, consumer, 0, "0-1", options) + options := options.NewXAutoClaimOptions().SetCount(1) + response, err := client.XAutoClaimWithOptions(key, group, consumer, 0, "0-1", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -238,22 +238,22 @@ func ExampleGlideClusterClient_XAutoClaimWithOptions() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) - options := options.NewXAutoClaimOptionsWithCount(1) - response, err := client.XAutoClaimWithOptions(key, group, consumer, 0, "0-1", options) + options := options.NewXAutoClaimOptions().SetCount(1) + response, err := client.XAutoClaimWithOptions(key, group, consumer, 0, "0-1", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -268,17 +268,17 @@ func ExampleGlideClient_XAutoClaimJustId() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) @@ -297,17 +297,17 @@ func ExampleGlideClusterClient_XAutoClaimJustId() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) @@ -326,22 +326,22 @@ func ExampleGlideClient_XAutoClaimJustIdWithOptions() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) - options := options.NewXAutoClaimOptionsWithCount(1) - response, err := client.XAutoClaimJustIdWithOptions(key, group, consumer, 0, "0-1", options) + options := options.NewXAutoClaimOptions().SetCount(1) + response, err := client.XAutoClaimJustIdWithOptions(key, group, consumer, 0, "0-1", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -356,22 +356,22 @@ func ExampleGlideClusterClient_XAutoClaimJustIdWithOptions() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) - options := options.NewXAutoClaimOptionsWithCount(1) - response, err := client.XAutoClaimJustIdWithOptions(key, group, consumer, 0, "0-1", options) + options := options.NewXAutoClaimOptions().SetCount(1) + response, err := client.XAutoClaimJustIdWithOptions(key, group, consumer, 0, "0-1", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -387,12 +387,12 @@ func ExampleGlideClient_XReadGroup() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) response, err := client.XReadGroup(group, consumer, map[string]string{key: "0"}) @@ -411,12 +411,12 @@ func ExampleGlideClusterClient_XReadGroup() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) response, err := client.XReadGroup(group, consumer, map[string]string{key: "0"}) @@ -435,16 +435,16 @@ func ExampleGlideClient_XReadGroupWithOptions() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) options := options.NewXReadGroupOptions().SetNoAck() - response, err := client.XReadGroupWithOptions(group, consumer, map[string]string{key: ">"}, options) + response, err := client.XReadGroupWithOptions(group, consumer, map[string]string{key: ">"}, *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -460,16 +460,16 @@ func ExampleGlideClusterClient_XReadGroupWithOptions() { group := uuid.NewString() consumer := uuid.NewString() - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) options := options.NewXReadGroupOptions().SetNoAck() - response, err := client.XReadGroupWithOptions(group, consumer, map[string]string{key: ">"}, options) + response, err := client.XReadGroupWithOptions(group, consumer, map[string]string{key: ">"}, *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -486,7 +486,7 @@ func ExampleGlideClient_XRead() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) response, err := client.XRead(map[string]string{key: "0-0"}) @@ -506,7 +506,7 @@ func ExampleGlideClusterClient_XRead() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) response, err := client.XRead(map[string]string{key: "0-0"}) @@ -528,17 +528,17 @@ func ExampleGlideClient_XReadWithOptions() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(genStreamId(key, streambase, 0)), + *options.NewXAddOptions().SetId(genStreamId(key, streambase, 0)), ) client.XAddWithOptions( key, [][]string{{"field3", "value3"}, {"field4", "value4"}}, - options.NewXAddOptions().SetId(genStreamId(key, streambase, 1)), + *options.NewXAddOptions().SetId(genStreamId(key, streambase, 1)), ) response, err := client.XReadWithOptions( map[string]string{key: genStreamId(key, streambase, 0)}, - options.NewXReadOptions().SetCount(1), + *options.NewXReadOptions().SetCount(1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -558,17 +558,17 @@ func ExampleGlideClusterClient_XReadWithOptions() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(genStreamId(key, streambase, 0)), + *options.NewXAddOptions().SetId(genStreamId(key, streambase, 0)), ) client.XAddWithOptions( key, [][]string{{"field3", "value3"}, {"field4", "value4"}}, - options.NewXAddOptions().SetId(genStreamId(key, streambase, 1)), + *options.NewXAddOptions().SetId(genStreamId(key, streambase, 1)), ) response, err := client.XReadWithOptions( map[string]string{key: genStreamId(key, streambase, 0)}, - options.NewXReadOptions().SetCount(1), + *options.NewXReadOptions().SetCount(1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -585,7 +585,7 @@ func ExampleGlideClient_XDel() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) count, err := client.XDel(key, []string{"0-1", "0-2", "0-3"}) @@ -604,7 +604,7 @@ func ExampleGlideClusterClient_XDel() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) count, err := client.XDel(key, []string{"0-1", "0-2", "0-3"}) @@ -623,12 +623,12 @@ func ExampleGlideClient_XPending() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) @@ -649,12 +649,12 @@ func ExampleGlideClusterClient_XPending() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) @@ -675,19 +675,19 @@ func ExampleGlideClient_XPendingWithOptions() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) details, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -717,19 +717,19 @@ func ExampleGlideClusterClient_XPendingWithOptions() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) details, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -759,12 +759,12 @@ func ExampleGlideClient_XGroupSetId() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) client.XAck(key, group, []string{streamId}) // ack the message and remove it from the pending list @@ -789,12 +789,12 @@ func ExampleGlideClusterClient_XGroupSetId() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) client.XAck(key, group, []string{streamId}) // ack the message and remove it from the pending list @@ -820,23 +820,23 @@ func ExampleGlideClient_XGroupSetIdWithOptions() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId1), + *options.NewXAddOptions().SetId(streamId1), ) client.XAddWithOptions( key, [][]string{{"field3", "value3"}, {"field4", "value4"}}, - options.NewXAddOptions().SetId(streamId2), + *options.NewXAddOptions().SetId(streamId2), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) client.XAck(key, group, []string{streamId1, streamId2}) // ack the message and remove it from the pending list opts := options.NewXGroupSetIdOptionsOptions().SetEntriesRead(1) - client.XGroupSetIdWithOptions(key, group, "0-0", opts) // reset the last acknowledged message to 0-0 + client.XGroupSetIdWithOptions(key, group, "0-0", *opts) // reset the last acknowledged message to 0-0 client.XReadGroup(group, consumer, map[string]string{key: ">"}) // read the group again summary, err := client.XPending(key, group) // get the pending messages, which should include the entry we previously acked @@ -857,23 +857,23 @@ func ExampleGlideClusterClient_XGroupSetIdWithOptions() { group := "g12345" consumer := "c12345" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer) client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId1), + *options.NewXAddOptions().SetId(streamId1), ) client.XAddWithOptions( key, [][]string{{"field3", "value3"}, {"field4", "value4"}}, - options.NewXAddOptions().SetId(streamId2), + *options.NewXAddOptions().SetId(streamId2), ) client.XReadGroup(group, consumer, map[string]string{key: ">"}) client.XAck(key, group, []string{streamId1, streamId2}) // ack the message and remove it from the pending list opts := options.NewXGroupSetIdOptionsOptions().SetEntriesRead(1) - client.XGroupSetIdWithOptions(key, group, "0-0", opts) // reset the last acknowledged message to 0-0 + client.XGroupSetIdWithOptions(key, group, "0-0", *opts) // reset the last acknowledged message to 0-0 client.XReadGroup(group, consumer, map[string]string{key: ">"}) // read the group again summary, err := client.XPending(key, group) // get the pending messages, which should include the entry we previously acked @@ -895,7 +895,7 @@ func ExampleGlideClient_XGroupCreate() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) // This will create the stream if it does not exist response, err := client.XGroupCreate(key, group, "0") // create the group (no MKSTREAM needed) @@ -916,7 +916,7 @@ func ExampleGlideClusterClient_XGroupCreate() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) // This will create the stream if it does not exist response, err := client.XGroupCreate(key, group, "0") // create the group (no MKSTREAM needed) @@ -934,7 +934,7 @@ func ExampleGlideClient_XGroupCreateWithOptions() { group := "g12345" opts := options.NewXGroupCreateOptions().SetMakeStream() - response, err := client.XGroupCreateWithOptions(key, group, "0", opts) // create the group (no MKSTREAM needed) + response, err := client.XGroupCreateWithOptions(key, group, "0", *opts) // create the group (no MKSTREAM needed) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -949,7 +949,7 @@ func ExampleGlideClusterClient_XGroupCreateWithOptions() { group := "g12345" opts := options.NewXGroupCreateOptions().SetMakeStream() - response, err := client.XGroupCreateWithOptions(key, group, "0", opts) // create the group (no MKSTREAM needed) + response, err := client.XGroupCreateWithOptions(key, group, "0", *opts) // create the group (no MKSTREAM needed) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -964,7 +964,7 @@ func ExampleGlideClient_XGroupDestroy() { group := "g12345" opts := options.NewXGroupCreateOptions().SetMakeStream() - client.XGroupCreateWithOptions(key, group, "0", opts) // create the group (no MKSTREAM needed) + client.XGroupCreateWithOptions(key, group, "0", *opts) // create the group (no MKSTREAM needed) success, err := client.XGroupDestroy(key, group) // destroy the group if err != nil { @@ -981,7 +981,7 @@ func ExampleGlideClusterClient_XGroupDestroy() { group := "g12345" opts := options.NewXGroupCreateOptions().SetMakeStream() - client.XGroupCreateWithOptions(key, group, "0", opts) // create the group (no MKSTREAM needed) + client.XGroupCreateWithOptions(key, group, "0", *opts) // create the group (no MKSTREAM needed) success, err := client.XGroupDestroy(key, group) // destroy the group if err != nil { @@ -999,7 +999,7 @@ func ExampleGlideClient_XGroupCreateConsumer() { consumer := "c12345" opts := options.NewXGroupCreateOptions().SetMakeStream() - client.XGroupCreateWithOptions(key, group, "0", opts) // create the group (no MKSTREAM needed) + client.XGroupCreateWithOptions(key, group, "0", *opts) // create the group (no MKSTREAM needed) success, err := client.XGroupCreateConsumer(key, group, consumer) if err != nil { @@ -1017,7 +1017,7 @@ func ExampleGlideClusterClient_XGroupCreateConsumer() { consumer := "c12345" opts := options.NewXGroupCreateOptions().SetMakeStream() - client.XGroupCreateWithOptions(key, group, "0", opts) // create the group (no MKSTREAM needed) + client.XGroupCreateWithOptions(key, group, "0", *opts) // create the group (no MKSTREAM needed) success, err := client.XGroupCreateConsumer(key, group, consumer) if err != nil { @@ -1038,7 +1038,7 @@ func ExampleGlideClient_XGroupDelConsumer() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XGroupCreate(key, group, "0") client.XGroupCreateConsumer(key, group, consumer) @@ -1064,7 +1064,7 @@ func ExampleGlideClusterClient_XGroupDelConsumer() { client.XAddWithOptions( key, [][]string{{"field1", "value1"}, {"field2", "value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XGroupCreate(key, group, "0") client.XGroupCreateConsumer(key, group, consumer) @@ -1134,19 +1134,19 @@ func ExampleGlideClient_XClaim() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1173,19 +1173,19 @@ func ExampleGlideClusterClient_XClaim() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1212,19 +1212,19 @@ func ExampleGlideClient_XClaimWithOptions() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1234,8 +1234,8 @@ func ExampleGlideClient_XClaimWithOptions() { return } - opts := options.NewStreamClaimOptions().SetRetryCount(3) - response, err := client.XClaimWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, opts) + opts := options.NewXClaimOptions().SetRetryCount(3) + response, err := client.XClaimWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1252,19 +1252,19 @@ func ExampleGlideClusterClient_XClaimWithOptions() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1274,8 +1274,8 @@ func ExampleGlideClusterClient_XClaimWithOptions() { return } - opts := options.NewStreamClaimOptions().SetRetryCount(3) - response, err := client.XClaimWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, opts) + opts := options.NewXClaimOptions().SetRetryCount(3) + response, err := client.XClaimWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1292,19 +1292,19 @@ func ExampleGlideClient_XClaimJustId() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1331,19 +1331,19 @@ func ExampleGlideClusterClient_XClaimJustId() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1370,19 +1370,19 @@ func ExampleGlideClient_XClaimJustIdWithOptions() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1392,8 +1392,8 @@ func ExampleGlideClient_XClaimJustIdWithOptions() { return } - opts := options.NewStreamClaimOptions().SetRetryCount(3) - response, err := client.XClaimJustIdWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, opts) + opts := options.NewXClaimOptions().SetRetryCount(3) + response, err := client.XClaimJustIdWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1410,19 +1410,19 @@ func ExampleGlideClusterClient_XClaimJustIdWithOptions() { consumer1 := "c12345-1" consumer2 := "c12345-2" - client.XGroupCreateWithOptions(key, group, "0", options.NewXGroupCreateOptions().SetMakeStream()) + client.XGroupCreateWithOptions(key, group, "0", *options.NewXGroupCreateOptions().SetMakeStream()) client.XGroupCreateConsumer(key, group, consumer1) client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId(streamId), + *options.NewXAddOptions().SetId(streamId), ) client.XReadGroup(group, consumer1, map[string]string{key: ">"}) result, err := client.XPendingWithOptions( key, group, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1432,8 +1432,8 @@ func ExampleGlideClusterClient_XClaimJustIdWithOptions() { return } - opts := options.NewStreamClaimOptions().SetRetryCount(3) - response, err := client.XClaimJustIdWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, opts) + opts := options.NewXClaimOptions().SetRetryCount(3) + response, err := client.XClaimJustIdWithOptions(key, group, consumer2, result[0].IdleTime, []string{result[0].Id}, *opts) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1488,7 +1488,7 @@ func ExampleGlideClient_XRangeWithOptions() { response, err := client.XRangeWithOptions(key, options.NewStreamBoundary(streamId1.Value(), true), options.NewStreamBoundary(streamId2.Value(), true), - options.NewStreamRangeOptions().SetCount(1)) + *options.NewXRangeOptions().SetCount(1)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1507,7 +1507,7 @@ func ExampleGlideClusterClient_XRangeWithOptions() { response, err := client.XRangeWithOptions(key, options.NewStreamBoundary(streamId1.Value(), true), options.NewStreamBoundary(streamId2.Value(), true), - options.NewStreamRangeOptions().SetCount(1)) + *options.NewXRangeOptions().SetCount(1)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1522,8 +1522,8 @@ func ExampleGlideClient_XRevRange() { streamId1 := "12345-1" streamId2 := "12345-2" - client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId(streamId1)) - client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, options.NewXAddOptions().SetId(streamId2)) + client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId(streamId1)) + client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, *options.NewXAddOptions().SetId(streamId2)) response, err := client.XRevRange(key, options.NewStreamBoundary(streamId2, true), @@ -1542,8 +1542,8 @@ func ExampleGlideClusterClient_XRevRange() { streamId1 := "12345-1" streamId2 := "12345-2" - client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId(streamId1)) - client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, options.NewXAddOptions().SetId(streamId2)) + client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId(streamId1)) + client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, *options.NewXAddOptions().SetId(streamId2)) response, err := client.XRevRange(key, options.NewStreamBoundary(streamId2, true), @@ -1562,13 +1562,13 @@ func ExampleGlideClient_XRevRangeWithOptions() { streamId1 := "12345-1" streamId2 := "12345-2" - client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId(streamId1)) - client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, options.NewXAddOptions().SetId(streamId2)) + client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId(streamId1)) + client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, *options.NewXAddOptions().SetId(streamId2)) response, err := client.XRevRangeWithOptions(key, options.NewStreamBoundary(streamId2, true), options.NewStreamBoundary(streamId1, true), - options.NewStreamRangeOptions().SetCount(2)) + *options.NewXRangeOptions().SetCount(2)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1583,13 +1583,13 @@ func ExampleGlideClusterClient_XRevRangeWithOptions() { streamId1 := "12345-1" streamId2 := "12345-2" - client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId(streamId1)) - client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, options.NewXAddOptions().SetId(streamId2)) + client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId(streamId1)) + client.XAddWithOptions(key, [][]string{{"field2", "value2"}}, *options.NewXAddOptions().SetId(streamId2)) response, err := client.XRevRangeWithOptions(key, options.NewStreamBoundary(streamId2, true), options.NewStreamBoundary(streamId1, true), - options.NewStreamRangeOptions().SetCount(2)) + *options.NewXRangeOptions().SetCount(2)) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -1603,7 +1603,7 @@ func ExampleGlideClient_XInfoStream() { key := "12345" streamId1 := "12345-1" - client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId(streamId1)) + client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId(streamId1)) response, err := client.XInfoStream(key) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1643,7 +1643,7 @@ func ExampleGlideClusterClient_XInfoStream() { key := "12345" streamId1 := "12345-1" - client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId(streamId1)) + client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId(streamId1)) response, err := client.XInfoStream(key) if err != nil { fmt.Println("Glide example failed with an error: ", err) @@ -1687,7 +1687,7 @@ func ExampleGlideClient_XInfoStreamFullWithOptions() { value := fmt.Sprintf("value%d", i) streamId := fmt.Sprintf("%s-%d", key, i) - client.XAddWithOptions(key, [][]string{{field, value}}, options.NewXAddOptions().SetId(streamId)) + client.XAddWithOptions(key, [][]string{{field, value}}, *options.NewXAddOptions().SetId(streamId)) } options := options.NewXInfoStreamOptionsOptions().SetCount(2) @@ -1737,7 +1737,7 @@ func ExampleGlideClusterClient_XInfoStreamFullWithOptions() { value := fmt.Sprintf("value%d", i) streamId := fmt.Sprintf("%s-%d", key, i) - client.XAddWithOptions(key, [][]string{{field, value}}, options.NewXAddOptions().SetId(streamId)) + client.XAddWithOptions(key, [][]string{{field, value}}, *options.NewXAddOptions().SetId(streamId)) } options := options.NewXInfoStreamOptionsOptions().SetCount(2) diff --git a/go/api/string_commands.go b/go/api/string_commands.go index 1641742092..a653612280 100644 --- a/go/api/string_commands.go +++ b/go/api/string_commands.go @@ -2,6 +2,10 @@ package api +import ( + "github.com/valkey-io/valkey-glide/go/api/options" +) + // Supports commands and transactions for the "String" group of commands for standalone and cluster clients. // // See [valkey.io] for details. @@ -10,13 +14,13 @@ package api type StringCommands interface { Set(key string, value string) (string, error) - SetWithOptions(key string, value string, options *SetOptions) (Result[string], error) + SetWithOptions(key string, value string, options options.SetOptions) (Result[string], error) Get(key string) (Result[string], error) GetEx(key string) (Result[string], error) - GetExWithOptions(key string, options *GetExOptions) (Result[string], error) + GetExWithOptions(key string, options options.GetExOptions) (Result[string], error) MSet(keyValueMap map[string]string) (string, error) diff --git a/go/api/string_commands_test.go b/go/api/string_commands_test.go index 138e293898..63947ea4ef 100644 --- a/go/api/string_commands_test.go +++ b/go/api/string_commands_test.go @@ -4,6 +4,8 @@ package api import ( "fmt" + + "github.com/valkey-io/valkey-glide/go/api/options" ) func ExampleGlideClient_Set() { @@ -33,11 +35,11 @@ func ExampleGlideClusterClient_Set() { func ExampleGlideClient_SetWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function - options := NewSetOptionsBuilder(). - SetExpiry(NewExpiryBuilder(). - SetType(Seconds). - SetCount(uint64(5))) - result, err := client.SetWithOptions("my_key", "my_value", options) + options := options.NewSetOptions(). + SetExpiry(options.NewExpiry(). + SetType(options.Seconds). + SetCount(5)) + result, err := client.SetWithOptions("my_key", "my_value", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -49,11 +51,11 @@ func ExampleGlideClient_SetWithOptions() { func ExampleGlideClusterClient_SetWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function - options := NewSetOptionsBuilder(). - SetExpiry(NewExpiryBuilder(). - SetType(Seconds). + options := options.NewSetOptions(). + SetExpiry(options.NewExpiry(). + SetType(options.Seconds). SetCount(uint64(5))) - result, err := client.SetWithOptions("my_key", "my_value", options) + result, err := client.SetWithOptions("my_key", "my_value", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -150,11 +152,11 @@ func ExampleGlideClient_GetExWithOptions() { var client *GlideClient = getExampleGlideClient() // example helper function client.Set("my_key", "my_value") - options := NewGetExOptionsBuilder(). - SetExpiry(NewExpiryBuilder(). - SetType(Seconds). - SetCount(uint64(5))) - result, err := client.GetExWithOptions("my_key", options) + options := options.NewGetExOptions(). + SetExpiry(options.NewExpiry(). + SetType(options.Seconds). + SetCount(5)) + result, err := client.GetExWithOptions("my_key", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } @@ -171,11 +173,11 @@ func ExampleGlideClusterClient_GetExWithOptions() { var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function client.Set("my_key", "my_value") - options := NewGetExOptionsBuilder(). - SetExpiry(NewExpiryBuilder(). - SetType(Seconds). + options := options.NewGetExOptions(). + SetExpiry(options.NewExpiry(). + SetType(options.Seconds). SetCount(uint64(5))) - result, err := client.GetExWithOptions("my_key", options) + result, err := client.GetExWithOptions("my_key", *options) if err != nil { fmt.Println("Glide example failed with an error: ", err) } diff --git a/go/examples/examples.md b/go/examples/examples.md index 5309def9ee..f1509aa16f 100644 --- a/go/examples/examples.md +++ b/go/examples/examples.md @@ -2,15 +2,15 @@ Go provides native support for Examples which are a great way to document how to use the Valkey Glide Go client. Examples are also run as tests, so they can be used to ensure that the client code behaves as expected. For more details on running the example tests, or writing your own examples, please see the [Developer Guide](../DEVELOPER.md). In place of creating an arbitrary example, you can find examples for each of the supported commands in the following files: -- [bitmap_commands_test.go](./bitmap_commands_test.go) -- [connection_management_commands_test.go](./connection_management_commands_test.go) -- [generic_base_commands_test.go](./generic_base_commands_test.go) -- [generic_commands_test.go](./generic_commands_test.go) -- [hash_commands_test.go](./hash_commands_test.go) -- [hyperloglog_commands_test.go](./hyperloglog_commands_test.go) -- [list_commands_test.go](./list_commands_test.go) -- [server_management_commands_test.go](./server_management_commands_test.go) -- [set_commands_test.go](./set_commands_test.go) -- [sorted_set_commands_test.go](./sorted_set_commands_test.go) -- [stream_commands_test.go](./stream_commands_test.go) -- [string_commands_test.go](./string_commands_test.go) +- [bitmap_commands_test.go](../api/bitmap_commands_test.go) +- [connection_management_commands_test.go](../api/connection_management_commands_test.go) +- [generic_base_commands_test.go](../api/generic_base_commands_test.go) +- [generic_commands_test.go](../api/generic_commands_test.go) +- [hash_commands_test.go](../api/hash_commands_test.go) +- [hyperloglog_commands_test.go](../api/hyperloglog_commands_test.go) +- [list_commands_test.go](../api/list_commands_test.go) +- [server_management_commands_test.go](../api/server_management_commands_test.go) +- [set_commands_test.go](../api/set_commands_test.go) +- [sorted_set_commands_test.go](../api/sorted_set_commands_test.go) +- [stream_commands_test.go](../api/stream_commands_test.go) +- [string_commands_test.go](../api/string_commands_test.go) diff --git a/go/integTest/cluster_commands_test.go b/go/integTest/cluster_commands_test.go index d6da52bf18..835825fe92 100644 --- a/go/integTest/cluster_commands_test.go +++ b/go/integTest/cluster_commands_test.go @@ -6,7 +6,6 @@ import ( "strings" "github.com/stretchr/testify/assert" - "github.com/valkey-io/valkey-glide/go/api" "github.com/valkey-io/valkey-glide/go/api/config" "github.com/valkey-io/valkey-glide/go/api/options" ) @@ -59,13 +58,13 @@ func (suite *GlideTestSuite) TestInfoCluster() { } // info with option or with multiple options without route - sections := []api.Section{api.Cpu} + sections := []options.Section{options.Cpu} if suite.serverVersion >= "7.0.0" { - sections = append(sections, api.Memory) + sections = append(sections, options.Memory) } - opts := api.ClusterInfoOptions{ - InfoOptions: &api.InfoOptions{Sections: sections}, - Route: nil, + opts := options.ClusterInfoOptions{ + InfoOptions: &options.InfoOptions{Sections: sections}, + RouteOption: nil, } response, err := client.InfoWithOptions(opts) assert.NoError(t, err) @@ -77,9 +76,9 @@ func (suite *GlideTestSuite) TestInfoCluster() { } // same sections with random route - opts = api.ClusterInfoOptions{ - InfoOptions: &api.InfoOptions{Sections: sections}, - Route: config.RandomRoute.ToPtr(), + opts = options.ClusterInfoOptions{ + InfoOptions: &options.InfoOptions{Sections: sections}, + RouteOption: &options.RouteOption{Route: config.RandomRoute}, } response, err = client.InfoWithOptions(opts) assert.NoError(t, err) @@ -94,9 +93,9 @@ func (suite *GlideTestSuite) TestInfoCluster() { } // default sections, multi node route - opts = api.ClusterInfoOptions{ + opts = options.ClusterInfoOptions{ InfoOptions: nil, - Route: config.AllPrimaries.ToPtr(), + RouteOption: &options.RouteOption{Route: config.AllPrimaries}, } response, err = client.InfoWithOptions(opts) assert.NoError(t, err) @@ -152,7 +151,7 @@ func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { PingOptions: &options.PingOptions{ Message: "hello", }, - Route: nil, + RouteOption: nil, } result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) @@ -161,12 +160,11 @@ func (suite *GlideTestSuite) TestPingWithOptions_NoRoute() { func (suite *GlideTestSuite) TestPingWithOptions_WithRoute() { client := suite.defaultClusterClient() - route := config.Route(config.AllNodes) options := options.ClusterPingOptions{ PingOptions: &options.PingOptions{ Message: "hello", }, - Route: &route, + RouteOption: &options.RouteOption{Route: config.AllNodes}, } result, err := client.PingWithOptions(options) assert.Nil(suite.T(), err) @@ -180,7 +178,7 @@ func (suite *GlideTestSuite) TestPingWithOptions_InvalidRoute() { PingOptions: &options.PingOptions{ Message: "hello", }, - Route: &invalidRoute, + RouteOption: &options.RouteOption{Route: invalidRoute}, } result, err := client.PingWithOptions(options) assert.NotNil(suite.T(), err) @@ -202,8 +200,7 @@ func (suite *GlideTestSuite) TestTimeWithoutRoute() { func (suite *GlideTestSuite) TestTimeWithAllNodesRoute() { client := suite.defaultClusterClient() - route := config.Route(config.AllNodes) - options := options.RouteOption{Route: route} + options := options.RouteOption{Route: config.AllNodes} result, err := client.TimeWithOptions(options) assert.NoError(suite.T(), err) assert.NotNil(suite.T(), result) diff --git a/go/integTest/glide_test_suite_test.go b/go/integTest/glide_test_suite_test.go index 197734b541..409f18977f 100644 --- a/go/integTest/glide_test_suite_test.go +++ b/go/integTest/glide_test_suite_test.go @@ -17,6 +17,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/valkey-io/valkey-glide/go/api" "github.com/valkey-io/valkey-glide/go/api/config" + "github.com/valkey-io/valkey-glide/go/api/options" ) type GlideTestSuite struct { @@ -150,7 +151,7 @@ func getServerVersion(suite *GlideTestSuite) string { client, err := api.NewGlideClient(clientConfig) if err == nil && client != nil { defer client.Close() - info, _ := client.InfoWithOptions(api.InfoOptions{Sections: []api.Section{api.Server}}) + info, _ := client.InfoWithOptions(options.InfoOptions{Sections: []options.Section{options.Server}}) return extractServerVersion(suite, info) } } @@ -171,9 +172,9 @@ func getServerVersion(suite *GlideTestSuite) string { defer client.Close() info, _ := client.InfoWithOptions( - api.ClusterInfoOptions{ - InfoOptions: &api.InfoOptions{Sections: []api.Section{api.Server}}, - Route: config.RandomRoute.ToPtr(), + options.ClusterInfoOptions{ + InfoOptions: &options.InfoOptions{Sections: []options.Section{options.Server}}, + RouteOption: &options.RouteOption{Route: config.RandomRoute}, }, ) return extractServerVersion(suite, info.SingleValue()) diff --git a/go/integTest/json_module_test.go b/go/integTest/json_module_test.go index 7707b043e1..08fc767b48 100644 --- a/go/integTest/json_module_test.go +++ b/go/integTest/json_module_test.go @@ -6,13 +6,16 @@ import ( "strings" "github.com/stretchr/testify/assert" - "github.com/valkey-io/valkey-glide/go/api" + "github.com/valkey-io/valkey-glide/go/api/options" ) func (suite *GlideTestSuite) TestModuleVerifyJsonLoaded() { client := suite.defaultClusterClient() result, err := client.InfoWithOptions( - api.ClusterInfoOptions{InfoOptions: &api.InfoOptions{Sections: []api.Section{api.Server}}, Route: nil}, + options.ClusterInfoOptions{ + InfoOptions: &options.InfoOptions{Sections: []options.Section{options.Server}}, + RouteOption: nil, + }, ) assert.Nil(suite.T(), err) diff --git a/go/integTest/shared_commands_test.go b/go/integTest/shared_commands_test.go index cf556e11cf..eda3cf367b 100644 --- a/go/integTest/shared_commands_test.go +++ b/go/integTest/shared_commands_test.go @@ -48,8 +48,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_ReturnOldValue() { suite.runWithDefaultClients(func(client api.BaseClient) { suite.verifyOK(client.Set(keyName, initialValue)) - opts := api.NewSetOptionsBuilder().SetReturnOldValue(true) - result, err := client.SetWithOptions(keyName, anotherValue, opts) + opts := options.NewSetOptions().SetReturnOldValue(true) + result, err := client.SetWithOptions(keyName, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), initialValue, result.Value()) @@ -61,8 +61,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfExists_overwrite() { key := uuid.New().String() suite.verifyOK(client.Set(key, initialValue)) - opts := api.NewSetOptionsBuilder().SetOnlyIfExists() - result, err := client.SetWithOptions(key, anotherValue, opts) + opts := options.NewSetOptions().SetOnlyIfExists() + result, err := client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -75,8 +75,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfExists_overwrite() { func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfExists_missingKey() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() - opts := api.NewSetOptionsBuilder().SetOnlyIfExists() - result, err := client.SetWithOptions(key, anotherValue, opts) + opts := options.NewSetOptions().SetOnlyIfExists() + result, err := client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "", result.Value()) @@ -86,8 +86,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfExists_missingKey() { func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfDoesNotExist_missingKey() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() - opts := api.NewSetOptionsBuilder().SetOnlyIfDoesNotExist() - result, err := client.SetWithOptions(key, anotherValue, opts) + opts := options.NewSetOptions().SetOnlyIfDoesNotExist() + result, err := client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -100,10 +100,10 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfDoesNotExist_missingKey() func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfDoesNotExist_existingKey() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() - opts := api.NewSetOptionsBuilder().SetOnlyIfDoesNotExist() + opts := options.NewSetOptions().SetOnlyIfDoesNotExist() suite.verifyOK(client.Set(key, initialValue)) - result, err := client.SetWithOptions(key, anotherValue, opts) + result, err := client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "", result.Value()) @@ -118,8 +118,9 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfDoesNotExist_existingKey() func (suite *GlideTestSuite) TestSetWithOptions_KeepExistingExpiry() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() - opts := api.NewSetOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.Milliseconds).SetCount(uint64(2000))) - result, err := client.SetWithOptions(key, initialValue, opts) + opts := options.NewSetOptions(). + SetExpiry(options.NewExpiry().SetType(options.Milliseconds).SetCount(uint64(2000))) + result, err := client.SetWithOptions(key, initialValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -127,8 +128,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_KeepExistingExpiry() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), initialValue, result.Value()) - opts = api.NewSetOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.KeepExisting)) - result, err = client.SetWithOptions(key, anotherValue, opts) + opts = options.NewSetOptions().SetExpiry(options.NewExpiry().SetType(options.KeepExisting)) + result, err = client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -148,8 +149,9 @@ func (suite *GlideTestSuite) TestSetWithOptions_KeepExistingExpiry() { func (suite *GlideTestSuite) TestSetWithOptions_UpdateExistingExpiry() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() - opts := api.NewSetOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.Milliseconds).SetCount(uint64(100500))) - result, err := client.SetWithOptions(key, initialValue, opts) + opts := options.NewSetOptions(). + SetExpiry(options.NewExpiry().SetType(options.Milliseconds).SetCount(uint64(100500))) + result, err := client.SetWithOptions(key, initialValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -157,8 +159,9 @@ func (suite *GlideTestSuite) TestSetWithOptions_UpdateExistingExpiry() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), initialValue, result.Value()) - opts = api.NewSetOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.Milliseconds).SetCount(uint64(2000))) - result, err = client.SetWithOptions(key, anotherValue, opts) + opts = options.NewSetOptions(). + SetExpiry(options.NewExpiry().SetType(options.Milliseconds).SetCount(uint64(2000))) + result, err = client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -181,8 +184,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfEquals() { suite.verifyOK(client.Set(key, initialValue)) // successful set - opts := api.NewSetOptionsBuilder().SetOnlyIfEquals(initialValue) - result, err := client.SetWithOptions(key, anotherValue, opts) + opts := options.NewSetOptions().SetOnlyIfEquals(initialValue) + result, err := client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result.Value()) @@ -191,8 +194,8 @@ func (suite *GlideTestSuite) TestSetWithOptions_OnlyIfEquals() { assert.Equal(suite.T(), anotherValue, result.Value()) // unsuccessful set - opts = api.NewSetOptionsBuilder().SetOnlyIfEquals(initialValue) - result, err = client.SetWithOptions(key, initialValue, opts) + opts = options.NewSetOptions().SetOnlyIfEquals(initialValue) + result, err = client.SetWithOptions(key, initialValue, *opts) assert.Nil(suite.T(), err) assert.True(suite.T(), result.IsNil()) }) @@ -219,8 +222,9 @@ func (suite *GlideTestSuite) TestGetExWithOptions_PersistKey() { key := uuid.New().String() suite.verifyOK(client.Set(key, initialValue)) - opts := api.NewGetExOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.Milliseconds).SetCount(uint64(2000))) - result, err := client.GetExWithOptions(key, opts) + opts := options.NewGetExOptions(). + SetExpiry(options.NewExpiry().SetType(options.Milliseconds).SetCount(uint64(2000))) + result, err := client.GetExWithOptions(key, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), initialValue, result.Value()) @@ -230,8 +234,8 @@ func (suite *GlideTestSuite) TestGetExWithOptions_PersistKey() { time.Sleep(1000 * time.Millisecond) - opts = api.NewGetExOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.Persist)) - result, err = client.GetExWithOptions(key, opts) + opts = options.NewGetExOptions().SetExpiry(options.NewExpiry().SetType(options.Persist)) + result, err = client.GetExWithOptions(key, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), initialValue, result.Value()) }) @@ -242,8 +246,9 @@ func (suite *GlideTestSuite) TestGetExWithOptions_UpdateExpiry() { key := uuid.New().String() suite.verifyOK(client.Set(key, initialValue)) - opts := api.NewGetExOptionsBuilder().SetExpiry(api.NewExpiryBuilder().SetType(api.Milliseconds).SetCount(uint64(2000))) - result, err := client.GetExWithOptions(key, opts) + opts := options.NewGetExOptions(). + SetExpiry(options.NewExpiry().SetType(options.Milliseconds).SetCount(uint64(2000))) + result, err := client.GetExWithOptions(key, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), initialValue, result.Value()) @@ -262,9 +267,9 @@ func (suite *GlideTestSuite) TestGetExWithOptions_UpdateExpiry() { func (suite *GlideTestSuite) TestSetWithOptions_ReturnOldValue_nonExistentKey() { suite.runWithDefaultClients(func(client api.BaseClient) { key := uuid.New().String() - opts := api.NewSetOptionsBuilder().SetReturnOldValue(true) + opts := options.NewSetOptions().SetReturnOldValue(true) - result, err := client.SetWithOptions(key, anotherValue, opts) + result, err := client.SetWithOptions(key, anotherValue, *opts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "", result.Value()) @@ -1165,8 +1170,8 @@ func (suite *GlideTestSuite) TestHScan() { assert.True(t, isSubset(resultKeys, keysList) && isSubset(keysList, resultKeys)) assert.True(t, isSubset(resultValues, valuesList) && isSubset(valuesList, resultValues)) - opts := options.NewHashScanOptionsBuilder().SetMatch("a") - resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, opts) + opts := options.NewHashScanOptions().SetMatch("a") + resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, *opts) assert.Equal(t, initialCursor, resCursor) assert.Equal(t, len(resCollection), 2) assert.Equal(t, resCollection[0], "a") @@ -1221,29 +1226,29 @@ func (suite *GlideTestSuite) TestHScan() { assert.True(t, isSubset(numberValuesList, secondResultAllValues)) // Test match pattern - opts = options.NewHashScanOptionsBuilder().SetMatch("*") - resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, opts) + opts = options.NewHashScanOptions().SetMatch("*") + resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, *opts) resCursorInt, _ := strconv.Atoi(resCursor) assert.True(t, resCursorInt >= 0) assert.True(t, int(len(resCollection)) >= defaultCount) // Test count - opts = options.NewHashScanOptionsBuilder().SetCount(int64(20)) - resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, opts) + opts = options.NewHashScanOptions().SetCount(int64(20)) + resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, *opts) resCursorInt, _ = strconv.Atoi(resCursor) assert.True(t, resCursorInt >= 0) assert.True(t, len(resCollection) >= 20) // Test count with match returns a non-empty list - opts = options.NewHashScanOptionsBuilder().SetMatch("1*").SetCount(int64(20)) - resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, opts) + opts = options.NewHashScanOptions().SetMatch("1*").SetCount(int64(20)) + resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, *opts) resCursorInt, _ = strconv.Atoi(resCursor) assert.True(t, resCursorInt >= 0) assert.True(t, len(resCollection) >= 0) if suite.serverVersion >= "8.0.0" { - opts = options.NewHashScanOptionsBuilder().SetNoValue(true) - resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, opts) + opts = options.NewHashScanOptions().SetNoValue(true) + resCursor, resCollection, _ = client.HScanWithOptions(key1, initialCursor, *opts) resCursorInt, _ = strconv.Atoi(resCursor) assert.True(t, resCursorInt >= 0) @@ -1264,13 +1269,13 @@ func (suite *GlideTestSuite) TestHScan() { assert.NotEmpty(t, err) // Check if Non-hash key throws an error when HSCAN called with options. - opts = options.NewHashScanOptionsBuilder().SetMatch("test").SetCount(int64(1)) - _, _, err = client.HScanWithOptions(key2, initialCursor, opts) + opts = options.NewHashScanOptions().SetMatch("test").SetCount(int64(1)) + _, _, err = client.HScanWithOptions(key2, initialCursor, *opts) assert.NotEmpty(t, err) // Check if a negative cursor value throws an error. - opts = options.NewHashScanOptionsBuilder().SetCount(int64(-1)) - _, _, err = client.HScanWithOptions(key1, initialCursor, opts) + opts = options.NewHashScanOptions().SetCount(int64(-1)) + _, _, err = client.HScanWithOptions(key1, initialCursor, *opts) assert.NotEmpty(t, err) }) } @@ -1407,7 +1412,7 @@ func (suite *GlideTestSuite) TestLPos_withAndWithoutOptions() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), res2.Value()) - res3, err := client.LPosWithOptions(key, "b", api.NewLPosOptionsBuilder().SetRank(2)) + res3, err := client.LPosWithOptions(key, "b", *options.NewLPosOptions().SetRank(2)) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(5), res3.Value()) @@ -1417,7 +1422,7 @@ func (suite *GlideTestSuite) TestLPos_withAndWithoutOptions() { assert.Equal(suite.T(), api.CreateNilInt64Result(), res4) // reverse traversal - res5, err := client.LPosWithOptions(key, "b", api.NewLPosOptionsBuilder().SetRank(-2)) + res5, err := client.LPosWithOptions(key, "b", *options.NewLPosOptions().SetRank(-2)) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(2), res5.Value()) @@ -1425,7 +1430,7 @@ func (suite *GlideTestSuite) TestLPos_withAndWithoutOptions() { res6, err := client.LPosWithOptions( key, "a", - api.NewLPosOptionsBuilder().SetRank(1).SetMaxLen(0), + *options.NewLPosOptions().SetRank(1).SetMaxLen(0), ) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), res6.Value()) @@ -1434,19 +1439,19 @@ func (suite *GlideTestSuite) TestLPos_withAndWithoutOptions() { res7, err := client.LPosWithOptions( key, "c", - api.NewLPosOptionsBuilder().SetRank(1).SetMaxLen(2), + *options.NewLPosOptions().SetRank(1).SetMaxLen(2), ) assert.Nil(suite.T(), err) assert.Equal(suite.T(), api.CreateNilInt64Result(), res7) // invalid rank value - res8, err := client.LPosWithOptions(key, "a", api.NewLPosOptionsBuilder().SetRank(0)) + res8, err := client.LPosWithOptions(key, "a", *options.NewLPosOptions().SetRank(0)) assert.Equal(suite.T(), api.CreateNilInt64Result(), res8) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) // invalid maxlen value - res9, err := client.LPosWithOptions(key, "a", api.NewLPosOptionsBuilder().SetMaxLen(-1)) + res9, err := client.LPosWithOptions(key, "a", *options.NewLPosOptions().SetMaxLen(-1)) assert.Equal(suite.T(), api.CreateNilInt64Result(), res9) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -1511,16 +1516,16 @@ func (suite *GlideTestSuite) TestLPosCount_withOptions() { assert.Equal(suite.T(), int64(6), res1) assert.Nil(suite.T(), err) - res2, err := client.LPosCountWithOptions(key, "a", int64(0), api.NewLPosOptionsBuilder().SetRank(1)) + res2, err := client.LPosCountWithOptions(key, "a", int64(0), *options.NewLPosOptions().SetRank(1)) assert.Equal(suite.T(), []int64{0, 1, 4}, res2) assert.Nil(suite.T(), err) - res3, err := client.LPosCountWithOptions(key, "a", int64(0), api.NewLPosOptionsBuilder().SetRank(2)) + res3, err := client.LPosCountWithOptions(key, "a", int64(0), *options.NewLPosOptions().SetRank(2)) assert.Equal(suite.T(), []int64{1, 4}, res3) assert.Nil(suite.T(), err) // reverse traversal - res4, err := client.LPosCountWithOptions(key, "a", int64(0), api.NewLPosOptionsBuilder().SetRank(-1)) + res4, err := client.LPosCountWithOptions(key, "a", int64(0), *options.NewLPosOptions().SetRank(-1)) assert.Equal(suite.T(), []int64{4, 1, 0}, res4) assert.Nil(suite.T(), err) }) @@ -2359,8 +2364,8 @@ func (suite *GlideTestSuite) TestSScan() { assert.Equal(t, len(charMembers), len(resCollection)) assert.True(t, isSubset(resCollection, charMembers)) - opts := options.NewBaseScanOptionsBuilder().SetMatch("a") - resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, opts) + opts := options.NewBaseScanOptions().SetMatch("a") + resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, *opts) assert.NoError(t, err) assert.Equal(t, initialCursor, resCursor) assert.True(t, isSubset(resCollection, []string{"a"})) @@ -2387,22 +2392,22 @@ func (suite *GlideTestSuite) TestSScan() { assert.True(t, isSubset(charMembers, resultCollection)) // test match pattern - opts = options.NewBaseScanOptionsBuilder().SetMatch("*") - resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, opts) + opts = options.NewBaseScanOptions().SetMatch("*") + resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, *opts) assert.NoError(t, err) assert.NotEqual(t, initialCursor, resCursor) assert.GreaterOrEqual(t, len(resCollection), defaultCount) // test count - opts = options.NewBaseScanOptionsBuilder().SetCount(20) - resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, opts) + opts = options.NewBaseScanOptions().SetCount(20) + resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, *opts) assert.NoError(t, err) assert.NotEqual(t, initialCursor, resCursor) assert.GreaterOrEqual(t, len(resCollection), 20) // test count with match, returns a non-empty array - opts = options.NewBaseScanOptionsBuilder().SetMatch("1*").SetCount(20) - resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, opts) + opts = options.NewBaseScanOptions().SetMatch("1*").SetCount(20) + resCursor, resCollection, err = client.SScanWithOptions(key1, initialCursor, *opts) assert.NoError(t, err) assert.NotEqual(t, initialCursor, resCursor) assert.GreaterOrEqual(t, len(resCollection), 0) @@ -2622,11 +2627,11 @@ func (suite *GlideTestSuite) TestLInsert() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(4), res1) - res2, err := client.LInsert(key, api.Before, "value2", "value1.5") + res2, err := client.LInsert(key, options.Before, "value2", "value1.5") assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(5), res2) - res3, err := client.LInsert(key, api.After, "value3", "value3.5") + res3, err := client.LInsert(key, options.After, "value3", "value3.5") assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(6), res3) @@ -2634,18 +2639,18 @@ func (suite *GlideTestSuite) TestLInsert() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), []string{"value1", "value1.5", "value2", "value3", "value3.5", "value4"}, res4) - res5, err := client.LInsert("non_existing_key", api.Before, "pivot", "elem") + res5, err := client.LInsert("non_existing_key", options.Before, "pivot", "elem") assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), res5) - res6, err := client.LInsert(key, api.Before, "value5", "value6") + res6, err := client.LInsert(key, options.Before, "value5", "value6") assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(-1), res6) key2 := uuid.NewString() suite.verifyOK(client.Set(key2, "value")) - res7, err := client.LInsert(key2, api.Before, "value5", "value6") + res7, err := client.LInsert(key2, options.Before, "value5", "value6") assert.Equal(suite.T(), int64(0), res7) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -2795,11 +2800,11 @@ func (suite *GlideTestSuite) TestLMPopAndLMPopCount() { key2 := "{key}-2" + uuid.NewString() key3 := "{key}-3" + uuid.NewString() - res1, err := client.LMPop([]string{key1}, api.Left) + res1, err := client.LMPop([]string{key1}, options.Left) assert.Nil(suite.T(), err) assert.Nil(suite.T(), res1) - res2, err := client.LMPopCount([]string{key1}, api.Left, int64(1)) + res2, err := client.LMPopCount([]string{key1}, options.Left, int64(1)) assert.Nil(suite.T(), err) assert.Nil(suite.T(), res2) @@ -2810,7 +2815,7 @@ func (suite *GlideTestSuite) TestLMPopAndLMPopCount() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(5), res4) - res5, err := client.LMPop([]string{key1}, api.Left) + res5, err := client.LMPop([]string{key1}, options.Left) assert.Nil(suite.T(), err) assert.Equal( suite.T(), @@ -2818,7 +2823,7 @@ func (suite *GlideTestSuite) TestLMPopAndLMPopCount() { res5, ) - res6, err := client.LMPopCount([]string{key2, key1}, api.Right, int64(2)) + res6, err := client.LMPopCount([]string{key2, key1}, options.Right, int64(2)) assert.Nil(suite.T(), err) assert.Equal( suite.T(), @@ -2830,7 +2835,7 @@ func (suite *GlideTestSuite) TestLMPopAndLMPopCount() { suite.verifyOK(client.Set(key3, "value")) - res7, err := client.LMPop([]string{key3}, api.Left) + res7, err := client.LMPop([]string{key3}, options.Left) assert.Nil(suite.T(), res7) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -2851,11 +2856,11 @@ func (suite *GlideTestSuite) TestBLMPopAndBLMPopCount() { key2 := "{key}-2" + uuid.NewString() key3 := "{key}-3" + uuid.NewString() - res1, err := client.BLMPop([]string{key1}, api.Left, float64(0.1)) + res1, err := client.BLMPop([]string{key1}, options.Left, float64(0.1)) assert.Nil(suite.T(), err) assert.Nil(suite.T(), res1) - res2, err := client.BLMPopCount([]string{key1}, api.Left, int64(1), float64(0.1)) + res2, err := client.BLMPopCount([]string{key1}, options.Left, int64(1), float64(0.1)) assert.Nil(suite.T(), err) assert.Nil(suite.T(), res2) @@ -2866,7 +2871,7 @@ func (suite *GlideTestSuite) TestBLMPopAndBLMPopCount() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(5), res4) - res5, err := client.BLMPop([]string{key1}, api.Left, float64(0.1)) + res5, err := client.BLMPop([]string{key1}, options.Left, float64(0.1)) assert.Nil(suite.T(), err) assert.Equal( suite.T(), @@ -2874,7 +2879,7 @@ func (suite *GlideTestSuite) TestBLMPopAndBLMPopCount() { res5, ) - res6, err := client.BLMPopCount([]string{key2, key1}, api.Right, int64(2), float64(0.1)) + res6, err := client.BLMPopCount([]string{key2, key1}, options.Right, int64(2), float64(0.1)) assert.Nil(suite.T(), err) assert.Equal( suite.T(), @@ -2886,7 +2891,7 @@ func (suite *GlideTestSuite) TestBLMPopAndBLMPopCount() { suite.verifyOK(client.Set(key3, "value")) - res7, err := client.BLMPop([]string{key3}, api.Left, float64(0.1)) + res7, err := client.BLMPop([]string{key3}, options.Left, float64(0.1)) assert.Nil(suite.T(), res7) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -2902,7 +2907,7 @@ func (suite *GlideTestSuite) TestBZMPopAndBZMPopWithOptions() { key2 := "{key}-2" + uuid.NewString() key3 := "{key}-3" + uuid.NewString() - res1, err := client.BZMPop([]string{key1}, api.MIN, float64(0.1)) + res1, err := client.BZMPop([]string{key1}, options.MIN, float64(0.1)) assert.Nil(suite.T(), err) assert.True(suite.T(), res1.IsNil()) @@ -2920,7 +2925,12 @@ func (suite *GlideTestSuite) TestBZMPopAndBZMPopWithOptions() { assert.Equal(suite.T(), int64(3), res4) // Try to pop the top 2 elements from key1 - res5, err := client.BZMPopWithOptions([]string{key1}, api.MAX, float64(0.1), options.NewZMPopOptions().SetCount(2)) + res5, err := client.BZMPopWithOptions( + []string{key1}, + options.MAX, + float64(0.1), + *options.NewZMPopOptions().SetCount(2), + ) assert.Nil(suite.T(), err) assert.Equal(suite.T(), key1, res5.Value().Key) assert.ElementsMatch( @@ -2933,7 +2943,7 @@ func (suite *GlideTestSuite) TestBZMPopAndBZMPopWithOptions() { ) // Try to pop the minimum value from key2 - res6, err := client.BZMPop([]string{key2}, api.MIN, float64(0.1)) + res6, err := client.BZMPop([]string{key2}, options.MIN, float64(0.1)) assert.Nil(suite.T(), err) assert.Equal( suite.T(), @@ -2949,7 +2959,7 @@ func (suite *GlideTestSuite) TestBZMPopAndBZMPopWithOptions() { ) // Pop the minimum value from multiple keys - res7, err := client.BZMPop([]string{key1, key2}, api.MIN, float64(0.1)) + res7, err := client.BZMPop([]string{key1, key2}, options.MIN, float64(0.1)) assert.Nil(suite.T(), err) assert.Equal( suite.T(), @@ -2967,7 +2977,7 @@ func (suite *GlideTestSuite) TestBZMPopAndBZMPopWithOptions() { suite.verifyOK(client.Set(key3, "value")) // Popping a non-existent value in key3 - res8, err := client.BZMPop([]string{key3}, api.MIN, float64(0.1)) + res8, err := client.BZMPop([]string{key3}, options.MIN, float64(0.1)) assert.True(suite.T(), res8.IsNil()) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -3015,7 +3025,7 @@ func (suite *GlideTestSuite) TestLMove() { nonExistentKey := "{key}-3" + uuid.NewString() nonListKey := "{key}-4" + uuid.NewString() - res1, err := client.LMove(key1, key2, api.Left, api.Right) + res1, err := client.LMove(key1, key2, options.Left, options.Right) assert.Equal(suite.T(), api.CreateNilStringResult(), res1) assert.Nil(suite.T(), err) @@ -3024,7 +3034,7 @@ func (suite *GlideTestSuite) TestLMove() { assert.Equal(suite.T(), int64(4), res2) // only source exists, only source elements gets popped, creates a list at nonExistingKey - res3, err := client.LMove(key1, nonExistentKey, api.Right, api.Left) + res3, err := client.LMove(key1, nonExistentKey, options.Right, options.Left) assert.Equal(suite.T(), "four", res3.Value()) assert.Nil(suite.T(), err) @@ -3033,7 +3043,7 @@ func (suite *GlideTestSuite) TestLMove() { assert.Equal(suite.T(), []string{"one", "two", "three"}, res4) // source and destination are the same, performing list rotation, "one" gets popped and added back - res5, err := client.LMove(key1, key1, api.Left, api.Left) + res5, err := client.LMove(key1, key1, options.Left, options.Left) assert.Equal(suite.T(), "one", res5.Value()) assert.Nil(suite.T(), err) @@ -3045,7 +3055,7 @@ func (suite *GlideTestSuite) TestLMove() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(3), res7) - res8, err := client.LMove(key1, key2, api.Right, api.Left) + res8, err := client.LMove(key1, key2, options.Right, options.Left) assert.Equal(suite.T(), "three", res8.Value()) assert.Nil(suite.T(), err) @@ -3059,7 +3069,7 @@ func (suite *GlideTestSuite) TestLMove() { // source exists but is not a list type key suite.verifyOK(client.Set(nonListKey, "value")) - res11, err := client.LMove(nonListKey, key1, api.Left, api.Left) + res11, err := client.LMove(nonListKey, key1, options.Left, options.Left) assert.Equal(suite.T(), api.CreateNilStringResult(), res11) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -3067,7 +3077,7 @@ func (suite *GlideTestSuite) TestLMove() { // destination exists but is not a list type key suite.verifyOK(client.Set(nonListKey, "value")) - res12, err := client.LMove(key1, nonListKey, api.Left, api.Left) + res12, err := client.LMove(key1, nonListKey, options.Left, options.Left) assert.Equal(suite.T(), api.CreateNilStringResult(), res12) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -3137,7 +3147,7 @@ func (suite *GlideTestSuite) TestExpireWithOptions_HasNoExpiry() { suite.verifyOK(client.Set(key, value)) - result, err := client.ExpireWithOptions(key, 2, api.HasNoExpiry) + result, err := client.ExpireWithOptions(key, 2, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), result) @@ -3147,7 +3157,7 @@ func (suite *GlideTestSuite) TestExpireWithOptions_HasNoExpiry() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), "", resultGet.Value()) - result, err = client.ExpireWithOptions(key, 1, api.HasNoExpiry) + result, err = client.ExpireWithOptions(key, 1, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.False(suite.T(), result) }) @@ -3161,11 +3171,11 @@ func (suite *GlideTestSuite) TestExpireWithOptions_HasExistingExpiry() { suite.verifyOK(client.Set(key, value)) - resexp, err := client.ExpireWithOptions(key, 20, api.HasNoExpiry) + resexp, err := client.ExpireWithOptions(key, 20, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resexp) - resultExpire, err := client.ExpireWithOptions(key, 1, api.HasExistingExpiry) + resultExpire, err := client.ExpireWithOptions(key, 1, options.HasExistingExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) @@ -3185,11 +3195,11 @@ func (suite *GlideTestSuite) TestExpireWithOptions_NewExpiryGreaterThanCurrent() value := uuid.New().String() suite.verifyOK(client.Set(key, value)) - resultExpire, err := client.ExpireWithOptions(key, 2, api.HasNoExpiry) + resultExpire, err := client.ExpireWithOptions(key, 2, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) - resultExpire, err = client.ExpireWithOptions(key, 5, api.NewExpiryGreaterThanCurrent) + resultExpire, err = client.ExpireWithOptions(key, 5, options.NewExpiryGreaterThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) time.Sleep(6 * time.Second) @@ -3207,16 +3217,16 @@ func (suite *GlideTestSuite) TestExpireWithOptions_NewExpiryLessThanCurrent() { suite.verifyOK(client.Set(key, value)) - resultExpire, err := client.ExpireWithOptions(key, 10, api.HasNoExpiry) + resultExpire, err := client.ExpireWithOptions(key, 10, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) - resultExpire, err = client.ExpireWithOptions(key, 5, api.NewExpiryLessThanCurrent) + resultExpire, err = client.ExpireWithOptions(key, 5, options.NewExpiryLessThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) - resultExpire, err = client.ExpireWithOptions(key, 15, api.NewExpiryGreaterThanCurrent) + resultExpire, err = client.ExpireWithOptions(key, 15, options.NewExpiryGreaterThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) @@ -3237,13 +3247,13 @@ func (suite *GlideTestSuite) TestExpireAtWithOptions_HasNoExpiry() { futureTimestamp := time.Now().Add(10 * time.Second).Unix() - resultExpire, err := client.ExpireAtWithOptions(key, futureTimestamp, api.HasNoExpiry) + resultExpire, err := client.ExpireAtWithOptions(key, futureTimestamp, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpire) resultExpireAt, err := client.ExpireAt(key, futureTimestamp) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireAt) - resultExpireWithOptions, err := client.ExpireAtWithOptions(key, futureTimestamp+10, api.HasNoExpiry) + resultExpireWithOptions, err := client.ExpireAtWithOptions(key, futureTimestamp+10, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.False(suite.T(), resultExpireWithOptions) }) @@ -3261,7 +3271,7 @@ func (suite *GlideTestSuite) TestExpireAtWithOptions_HasExistingExpiry() { assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireAt) - resultExpireWithOptions, err := client.ExpireAtWithOptions(key, futureTimestamp+10, api.HasExistingExpiry) + resultExpireWithOptions, err := client.ExpireAtWithOptions(key, futureTimestamp+10, options.HasExistingExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) }) @@ -3281,7 +3291,11 @@ func (suite *GlideTestSuite) TestExpireAtWithOptions_NewExpiryGreaterThanCurrent assert.True(suite.T(), resultExpireAt) newFutureTimestamp := time.Now().Add(20 * time.Second).Unix() - resultExpireWithOptions, err := client.ExpireAtWithOptions(key, newFutureTimestamp, api.NewExpiryGreaterThanCurrent) + resultExpireWithOptions, err := client.ExpireAtWithOptions( + key, + newFutureTimestamp, + options.NewExpiryGreaterThanCurrent, + ) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) }) @@ -3301,7 +3315,7 @@ func (suite *GlideTestSuite) TestExpireAtWithOptions_NewExpiryLessThanCurrent() assert.True(suite.T(), resultExpireAt) newFutureTimestamp := time.Now().Add(5 * time.Second).Unix() - resultExpireWithOptions, err := client.ExpireAtWithOptions(key, newFutureTimestamp, api.NewExpiryLessThanCurrent) + resultExpireWithOptions, err := client.ExpireAtWithOptions(key, newFutureTimestamp, options.NewExpiryLessThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3346,7 +3360,7 @@ func (suite *GlideTestSuite) TestPExpireWithOptions_HasExistingExpiry() { newExpire := 1000 - resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), api.HasExistingExpiry) + resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), options.HasExistingExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3367,7 +3381,7 @@ func (suite *GlideTestSuite) TestPExpireWithOptions_HasNoExpiry() { newExpire := 500 - resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), api.HasNoExpiry) + resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3393,7 +3407,7 @@ func (suite *GlideTestSuite) TestPExpireWithOptions_NewExpiryGreaterThanCurrent( newExpire := 1000 - resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), api.NewExpiryGreaterThanCurrent) + resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), options.NewExpiryGreaterThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3419,7 +3433,7 @@ func (suite *GlideTestSuite) TestPExpireWithOptions_NewExpiryLessThanCurrent() { newExpire := 200 - resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), api.NewExpiryLessThanCurrent) + resultExpireWithOptions, err := client.PExpireWithOptions(key, int64(newExpire), options.NewExpiryLessThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3459,7 +3473,7 @@ func (suite *GlideTestSuite) TestPExpireAtWithOptions_HasNoExpiry() { suite.verifyOK(client.Set(key, value)) timestamp := time.Now().Unix() * 1000 - result, err := client.PExpireAtWithOptions(key, timestamp, api.HasNoExpiry) + result, err := client.PExpireAtWithOptions(key, timestamp, options.HasNoExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), result) @@ -3484,7 +3498,7 @@ func (suite *GlideTestSuite) TestPExpireAtWithOptions_HasExistingExpiry() { assert.True(suite.T(), resultExpire) newExpire := time.Now().Unix()*1000 + 1000 - resultExpireWithOptions, err := client.PExpireAtWithOptions(key, newExpire, api.HasExistingExpiry) + resultExpireWithOptions, err := client.PExpireAtWithOptions(key, newExpire, options.HasExistingExpiry) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3510,7 +3524,7 @@ func (suite *GlideTestSuite) TestPExpireAtWithOptions_NewExpiryGreaterThanCurren newExpire := time.Now().UnixMilli() + 2000 - resultExpireWithOptions, err := client.PExpireAtWithOptions(key, newExpire, api.NewExpiryGreaterThanCurrent) + resultExpireWithOptions, err := client.PExpireAtWithOptions(key, newExpire, options.NewExpiryGreaterThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3536,7 +3550,7 @@ func (suite *GlideTestSuite) TestPExpireAtWithOptions_NewExpiryLessThanCurrent() newExpire := time.Now().Unix()*1000 + 500 - resultExpireWithOptions, err := client.PExpireAtWithOptions(key, newExpire, api.NewExpiryLessThanCurrent) + resultExpireWithOptions, err := client.PExpireAtWithOptions(key, newExpire, options.NewExpiryLessThanCurrent) assert.Nil(suite.T(), err) assert.True(suite.T(), resultExpireWithOptions) @@ -3814,7 +3828,7 @@ func (suite *GlideTestSuite) TestSortWithOptions_AscendingOrder() { SetOrderBy(options.ASC). SetIsAlpha(true) - sortResult, err := client.SortWithOptions(key, options) + sortResult, err := client.SortWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -3837,7 +3851,7 @@ func (suite *GlideTestSuite) TestSortWithOptions_DescendingOrder() { SetIsAlpha(true). SetSortLimit(0, 3) - sortResult, err := client.SortWithOptions(key, options) + sortResult, err := client.SortWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -3904,7 +3918,7 @@ func (suite *GlideTestSuite) TestSortStoreWithOptions_DescendingOrder() { client.LPush(key, []string{"30", "20", "10", "40", "50"}) options := options.NewSortOptions().SetOrderBy(options.DESC).SetIsAlpha(false) - result, err := client.SortStoreWithOptions(key, sortedKey, options) + result, err := client.SortStoreWithOptions(key, sortedKey, *options) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), result) @@ -3923,7 +3937,7 @@ func (suite *GlideTestSuite) TestSortStoreWithOptions_AlphaSorting() { client.LPush(key, []string{"apple", "banana", "cherry", "date", "elderberry"}) options := options.NewSortOptions().SetIsAlpha(true) - result, err := client.SortStoreWithOptions(key, sortedKey, options) + result, err := client.SortStoreWithOptions(key, sortedKey, *options) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), result) @@ -3943,7 +3957,7 @@ func (suite *GlideTestSuite) TestSortStoreWithOptions_Limit() { client.LPush(key, []string{"10", "20", "30", "40", "50"}) options := options.NewSortOptions().SetSortLimit(1, 3) - result, err := client.SortStoreWithOptions(key, sortedKey, options) + result, err := client.SortStoreWithOptions(key, sortedKey, *options) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), result) @@ -3986,7 +4000,7 @@ func (suite *GlideTestSuite) TestSortReadyOnlyWithOptions_DescendingOrder() { SetIsAlpha(true). SetSortLimit(0, 3) - sortResult, err := client.SortReadOnlyWithOptions(key, options) + sortResult, err := client.SortReadOnlyWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -4009,7 +4023,7 @@ func (suite *GlideTestSuite) TestBLMove() { nonExistentKey := "{key}-3" + uuid.NewString() nonListKey := "{key}-4" + uuid.NewString() - res1, err := client.BLMove(key1, key2, api.Left, api.Right, float64(0.1)) + res1, err := client.BLMove(key1, key2, options.Left, options.Right, float64(0.1)) assert.Equal(suite.T(), api.CreateNilStringResult(), res1) assert.Nil(suite.T(), err) @@ -4018,7 +4032,7 @@ func (suite *GlideTestSuite) TestBLMove() { assert.Equal(suite.T(), int64(4), res2) // only source exists, only source elements gets popped, creates a list at nonExistingKey - res3, err := client.BLMove(key1, nonExistentKey, api.Right, api.Left, float64(0.1)) + res3, err := client.BLMove(key1, nonExistentKey, options.Right, options.Left, float64(0.1)) assert.Equal(suite.T(), "four", res3.Value()) assert.Nil(suite.T(), err) @@ -4027,7 +4041,7 @@ func (suite *GlideTestSuite) TestBLMove() { assert.Equal(suite.T(), []string{"one", "two", "three"}, res4) // source and destination are the same, performing list rotation, "one" gets popped and added back - res5, err := client.BLMove(key1, key1, api.Left, api.Left, float64(0.1)) + res5, err := client.BLMove(key1, key1, options.Left, options.Left, float64(0.1)) assert.Equal(suite.T(), "one", res5.Value()) assert.Nil(suite.T(), err) @@ -4039,7 +4053,7 @@ func (suite *GlideTestSuite) TestBLMove() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(3), res7) - res8, err := client.BLMove(key1, key2, api.Right, api.Left, float64(0.1)) + res8, err := client.BLMove(key1, key2, options.Right, options.Left, float64(0.1)) assert.Equal(suite.T(), "three", res8.Value()) assert.Nil(suite.T(), err) @@ -4054,7 +4068,7 @@ func (suite *GlideTestSuite) TestBLMove() { // source exists but is not a list type key suite.verifyOK(client.Set(nonListKey, "value")) - res11, err := client.BLMove(nonListKey, key1, api.Left, api.Left, float64(0.1)) + res11, err := client.BLMove(nonListKey, key1, options.Left, options.Left, float64(0.1)) assert.Equal(suite.T(), api.CreateNilStringResult(), res11) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -4062,7 +4076,7 @@ func (suite *GlideTestSuite) TestBLMove() { // destination exists but is not a list type key suite.verifyOK(client.Set(nonListKey, "value")) - res12, err := client.BLMove(key1, nonListKey, api.Left, api.Left, float64(0.1)) + res12, err := client.BLMove(key1, nonListKey, options.Left, options.Left, float64(0.1)) assert.Equal(suite.T(), api.CreateNilStringResult(), res12) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -4229,13 +4243,13 @@ func (suite *GlideTestSuite) TestXAddWithOptions() { res, err := client.XAddWithOptions( key, [][]string{{"field1", "value1"}}, - options.NewXAddOptions().SetDontMakeNewStream(), + *options.NewXAddOptions().SetDontMakeNewStream(), ) assert.Nil(suite.T(), err) assert.True(suite.T(), res.IsNil()) // adding data to with given ID - res, err = client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, options.NewXAddOptions().SetId("0-1")) + res, err = client.XAddWithOptions(key, [][]string{{"field1", "value1"}}, *options.NewXAddOptions().SetId("0-1")) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "0-1", res.Value()) @@ -4245,7 +4259,7 @@ func (suite *GlideTestSuite) TestXAddWithOptions() { res, err = client.XAddWithOptions( key, [][]string{{"field3", "value3"}}, - options.NewXAddOptions().SetTrimOptions(options.NewXTrimOptionsWithMaxLen(2).SetExactTrimming()), + *options.NewXAddOptions().SetTrimOptions(options.NewXTrimOptionsWithMaxLen(2).SetExactTrimming()), ) assert.Nil(suite.T(), err) assert.False(suite.T(), res.IsNil()) @@ -4292,14 +4306,14 @@ func (suite *GlideTestSuite) TestXAutoClaim() { xadd, err := client.XAddWithOptions( key, [][]string{{"entry1_field1", "entry1_value1"}, {"entry1_field2", "entry1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "0-1", xadd.Value()) xadd, err = client.XAddWithOptions( key, [][]string{{"entry2_field1", "entry2_value1"}}, - options.NewXAddOptions().SetId("0-2"), + *options.NewXAddOptions().SetId("0-2"), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "0-2", xadd.Value()) @@ -4313,8 +4327,8 @@ func (suite *GlideTestSuite) TestXAutoClaim() { }, }, xreadgroup) - opts := options.NewXAutoClaimOptionsWithCount(1) - xautoclaim, err := client.XAutoClaimWithOptions(key, group, consumer, 0, "0-0", opts) + opts := options.NewXAutoClaimOptions().SetCount(1) + xautoclaim, err := client.XAutoClaimWithOptions(key, group, consumer, 0, "0-0", *opts) assert.NoError(suite.T(), err) var deletedEntries []string if suite.serverVersion >= "7.0.0" { @@ -4348,7 +4362,7 @@ func (suite *GlideTestSuite) TestXAutoClaim() { xadd, err = client.XAddWithOptions( key, [][]string{{"entry3_field1", "entry3_value1"}}, - options.NewXAddOptions().SetId("0-3"), + *options.NewXAddOptions().SetId("0-3"), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "0-3", xadd.Value()) @@ -4524,12 +4538,16 @@ func (suite *GlideTestSuite) TestXRead() { res, err := client.XAddWithOptions( key1, [][]string{{"k1_field1", "k1_value1"}, {"k1_field1", "k1_value2"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) assert.Nil(suite.T(), err) assert.False(suite.T(), res.IsNil()) - res, err = client.XAddWithOptions(key2, [][]string{{"k2_field1", "k2_value1"}}, options.NewXAddOptions().SetId("2-0")) + res, err = client.XAddWithOptions( + key2, + [][]string{{"k2_field1", "k2_value1"}}, + *options.NewXAddOptions().SetId("2-0"), + ) assert.Nil(suite.T(), err) assert.False(suite.T(), res.IsNil()) @@ -4566,7 +4584,10 @@ func (suite *GlideTestSuite) TestXRead() { WithAddress(&suite.clusterHosts[0]). WithUseTLS(suite.tls)) } - read, err = testClient.XReadWithOptions(map[string]string{key1: "0-1"}, options.NewXReadOptions().SetBlock(1000)) + read, err = testClient.XReadWithOptions( + map[string]string{key1: "0-1"}, + *options.NewXReadOptions().SetBlock(1000), + ) assert.Nil(suite.T(), err) assert.Nil(suite.T(), read) @@ -4574,7 +4595,7 @@ func (suite *GlideTestSuite) TestXRead() { // but we wrap the test with timeout to avoid test failing or stuck forever finished := make(chan bool) go func() { - testClient.XReadWithOptions(map[string]string{key1: "0-1"}, options.NewXReadOptions().SetBlock(0)) + testClient.XReadWithOptions(map[string]string{key1: "0-1"}, *options.NewXReadOptions().SetBlock(0)) finished <- true }() select { @@ -4596,21 +4617,21 @@ func (suite *GlideTestSuite) TestXGroupSetId() { xadd, err := client.XAddWithOptions( key, [][]string{{"f0", "v0"}}, - options.NewXAddOptions().SetId("1-0"), + *options.NewXAddOptions().SetId("1-0"), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "1-0", xadd.Value()) xadd, err = client.XAddWithOptions( key, [][]string{{"f1", "v1"}}, - options.NewXAddOptions().SetId("1-1"), + *options.NewXAddOptions().SetId("1-1"), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "1-1", xadd.Value()) xadd, err = client.XAddWithOptions( key, [][]string{{"f2", "v2"}}, - options.NewXAddOptions().SetId("1-2"), + *options.NewXAddOptions().SetId("1-2"), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "1-2", xadd.Value()) @@ -4643,7 +4664,7 @@ func (suite *GlideTestSuite) TestXGroupSetId() { suite.verifyOK(client.XGroupSetId(key, group, "1-1")) } else { opts := options.NewXGroupSetIdOptionsOptions().SetEntriesRead(42) - suite.verifyOK(client.XGroupSetIdWithOptions(key, group, "1-1", opts)) + suite.verifyOK(client.XGroupSetIdWithOptions(key, group, "1-1", *opts)) } // xreadgroup should only return entry 1-2 since we reset the last delivered ID to 1-1 @@ -4710,22 +4731,22 @@ func (suite *GlideTestSuite) TestZAddAndZAddIncr() { assert.IsType(suite.T(), &errors.RequestError{}, err) // with NX & XX - onlyIfExistsOpts := options.NewZAddOptionsBuilder().SetConditionalChange(options.OnlyIfExists) - onlyIfDoesNotExistOpts := options.NewZAddOptionsBuilder().SetConditionalChange(options.OnlyIfDoesNotExist) + onlyIfExistsOpts := options.NewZAddOptions().SetConditionalChange(options.OnlyIfExists) + onlyIfDoesNotExistOpts := options.NewZAddOptions().SetConditionalChange(options.OnlyIfDoesNotExist) - res, err = client.ZAddWithOptions(key3, membersScoreMap, onlyIfExistsOpts) + res, err = client.ZAddWithOptions(key3, membersScoreMap, *onlyIfExistsOpts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), res) - res, err = client.ZAddWithOptions(key3, membersScoreMap, onlyIfDoesNotExistOpts) + res, err = client.ZAddWithOptions(key3, membersScoreMap, *onlyIfDoesNotExistOpts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(3), res) - resIncr, err = client.ZAddIncrWithOptions(key3, "one", 5, onlyIfDoesNotExistOpts) + resIncr, err = client.ZAddIncrWithOptions(key3, "one", 5, *onlyIfDoesNotExistOpts) assert.Nil(suite.T(), err) assert.True(suite.T(), resIncr.IsNil()) - resIncr, err = client.ZAddIncrWithOptions(key3, "one", 5, onlyIfExistsOpts) + resIncr, err = client.ZAddIncrWithOptions(key3, "one", 5, *onlyIfExistsOpts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), float64(6), resIncr.Value()) @@ -4742,24 +4763,24 @@ func (suite *GlideTestSuite) TestZAddAndZAddIncr() { membersScoreMap2["one"] = 10.0 - gtOpts := options.NewZAddOptionsBuilder().SetUpdateOptions(options.ScoreGreaterThanCurrent) - ltOpts := options.NewZAddOptionsBuilder().SetUpdateOptions(options.ScoreLessThanCurrent) - gtOptsChanged, _ := options.NewZAddOptionsBuilder().SetUpdateOptions(options.ScoreGreaterThanCurrent).SetChanged(true) - ltOptsChanged, _ := options.NewZAddOptionsBuilder().SetUpdateOptions(options.ScoreLessThanCurrent).SetChanged(true) + gtOpts := options.NewZAddOptions().SetUpdateOptions(options.ScoreGreaterThanCurrent) + ltOpts := options.NewZAddOptions().SetUpdateOptions(options.ScoreLessThanCurrent) + gtOptsChanged, _ := options.NewZAddOptions().SetUpdateOptions(options.ScoreGreaterThanCurrent).SetChanged(true) + ltOptsChanged, _ := options.NewZAddOptions().SetUpdateOptions(options.ScoreLessThanCurrent).SetChanged(true) - res, err = client.ZAddWithOptions(key4, membersScoreMap2, gtOptsChanged) + res, err = client.ZAddWithOptions(key4, membersScoreMap2, *gtOptsChanged) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(1), res) - res, err = client.ZAddWithOptions(key4, membersScoreMap2, ltOptsChanged) + res, err = client.ZAddWithOptions(key4, membersScoreMap2, *ltOptsChanged) assert.Nil(suite.T(), err) assert.Equal(suite.T(), int64(0), res) - resIncr, err = client.ZAddIncrWithOptions(key4, "one", -3, ltOpts) + resIncr, err = client.ZAddIncrWithOptions(key4, "one", -3, *ltOpts) assert.Nil(suite.T(), err) assert.Equal(suite.T(), float64(7), resIncr.Value()) - resIncr, err = client.ZAddIncrWithOptions(key4, "one", -3, gtOpts) + resIncr, err = client.ZAddIncrWithOptions(key4, "one", -3, *gtOpts) assert.Nil(suite.T(), err) assert.True(suite.T(), resIncr.IsNil()) }) @@ -4856,7 +4877,7 @@ func (suite *GlideTestSuite) TestZPopMin() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"one": float64(1)}, res2) - res3, err := client.ZPopMinWithCount(key1, 2) + res3, err := client.ZPopMinWithOptions(key1, *options.NewZPopOptions().SetCount(2)) assert.Nil(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": float64(2), "three": float64(3)}, res3) @@ -4887,7 +4908,7 @@ func (suite *GlideTestSuite) TestZPopMax() { assert.Nil(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"three": float64(3)}, res2) - res3, err := client.ZPopMaxWithCount(key1, 2) + res3, err := client.ZPopMaxWithOptions(key1, *options.NewZPopOptions().SetCount(2)) assert.Nil(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": float64(2), "one": float64(1)}, res3) @@ -5386,7 +5407,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { xAddResult, err := client.XAddWithOptions( key1, [][]string{{field1, "foo"}, {field2, "bar"}}, - options.NewXAddOptions().SetDontMakeNewStream(), + *options.NewXAddOptions().SetDontMakeNewStream(), ) assert.NoError(t, err) assert.True(t, xAddResult.IsNil()) @@ -5394,7 +5415,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { xAddResult, err = client.XAddWithOptions( key1, [][]string{{field1, "foo1"}, {field2, "bar1"}}, - options.NewXAddOptions().SetId("0-1"), + *options.NewXAddOptions().SetId("0-1"), ) assert.NoError(t, err) assert.Equal(t, xAddResult.Value(), "0-1") @@ -5414,7 +5435,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { xAddResult, err = client.XAddWithOptions( key1, [][]string{{field1, "foo3"}, {field2, "bar2"}}, - options.NewXAddOptions().SetTrimOptions( + *options.NewXAddOptions().SetTrimOptions( options.NewXTrimOptionsWithMaxLen(2).SetExactTrimming(), ), ) @@ -5429,7 +5450,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { xAddResult, err = client.XAddWithOptions( key1, [][]string{{field1, "foo4"}, {field2, "bar4"}}, - options.NewXAddOptions().SetTrimOptions( + *options.NewXAddOptions().SetTrimOptions( options.NewXTrimOptionsWithMinId(id).SetExactTrimming(), ), ) @@ -5442,7 +5463,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { // Test xtrim to remove 1 element xTrimResult, err := client.XTrim( key1, - options.NewXTrimOptionsWithMaxLen(1).SetExactTrimming(), + *options.NewXTrimOptionsWithMaxLen(1).SetExactTrimming(), ) assert.NoError(t, err) assert.Equal(t, int64(1), xTrimResult) @@ -5453,7 +5474,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { // Key does not exist - returns 0 xTrimResult, err = client.XTrim( key2, - options.NewXTrimOptionsWithMaxLen(1).SetExactTrimming(), + *options.NewXTrimOptionsWithMaxLen(1).SetExactTrimming(), ) assert.NoError(t, err) assert.Equal(t, int64(0), xTrimResult) @@ -5463,7 +5484,7 @@ func (suite *GlideTestSuite) Test_XAdd_XLen_XTrim() { // Throw Exception: Key exists - but it is not a stream suite.verifyOK(client.Set(key2, "xtrimtest")) - _, err = client.XTrim(key2, options.NewXTrimOptionsWithMinId("0-1")) + _, err = client.XTrim(key2, *options.NewXTrimOptionsWithMinId("0-1")) assert.NotNil(t, err) assert.IsType(t, &errors.RequestError{}, err) _, err = client.XLen(key2) @@ -5526,65 +5547,65 @@ func (suite *GlideTestSuite) TestZCount() { assert.Equal(t, int64(3), res1) // In range negative to positive infinity. - zCountRange := options.NewZCountRangeBuilder( + zCountRange := options.NewZCountRange( options.NewInfiniteScoreBoundary(options.NegativeInfinity), options.NewInfiniteScoreBoundary(options.PositiveInfinity), ) - zCountResult, err := client.ZCount(key1, zCountRange) + zCountResult, err := client.ZCount(key1, *zCountRange) assert.Nil(t, err) assert.Equal(t, int64(3), zCountResult) - zCountRange = options.NewZCountRangeBuilder( + zCountRange = options.NewZCountRange( options.NewInclusiveScoreBoundary(math.Inf(-1)), options.NewInclusiveScoreBoundary(math.Inf(+1)), ) - zCountResult, err = client.ZCount(key1, zCountRange) + zCountResult, err = client.ZCount(key1, *zCountRange) assert.Nil(t, err) assert.Equal(t, int64(3), zCountResult) // In range 1 (exclusive) to 3 (inclusive) - zCountRange = options.NewZCountRangeBuilder( + zCountRange = options.NewZCountRange( options.NewScoreBoundary(1, false), options.NewScoreBoundary(3, true), ) - zCountResult, err = client.ZCount(key1, zCountRange) + zCountResult, err = client.ZCount(key1, *zCountRange) assert.Nil(t, err) assert.Equal(t, int64(2), zCountResult) // In range negative infinity to 3 (inclusive) - zCountRange = options.NewZCountRangeBuilder( + zCountRange = options.NewZCountRange( options.NewInfiniteScoreBoundary(options.NegativeInfinity), options.NewScoreBoundary(3, true), ) - zCountResult, err = client.ZCount(key1, zCountRange) + zCountResult, err = client.ZCount(key1, *zCountRange) assert.Nil(t, err) assert.Equal(t, int64(3), zCountResult) // Incorrect range start > end - zCountRange = options.NewZCountRangeBuilder( + zCountRange = options.NewZCountRange( options.NewInfiniteScoreBoundary(options.PositiveInfinity), options.NewInclusiveScoreBoundary(3), ) - zCountResult, err = client.ZCount(key1, zCountRange) + zCountResult, err = client.ZCount(key1, *zCountRange) assert.Nil(t, err) assert.Equal(t, int64(0), zCountResult) // Non-existing key - zCountRange = options.NewZCountRangeBuilder( + zCountRange = options.NewZCountRange( options.NewInfiniteScoreBoundary(options.NegativeInfinity), options.NewInfiniteScoreBoundary(options.PositiveInfinity), ) - zCountResult, err = client.ZCount("non_existing_key", zCountRange) + zCountResult, err = client.ZCount("non_existing_key", *zCountRange) assert.Nil(t, err) assert.Equal(t, int64(0), zCountResult) // Key exists, but it is not a set setResult, _ := client.Set(key2, "value") assert.Equal(t, setResult, "OK") - zCountRange = options.NewZCountRangeBuilder( + zCountRange = options.NewZCountRange( options.NewInfiniteScoreBoundary(options.NegativeInfinity), options.NewInfiniteScoreBoundary(options.PositiveInfinity), ) - _, err = client.ZCount(key2, zCountRange) + _, err = client.ZCount(key2, *zCountRange) assert.NotNil(t, err) assert.IsType(suite.T(), &errors.RequestError{}, err) }) @@ -5602,7 +5623,7 @@ func (suite *GlideTestSuite) Test_XDel() { xAddResult, err := client.XAddWithOptions( key1, [][]string{{"f1", "foo1"}, {"f2", "bar2"}}, - options.NewXAddOptions().SetId(streamId1), + *options.NewXAddOptions().SetId(streamId1), ) assert.NoError(t, err) assert.Equal(t, xAddResult.Value(), streamId1) @@ -5610,7 +5631,7 @@ func (suite *GlideTestSuite) Test_XDel() { xAddResult, err = client.XAddWithOptions( key1, [][]string{{"f1", "foo1"}, {"f2", "bar2"}}, - options.NewXAddOptions().SetId(streamId2), + *options.NewXAddOptions().SetId(streamId2), ) assert.NoError(t, err) assert.Equal(t, xAddResult.Value(), streamId2) @@ -5703,8 +5724,8 @@ func (suite *GlideTestSuite) TestZScan() { // Scores come back as integers converted to a string when the fraction is zero. assert.True(suite.T(), isSubset(charMapValues, resultValueSet)) - opts := options.NewZScanOptionsBuilder().SetMatch("a") - resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, opts) + opts := options.NewZScanOptions().SetMatch("a") + resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, *opts) assert.NoError(suite.T(), err) assert.Equal(suite.T(), initialCursor, resCursor) assert.Equal(suite.T(), resCollection, []string{"a", "0"}) @@ -5738,30 +5759,30 @@ func (suite *GlideTestSuite) TestZScan() { assert.True(suite.T(), isSubset(numMembers, resKeys)) // Test match pattern - opts = options.NewZScanOptionsBuilder().SetMatch("*") - resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, opts) + opts = options.NewZScanOptions().SetMatch("*") + resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, *opts) assert.NoError(suite.T(), err) assert.NotEqual(suite.T(), initialCursor, resCursor) assert.GreaterOrEqual(suite.T(), len(resCollection), defaultCount) // test count - opts = options.NewZScanOptionsBuilder().SetCount(20) - resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, opts) + opts = options.NewZScanOptions().SetCount(20) + resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, *opts) assert.NoError(suite.T(), err) assert.NotEqual(suite.T(), initialCursor, resCursor) assert.GreaterOrEqual(suite.T(), len(resCollection), 20) // test count with match, returns a non-empty array - opts = options.NewZScanOptionsBuilder().SetMatch("1*").SetCount(20) - resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, opts) + opts = options.NewZScanOptions().SetMatch("1*").SetCount(20) + resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, *opts) assert.NoError(suite.T(), err) assert.NotEqual(suite.T(), initialCursor, resCursor) assert.GreaterOrEqual(suite.T(), len(resCollection), 0) // Test NoScores option for Redis 8.0.0+ if suite.serverVersion >= "8.0.0" { - opts = options.NewZScanOptionsBuilder().SetNoScores(true) - resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, opts) + opts = options.NewZScanOptions().SetNoScores(true) + resCursor, resCollection, err = client.ZScanWithOptions(key1, initialCursor, *opts) assert.NoError(suite.T(), err) cursor, err := strconv.ParseInt(resCursor, 10, 64) assert.NoError(suite.T(), err) @@ -5784,14 +5805,14 @@ func (suite *GlideTestSuite) TestZScan() { assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) - opts = options.NewZScanOptionsBuilder().SetMatch("test").SetCount(1) - _, _, err = client.ZScanWithOptions(stringKey, initialCursor, opts) + opts = options.NewZScanOptions().SetMatch("test").SetCount(1) + _, _, err = client.ZScanWithOptions(stringKey, initialCursor, *opts) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) // Negative count - opts = options.NewZScanOptionsBuilder().SetCount(-1) - _, _, err = client.ZScanWithOptions(key1, "-1", opts) + opts = options.NewZScanOptions().SetCount(-1) + _, _, err = client.ZScanWithOptions(key1, "-1", *opts) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) }) @@ -5874,7 +5895,7 @@ func (suite *GlideTestSuite) TestXPending() { detailResult, _ := client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) assert.Equal(suite.T(), len(detailResult), 2) assert.Equal(suite.T(), streamid_1.Value(), detailResult[0].Id) @@ -5948,7 +5969,7 @@ func (suite *GlideTestSuite) TestXPending() { detailResult, _ := client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(consumer1), ) assert.Equal(suite.T(), len(detailResult), 2) assert.Equal(suite.T(), streamid_1.Value(), detailResult[0].Id) @@ -5996,7 +6017,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { key, groupName, zeroStreamId, - options.NewXGroupCreateOptions().SetMakeStream(), + *options.NewXGroupCreateOptions().SetMakeStream(), ), ) @@ -6015,7 +6036,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(0), summaryResult.NumOfMessages) - detailResult, err := client.XPendingWithOptions(key, groupName, options.NewXPendingOptions("-", "+", 10)) + detailResult, err := client.XPendingWithOptions(key, groupName, *options.NewXPendingOptions("-", "+", 10)) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6031,7 +6052,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 1).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 1).SetConsumer(consumer1), ) assert.NoError(suite.T(), err) assert.True(suite.T(), len(detailResult) > 0) @@ -6040,7 +6061,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("+", "-", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("+", "-", 10).SetConsumer(consumer1), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6049,7 +6070,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetMinIdleTime(100000), + *options.NewXPendingOptions("-", "+", 10).SetMinIdleTime(100000), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6058,7 +6079,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetConsumer(invalidConsumer), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(invalidConsumer), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6067,7 +6088,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("invalid-id", "+", 10), + *options.NewXPendingOptions("invalid-id", "+", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6075,7 +6096,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "invalid-id", 10), + *options.NewXPendingOptions("-", "invalid-id", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6084,7 +6105,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", -1), + *options.NewXPendingOptions("-", "+", -1), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6110,7 +6131,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( missingKey, groupName, - options.NewXPendingOptions("-", "+", 10), + *options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6129,7 +6150,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( nonStreamKey, groupName, - options.NewXPendingOptions("-", "+", 10), + *options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6147,7 +6168,12 @@ func (suite *GlideTestSuite) TestXPendingFailures() { invalidConsumer := "invalid-consumer-" + uuid.New().String() suite.verifyOK( - client.XGroupCreateWithOptions(key, groupName, zeroStreamId, options.NewXGroupCreateOptions().SetMakeStream()), + client.XGroupCreateWithOptions( + key, + groupName, + zeroStreamId, + *options.NewXGroupCreateOptions().SetMakeStream(), + ), ) command := []string{"XGroup", "CreateConsumer", key, groupName, consumer1} @@ -6165,7 +6191,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(0), summaryResult.NumOfMessages) - detailResult, err := client.XPendingWithOptions(key, groupName, options.NewXPendingOptions("-", "+", 10)) + detailResult, err := client.XPendingWithOptions(key, groupName, *options.NewXPendingOptions("-", "+", 10)) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6181,7 +6207,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 1).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 1).SetConsumer(consumer1), ) assert.NoError(suite.T(), err) assert.True(suite.T(), len(detailResult) > 0) @@ -6190,7 +6216,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("+", "-", 10).SetConsumer(consumer1), + *options.NewXPendingOptions("+", "-", 10).SetConsumer(consumer1), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6199,7 +6225,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetMinIdleTime(100000), + *options.NewXPendingOptions("-", "+", 10).SetMinIdleTime(100000), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6208,7 +6234,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetConsumer(invalidConsumer), + *options.NewXPendingOptions("-", "+", 10).SetConsumer(invalidConsumer), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6217,7 +6243,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("invalid-id", "+", 10), + *options.NewXPendingOptions("invalid-id", "+", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6225,7 +6251,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "invalid-id", 10), + *options.NewXPendingOptions("-", "invalid-id", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6234,7 +6260,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { detailResult, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", -1), + *options.NewXPendingOptions("-", "+", -1), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 0, len(detailResult)) @@ -6260,7 +6286,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( missingKey, groupName, - options.NewXPendingOptions("-", "+", 10), + *options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6279,7 +6305,7 @@ func (suite *GlideTestSuite) TestXPendingFailures() { _, err = client.XPendingWithOptions( nonStreamKey, groupName, - options.NewXPendingOptions("-", "+", 10), + *options.NewXPendingOptions("-", "+", 10), ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -6313,7 +6339,7 @@ func (suite *GlideTestSuite) TestXGroupCreate_XGroupDestroy() { // Stream with option to create creates stream & Group opts := options.NewXGroupCreateOptions().SetMakeStream() - suite.verifyOK(client.XGroupCreateWithOptions(key, group, id, opts)) + suite.verifyOK(client.XGroupCreateWithOptions(key, group, id, *opts)) // ...and again results in BUSYGROUP error, because group names must be unique _, err = client.XGroupCreate(key, group, id) @@ -6333,9 +6359,9 @@ func (suite *GlideTestSuite) TestXGroupCreate_XGroupDestroy() { // ENTRIESREAD option was added in valkey 7.0.0 opts = options.NewXGroupCreateOptions().SetEntriesRead(100) if suite.serverVersion >= "7.0.0" { - suite.verifyOK(client.XGroupCreateWithOptions(key, group, id, opts)) + suite.verifyOK(client.XGroupCreateWithOptions(key, group, id, *opts)) } else { - _, err = client.XGroupCreateWithOptions(key, group, id, opts) + _, err = client.XGroupCreateWithOptions(key, group, id, *opts) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) } @@ -6411,8 +6437,8 @@ func (suite *GlideTestSuite) TestRestoreWithOptions() { deletedCount, err := client.Del([]string{key}) assert.Nil(t, err) assert.Equal(t, int64(1), deletedCount) - optsReplace := api.NewRestoreOptionsBuilder().SetReplace() - result_test1, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), optsReplace) + optsReplace := options.NewRestoreOptions().SetReplace() + result_test1, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), *optsReplace) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result_test1.Value()) resultGetRestoreKey, err := client.Get(key) @@ -6423,8 +6449,8 @@ func (suite *GlideTestSuite) TestRestoreWithOptions() { delete_test2, err := client.Del([]string{key}) assert.Nil(t, err) assert.Equal(t, int64(1), delete_test2) - opts_test2 := api.NewRestoreOptionsBuilder().SetABSTTL() - result_test2, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), opts_test2) + opts_test2 := options.NewRestoreOptions().SetABSTTL() + result_test2, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), *opts_test2) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result_test2.Value()) resultGet_test2, err := client.Get(key) @@ -6435,8 +6461,8 @@ func (suite *GlideTestSuite) TestRestoreWithOptions() { delete_test3, err := client.Del([]string{key}) assert.Nil(t, err) assert.Equal(t, int64(1), delete_test3) - opts_test3 := api.NewRestoreOptionsBuilder().SetEviction(api.FREQ, 10) - result_test3, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), opts_test3) + opts_test3 := options.NewRestoreOptions().SetEviction(options.FREQ, 10) + result_test3, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), *opts_test3) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result_test3.Value()) resultGet_test3, err := client.Get(key) @@ -6447,8 +6473,8 @@ func (suite *GlideTestSuite) TestRestoreWithOptions() { delete_test4, err := client.Del([]string{key}) assert.Nil(t, err) assert.Equal(t, int64(1), delete_test4) - opts_test4 := api.NewRestoreOptionsBuilder().SetEviction(api.IDLETIME, 10) - result_test4, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), opts_test4) + opts_test4 := options.NewRestoreOptions().SetEviction(options.IDLETIME, 10) + result_test4, err := client.RestoreWithOptions(key, int64(0), resultDump.Value(), *opts_test4) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "OK", result_test4.Value()) resultGet_test4, err := client.Get(key) @@ -6811,7 +6837,7 @@ func (suite *GlideTestSuite) TestSortWithOptions_ExternalWeights() { SetOrderBy(options.ASC). SetIsAlpha(false) - sortResult, err := client.SortWithOptions(key, options) + sortResult, err := client.SortWithOptions(key, *options) assert.Nil(suite.T(), err) resultList := []api.Result[string]{ @@ -6840,7 +6866,7 @@ func (suite *GlideTestSuite) TestSortWithOptions_GetPatterns() { SetIsAlpha(false). AddGetPattern("object_*") - sortResult, err := client.SortWithOptions(key, options) + sortResult, err := client.SortWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -6875,7 +6901,7 @@ func (suite *GlideTestSuite) TestSortWithOptions_SuccessfulSortByWeightAndGet() AddGetPattern("object_*"). AddGetPattern("#") - sortResult, err := client.SortWithOptions(key, options) + sortResult, err := client.SortWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -6922,7 +6948,7 @@ func (suite *GlideTestSuite) TestSortStoreWithOptions_ByPattern() { options := options.NewSortOptions().SetByPattern("{listKey}weight_*") - result, err := client.SortStoreWithOptions(key, sortedKey, options) + result, err := client.SortStoreWithOptions(key, sortedKey, *options) assert.Nil(suite.T(), err) assert.NotNil(suite.T(), result) @@ -7053,7 +7079,7 @@ func (suite *GlideTestSuite) TestXInfoStream() { group := uuid.NewString() consumer := uuid.NewString() - xadd, err := client.XAddWithOptions(key, [][]string{{"a", "b"}, {"c", "d"}}, options.NewXAddOptions().SetId("1-0")) + xadd, err := client.XAddWithOptions(key, [][]string{{"a", "b"}, {"c", "d"}}, *options.NewXAddOptions().SetId("1-0")) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "1-0", xadd.Value()) @@ -7070,7 +7096,7 @@ func (suite *GlideTestSuite) TestXInfoStream() { assert.Equal(suite.T(), expectedEntry, infoSmall["first-entry"]) assert.Equal(suite.T(), expectedEntry, infoSmall["last-entry"]) - xadd, err = client.XAddWithOptions(key, [][]string{{"e", "f"}}, options.NewXAddOptions().SetId("1-1")) + xadd, err = client.XAddWithOptions(key, [][]string{{"e", "f"}}, *options.NewXAddOptions().SetId("1-1")) assert.Nil(suite.T(), err) assert.Equal(suite.T(), "1-1", xadd.Value()) @@ -7231,13 +7257,11 @@ func (suite *GlideTestSuite) TestBitCountWithOptions_StartEnd() { client.Set(key, value) - start := int64(1) - end := int64(5) - opts := &options.BitCountOptions{} - opts.SetStart(start) - opts.SetEnd(end) + opts := options.NewBitCountOptions(). + SetStart(1). + SetEnd(5) - result, err := client.BitCountWithOptions(key, opts) + result, err := client.BitCountWithOptions(key, *opts) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(19), result) }) @@ -7251,14 +7275,12 @@ func (suite *GlideTestSuite) TestBitCountWithOptions_StartEndByte() { client.Set(key, value) - start := int64(1) - end := int64(5) - opts := &options.BitCountOptions{} - opts.SetStart(start) - opts.SetEnd(end) - opts.SetBitmapIndexType(options.BYTE) + opts := options.NewBitCountOptions(). + SetStart(1). + SetEnd(5). + SetBitmapIndexType(options.BYTE) - result, err := client.BitCountWithOptions(key, opts) + result, err := client.BitCountWithOptions(key, *opts) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(19), result) }) @@ -7272,14 +7294,12 @@ func (suite *GlideTestSuite) TestBitCountWithOptions_StartEndBit() { client.Set(key, value) - start := int64(1) - end := int64(5) - opts := &options.BitCountOptions{} - opts.SetStart(start) - opts.SetEnd(end) - opts.SetBitmapIndexType(options.BIT) + opts := options.NewBitCountOptions(). + SetStart(1). + SetEnd(5). + SetBitmapIndexType(options.BIT) - result, err := client.BitCountWithOptions(key, opts) + result, err := client.BitCountWithOptions(key, *opts) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(3), result) }) @@ -7298,7 +7318,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { key, groupName, zeroStreamId, - options.NewXGroupCreateOptions().SetMakeStream(), + *options.NewXGroupCreateOptions().SetMakeStream(), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "OK", resp) @@ -7370,7 +7390,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { pendingResultExtended, err := client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10), + *options.NewXPendingOptions("-", "+", 10), ) assert.NoError(suite.T(), err) @@ -7433,7 +7453,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { consumer1, int64(0), []string{streamid_6.Value()}, - options.NewStreamClaimOptions().SetForce().SetRetryCount(99), + *options.NewXClaimOptions().SetForce().SetRetryCount(99), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), map[string][][]string{streamid_6.Value(): {{"field6", "value6"}}}, claimResult) @@ -7441,7 +7461,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { forcePendingResult, err := client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions(streamid_6.Value(), streamid_6.Value(), 1), + *options.NewXPendingOptions(streamid_6.Value(), streamid_6.Value(), 1), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 1, len(forcePendingResult)) @@ -7459,7 +7479,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { pendingResultExtended, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions(streamid_3.Value(), "+", 10), + *options.NewXPendingOptions(streamid_3.Value(), "+", 10), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 1, len(pendingResultExtended)) @@ -7469,7 +7489,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { pendingResultExtended, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "("+streamid_5.Value(), 10), + *options.NewXPendingOptions("-", "("+streamid_5.Value(), 10), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 1, len(pendingResultExtended)) @@ -7479,7 +7499,7 @@ func (suite *GlideTestSuite) TestXPendingAndXClaim() { pendingResultExtended, err = client.XPendingWithOptions( key, groupName, - options.NewXPendingOptions("-", "+", 10).SetMinIdleTime(1).SetConsumer(consumer1), + *options.NewXPendingOptions("-", "+", 10).SetMinIdleTime(1).SetConsumer(consumer1), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), 2, len(pendingResultExtended)) @@ -7499,7 +7519,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { key, groupName, zeroStreamId, - options.NewXGroupCreateOptions().SetMakeStream(), + *options.NewXGroupCreateOptions().SetMakeStream(), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), "OK", groupCreateResult) @@ -7528,7 +7548,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { assert.Equal(suite.T(), []string{}, claimResult) // non existent key causes a RequestError - claimOptions := options.NewStreamClaimOptions().SetIdleTime(1) + claimOptions := options.NewXClaimOptions().SetIdleTime(1) _, err = client.XClaim(stringKey, groupName, consumer1, int64(1), []string{streamid_1.Value()}) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -7540,7 +7560,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { consumer1, int64(1), []string{streamid_1.Value()}, - claimOptions, + *claimOptions, ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -7557,7 +7577,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { consumer1, int64(1), []string{streamid_1.Value()}, - claimOptions, + *claimOptions, ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -7576,7 +7596,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { consumer1, int64(1), []string{streamid_1.Value()}, - claimOptions, + *claimOptions, ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -7591,7 +7611,7 @@ func (suite *GlideTestSuite) TestXClaimFailure() { consumer1, int64(1), []string{streamid_1.Value()}, - claimOptions, + *claimOptions, ) assert.Error(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -7628,8 +7648,8 @@ func (suite *GlideTestSuite) TestCopyWithOptions() { suite.verifyOK(client.Set(key2, "World")) // Test 1: Check the copy command with options - optsCopy := api.NewCopyOptionsBuilder().SetReplace() - resultCopy, err := client.CopyWithOptions(key, key2, optsCopy) + optsCopy := options.NewCopyOptions().SetReplace() + resultCopy, err := client.CopyWithOptions(key, key2, *optsCopy) assert.Nil(t, err) assert.True(t, resultCopy) @@ -7729,7 +7749,7 @@ func (suite *GlideTestSuite) TestXRangeAndXRevRange() { key, options.NewStreamBoundary(streamId2.Value(), false), positiveInfinity, - options.NewStreamRangeOptions().SetCount(1), + *options.NewXRangeOptions().SetCount(1), ) assert.NoError(suite.T(), err) assert.Equal( @@ -7745,7 +7765,7 @@ func (suite *GlideTestSuite) TestXRangeAndXRevRange() { key, positiveInfinity, options.NewStreamBoundary(streamId2.Value(), false), - options.NewStreamRangeOptions().SetCount(1), + *options.NewXRangeOptions().SetCount(1), ) assert.NoError(suite.T(), err) assert.Equal( @@ -7761,7 +7781,7 @@ func (suite *GlideTestSuite) TestXRangeAndXRevRange() { key, negativeInfinity, positiveInfinity, - options.NewStreamRangeOptions().SetCount(0), + *options.NewXRangeOptions().SetCount(0), ) assert.NoError(suite.T(), err) assert.Empty(suite.T(), xrangeResult) @@ -7770,7 +7790,7 @@ func (suite *GlideTestSuite) TestXRangeAndXRevRange() { key, positiveInfinity, negativeInfinity, - options.NewStreamRangeOptions().SetCount(-1), + *options.NewXRangeOptions().SetCount(-1), ) assert.NoError(suite.T(), err) assert.Empty(suite.T(), xrevrangeResult) @@ -8069,7 +8089,7 @@ func (suite *GlideTestSuite) TestZInter() { // intersection with scores zinterWithScoresResult, err := client.ZInterWithScores(options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": 5.5}, zinterWithScoresResult) @@ -8077,7 +8097,7 @@ func (suite *GlideTestSuite) TestZInter() { // intersect results with max aggregate zinterWithMaxAggregateResult, err := client.ZInterWithScores( options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateMax), + *options.NewZInterOptions().SetAggregate(options.AggregateMax), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": 3.5}, zinterWithMaxAggregateResult) @@ -8085,7 +8105,7 @@ func (suite *GlideTestSuite) TestZInter() { // intersect results with min aggregate zinterWithMinAggregateResult, err := client.ZInterWithScores( options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateMin), + *options.NewZInterOptions().SetAggregate(options.AggregateMin), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": 2.0}, zinterWithMinAggregateResult) @@ -8093,7 +8113,7 @@ func (suite *GlideTestSuite) TestZInter() { // intersect results with sum aggregate zinterWithSumAggregateResult, err := client.ZInterWithScores( options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": 5.5}, zinterWithSumAggregateResult) @@ -8106,7 +8126,7 @@ func (suite *GlideTestSuite) TestZInter() { {Key: key2, Weight: 2.0}, }, }, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), map[string]float64{"two": 11.0}, zinterWithWeightedKeysResult) @@ -8114,14 +8134,14 @@ func (suite *GlideTestSuite) TestZInter() { // non-existent key - empty intersection zinterWithNonExistentKeyResult, err := client.ZInterWithScores( options.KeyArray{Keys: []string{key1, key3}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NoError(suite.T(), err) assert.Empty(suite.T(), zinterWithNonExistentKeyResult) // empty key list - request error _, err = client.ZInterWithScores(options.KeyArray{Keys: []string{}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -8136,7 +8156,7 @@ func (suite *GlideTestSuite) TestZInter() { _, err = client.ZInterWithScores( options.KeyArray{Keys: []string{key1, key3}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NotNil(suite.T(), err) assert.IsType(suite.T(), &errors.RequestError{}, err) @@ -8181,7 +8201,7 @@ func (suite *GlideTestSuite) TestZInterStore() { // Store the intersection of key1 and key2 in key4 with max aggregate res, err = client.ZInterStoreWithOptions(key3, options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateMax), + *options.NewZInterOptions().SetAggregate(options.AggregateMax), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(2), res) @@ -8193,7 +8213,7 @@ func (suite *GlideTestSuite) TestZInterStore() { // Store the intersection of key1 and key2 in key5 with min aggregate res, err = client.ZInterStoreWithOptions(key3, options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateMin), + *options.NewZInterOptions().SetAggregate(options.AggregateMin), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(2), res) @@ -8205,7 +8225,7 @@ func (suite *GlideTestSuite) TestZInterStore() { // Store the intersection of key1 and key2 in key6 with sum aggregate res, err = client.ZInterStoreWithOptions(key3, options.KeyArray{Keys: []string{key1, key2}}, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateSum), + *options.NewZInterOptions().SetAggregate(options.AggregateSum), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(2), res) @@ -8238,7 +8258,7 @@ func (suite *GlideTestSuite) TestZInterStore() { {Key: key2, Weight: -2.0}, }, }, - options.NewZInterOptionsBuilder().SetAggregate(options.AggregateMin), + *options.NewZInterOptions().SetAggregate(options.AggregateMin), ) assert.NoError(suite.T(), err) assert.Equal(suite.T(), int64(2), res) diff --git a/go/integTest/standalone_commands_test.go b/go/integTest/standalone_commands_test.go index 3bcec05e15..11f909f70d 100644 --- a/go/integTest/standalone_commands_test.go +++ b/go/integTest/standalone_commands_test.go @@ -291,7 +291,7 @@ func (suite *GlideTestSuite) TestSortReadOnlyWithOptions_ExternalWeights() { SetOrderBy(options.ASC). SetIsAlpha(false) - sortResult, err := client.SortReadOnlyWithOptions(key, options) + sortResult, err := client.SortReadOnlyWithOptions(key, *options) assert.Nil(suite.T(), err) resultList := []api.Result[string]{ @@ -320,7 +320,7 @@ func (suite *GlideTestSuite) TestSortReadOnlyWithOptions_GetPatterns() { SetIsAlpha(false). AddGetPattern("object_*") - sortResult, err := client.SortReadOnlyWithOptions(key, options) + sortResult, err := client.SortReadOnlyWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -356,7 +356,7 @@ func (suite *GlideTestSuite) TestSortReadOnlyWithOptions_SuccessfulSortByWeightA AddGetPattern("object_*"). AddGetPattern("#") - sortResult, err := client.SortReadOnlyWithOptions(key, options) + sortResult, err := client.SortReadOnlyWithOptions(key, *options) assert.Nil(suite.T(), err) @@ -414,11 +414,11 @@ func (suite *GlideTestSuite) TestInfoStandalone() { } // info with option or with multiple options - sections := []api.Section{api.Cpu} + sections := []options.Section{options.Cpu} if suite.serverVersion >= "7.0.0" { - sections = append(sections, api.Memory) + sections = append(sections, options.Memory) } - info, err = client.InfoWithOptions(api.InfoOptions{Sections: sections}) + info, err = client.InfoWithOptions(options.InfoOptions{Sections: sections}) assert.NoError(t, err) for _, section := range sections { assert.Contains(t, strings.ToLower(info), strings.ToLower("# "+string(section)), "Section "+section+" is missing") diff --git a/go/integTest/vss_module_test.go b/go/integTest/vss_module_test.go index 39b720f210..10e10bd7ce 100644 --- a/go/integTest/vss_module_test.go +++ b/go/integTest/vss_module_test.go @@ -6,13 +6,16 @@ import ( "strings" "github.com/stretchr/testify/assert" - "github.com/valkey-io/valkey-glide/go/api" + "github.com/valkey-io/valkey-glide/go/api/options" ) func (suite *GlideTestSuite) TestModuleVerifyVssLoaded() { client := suite.defaultClusterClient() result, err := client.InfoWithOptions( - api.ClusterInfoOptions{InfoOptions: &api.InfoOptions{Sections: []api.Section{api.Server}}, Route: nil}, + options.ClusterInfoOptions{ + InfoOptions: &options.InfoOptions{Sections: []options.Section{options.Server}}, + RouteOption: nil, + }, ) assert.Nil(suite.T(), err) diff --git a/java/THIRD_PARTY_LICENSES_JAVA b/java/THIRD_PARTY_LICENSES_JAVA index 014d1863be..93aa907a6c 100644 --- a/java/THIRD_PARTY_LICENSES_JAVA +++ b/java/THIRD_PARTY_LICENSES_JAVA @@ -24565,7 +24565,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- -Package: smallvec:1.13.2 +Package: smallvec:1.14.0 The following copyrights and licenses were found in the source code of this package: diff --git a/java/benchmarks/build.gradle b/java/benchmarks/build.gradle index f8e62ab6d7..7fcb72fe86 100644 --- a/java/benchmarks/build.gradle +++ b/java/benchmarks/build.gradle @@ -25,7 +25,9 @@ dependencies { implementation group: 'com.google.code.gson', name: 'gson', version: '2.10.1' } -compileJava.dependsOn ':client:publishToMavenLocal' +if (!System.getenv("GLIDE_RELEASE_VERSION")) { + compileJava.dependsOn ':client:publishToMavenLocal' +} application { // Define the main class for the application. diff --git a/java/client/src/main/java/glide/api/commands/servermodules/MultiJson.java b/java/client/src/main/java/glide/api/commands/servermodules/JsonBatch.java similarity index 99% rename from java/client/src/main/java/glide/api/commands/servermodules/MultiJson.java rename to java/client/src/main/java/glide/api/commands/servermodules/JsonBatch.java index 32f19b45c1..8f9874e296 100644 --- a/java/client/src/main/java/glide/api/commands/servermodules/MultiJson.java +++ b/java/client/src/main/java/glide/api/commands/servermodules/JsonBatch.java @@ -18,14 +18,14 @@ * @example *
{@code
  * Transaction transaction = new Transaction();
- * MultiJson.set(transaction, "doc", ".", "{\"a\": 1.0, \"b\": 2}");
- * MultiJson.get(transaction, "doc");
+ * JsonBatch.set(transaction, "doc", ".", "{\"a\": 1.0, \"b\": 2}");
+ * JsonBatch.get(transaction, "doc");
  * Object[] result = client.exec(transaction).get();
- * assert result[0].equals("OK"); // result of MultiJson.set()
- * assert result[1].equals("{\"a\": 1.0, \"b\": 2}"); // result of MultiJson.get()
+ * assert result[0].equals("OK"); // result of JsonBatch.set()
+ * assert result[1].equals("{\"a\": 1.0, \"b\": 2}"); // result of JsonBatch.get()
  * }
*/ -public class MultiJson { +public class JsonBatch { private static final String JSON_PREFIX = "JSON."; private static final String JSON_SET = JSON_PREFIX + "SET"; @@ -52,7 +52,7 @@ public class MultiJson { private static final String JSON_RESP = JSON_PREFIX + "RESP"; private static final String JSON_TYPE = JSON_PREFIX + "TYPE"; - private MultiJson() {} + private JsonBatch() {} /** * Sets the JSON value at the specified path stored at key. diff --git a/java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java b/java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java index 532c9a2939..8efaff5a4a 100644 --- a/java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java +++ b/java/client/src/main/java/glide/api/models/configuration/BaseClientConfiguration.java @@ -83,8 +83,9 @@ public abstract class BaseClientConfiguration { private final Integer inflightRequestsLimit; /** - * Availability Zone of the client. If ReadFrom strategy is AZAffinity, this setting ensures that - * readonly commands are directed to replicas within the specified AZ if exits. + * Availability Zone of the client. If ReadFrom strategy is AZAffinity or + * AZAffinityReplicasAndPrimary, this setting ensures that readonly commands are directed to nodes + * within the specified AZ if exits. */ private final String clientAZ; } diff --git a/java/client/src/main/java/glide/api/models/configuration/ReadFrom.java b/java/client/src/main/java/glide/api/models/configuration/ReadFrom.java index 29a212d8c7..249ed37789 100644 --- a/java/client/src/main/java/glide/api/models/configuration/ReadFrom.java +++ b/java/client/src/main/java/glide/api/models/configuration/ReadFrom.java @@ -15,4 +15,10 @@ public enum ReadFrom { * round-robin manner, falling back to other replicas or the primary if needed. */ AZ_AFFINITY, + /** + * Spread the read requests among nodes within the client's Availability Zone (AZ) in a round + * robin manner, prioritizing local replicas, then the local primary, and falling back to any + * replica or the primary if needed. + */ + AZ_AFFINITY_REPLICAS_AND_PRIMARY, } diff --git a/java/client/src/main/java/glide/managers/ConnectionManager.java b/java/client/src/main/java/glide/managers/ConnectionManager.java index cff6e023b9..e0b85b2c60 100644 --- a/java/client/src/main/java/glide/managers/ConnectionManager.java +++ b/java/client/src/main/java/glide/managers/ConnectionManager.java @@ -133,6 +133,14 @@ private ConnectionRequest.Builder setupConnectionRequestBuilderBaseConfiguration connectionRequestBuilder.setClientAz(configuration.getClientAZ()); } + if (configuration.getReadFrom() == ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY) { + if (configuration.getClientAZ() == null) { + throw new ConfigurationError( + "`clientAZ` must be set when read_from is set to `AZ_AFFINITY_REPLICAS_AND_PRIMARY`"); + } + connectionRequestBuilder.setClientAz(configuration.getClientAZ()); + } + if (configuration.getProtocol() != null) { connectionRequestBuilder.setProtocolValue(configuration.getProtocol().ordinal()); } @@ -256,6 +264,8 @@ private ConnectionRequestOuterClass.ReadFrom mapReadFromEnum(ReadFrom readFrom) return ConnectionRequestOuterClass.ReadFrom.PreferReplica; case AZ_AFFINITY: return ConnectionRequestOuterClass.ReadFrom.AZAffinity; + case AZ_AFFINITY_REPLICAS_AND_PRIMARY: + return ConnectionRequestOuterClass.ReadFrom.AZAffinityReplicasAndPrimary; default: return ConnectionRequestOuterClass.ReadFrom.Primary; } diff --git a/java/client/src/test/java/glide/managers/ConnectionManagerTest.java b/java/client/src/test/java/glide/managers/ConnectionManagerTest.java index 24a37a8114..cbe455d7a2 100644 --- a/java/client/src/test/java/glide/managers/ConnectionManagerTest.java +++ b/java/client/src/test/java/glide/managers/ConnectionManagerTest.java @@ -276,13 +276,23 @@ public void connection_on_resp_pointer_throws_ClosingException() { @SneakyThrows @Test public void test_convert_config_with_azaffinity_to_protobuf() { + testConvertConfigWithAzAffinity(ReadFrom.AZ_AFFINITY); + } + + @SneakyThrows + @Test + public void test_convert_config_with_azaffinity_replicas_and_primary_to_protobuf() { + testConvertConfigWithAzAffinity(ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY); + } + + private void testConvertConfigWithAzAffinity(ReadFrom readFrom) throws Exception { // setup String az = "us-east-1a"; GlideClientConfiguration config = GlideClientConfiguration.builder() .address(NodeAddress.builder().host(DEFAULT_HOST).port(DEFAULT_PORT).build()) .useTLS(true) - .readFrom(ReadFrom.AZ_AFFINITY) + .readFrom(readFrom) .clientAZ(az) .build(); @@ -294,7 +304,7 @@ public void test_convert_config_with_azaffinity_to_protobuf() { .setPort(DEFAULT_PORT) .build()) .setTlsMode(TlsMode.SecureTls) - .setReadFrom(ConnectionRequestOuterClass.ReadFrom.AZAffinity) + .setReadFrom(mapReadFrom(readFrom)) .setClientAz(az) .build(); @@ -314,16 +324,38 @@ public void test_convert_config_with_azaffinity_to_protobuf() { @SneakyThrows @Test public void test_az_affinity_without_client_az_throws_ConfigurationError() { + testAzAffinityWithoutClientAzThrowsConfigurationError(ReadFrom.AZ_AFFINITY); + } + + @SneakyThrows + @Test + public void test_az_affinity_replicas_and_primary_without_client_az_throws_ConfigurationError() { + testAzAffinityWithoutClientAzThrowsConfigurationError( + ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY); + } + + private void testAzAffinityWithoutClientAzThrowsConfigurationError(ReadFrom readFrom) { // setup String az = "us-east-1a"; GlideClientConfiguration config = GlideClientConfiguration.builder() .address(NodeAddress.builder().host(DEFAULT_HOST).port(DEFAULT_PORT).build()) .useTLS(true) - .readFrom(ReadFrom.AZ_AFFINITY) + .readFrom(readFrom) .build(); // verify assertThrows(ConfigurationError.class, () -> connectionManager.connectToValkey(config)); } + + private ConnectionRequestOuterClass.ReadFrom mapReadFrom(ReadFrom readFrom) { + switch (readFrom) { + case AZ_AFFINITY: + return ConnectionRequestOuterClass.ReadFrom.AZAffinity; + case AZ_AFFINITY_REPLICAS_AND_PRIMARY: + return ConnectionRequestOuterClass.ReadFrom.AZAffinityReplicasAndPrimary; + default: + throw new IllegalArgumentException("Unsupported ReadFrom value: " + readFrom); + } + } } diff --git a/java/integTest/src/test/java/glide/ConnectionTests.java b/java/integTest/src/test/java/glide/ConnectionTests.java index f2a87cc4df..b7a525423a 100644 --- a/java/integTest/src/test/java/glide/ConnectionTests.java +++ b/java/integTest/src/test/java/glide/ConnectionTests.java @@ -324,4 +324,90 @@ public void test_connection_timeout(boolean clusterMode) { } } } + + @SneakyThrows + @Test + public void test_az_affinity_replicas_and_primary_routes_to_primary() { + assumeTrue(SERVER_VERSION.isGreaterThanOrEqualTo("8.0.0"), "Skip for versions below 8"); + + String az = "us-east-1a"; + String otherAz = "us-east-1b"; + int nGetCalls = 4; + String getCmdstat = String.format("cmdstat_get:calls=%d", nGetCalls); + + // Create client for setting the configs + GlideClusterClient configSetClient = + GlideClusterClient.createClient(azClusterClientConfig().requestTimeout(2000).build()).get(); + + // Reset stats and set all nodes to other_az + assertEquals(configSetClient.configResetStat().get(), OK); + configSetClient.configSet(Map.of("availability-zone", otherAz), ALL_NODES).get(); + + // Set primary for slot 12182 to az + configSetClient + .configSet( + Map.of("availability-zone", az), + new RequestRoutingConfiguration.SlotIdRoute(12182, PRIMARY)) + .get(); + + // Verify primary AZ + ClusterValue> primaryAzResult = + configSetClient + .configGet( + new String[] {"availability-zone"}, + new RequestRoutingConfiguration.SlotIdRoute(12182, PRIMARY)) + .get(); + assertEquals( + az, + primaryAzResult.getSingleValue().get("availability-zone"), + "Primary for slot 12182 is not in the expected AZ " + az); + + configSetClient.close(); + + // Create test client with AZ_AFFINITY_REPLICAS_AND_PRIMARY configuration + GlideClusterClient azTestClient = + GlideClusterClient.createClient( + azClusterClientConfig() + .readFrom(ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY) + .clientAZ(az) + .requestTimeout(2000) + .build()) + .get(); + + // Execute GET commands + for (int i = 0; i < nGetCalls; i++) { + azTestClient.get("foo").get(); + } + + ClusterValue infoResult = + azTestClient.info(new InfoOptions.Section[] {InfoOptions.Section.ALL}, ALL_NODES).get(); + Map infoData = infoResult.getMultiValue(); + + // Check that only the primary in the specified AZ handled all GET calls + long matchingEntries = + infoData.values().stream() + .filter( + value -> + value.contains(getCmdstat) + && value.contains(az) + && value.contains("role:master")) + .count(); + assertEquals(1, matchingEntries, "Exactly one primary in AZ should handle all calls"); + + // Verify total GET calls + long totalGetCalls = + infoData.values().stream() + .filter(value -> value.contains("cmdstat_get:calls=")) + .mapToInt( + value -> { + int startIndex = + value.indexOf("cmdstat_get:calls=") + "cmdstat_get:calls=".length(); + int endIndex = value.indexOf(",", startIndex); + return Integer.parseInt(value.substring(startIndex, endIndex)); + }) + .sum(); + assertEquals(nGetCalls, totalGetCalls, "Total GET calls mismatch"); + + azTestClient.close(); + } } diff --git a/java/integTest/src/test/java/glide/modules/JsonTests.java b/java/integTest/src/test/java/glide/modules/JsonTests.java index 21d051f12f..43165dfd2a 100644 --- a/java/integTest/src/test/java/glide/modules/JsonTests.java +++ b/java/integTest/src/test/java/glide/modules/JsonTests.java @@ -17,7 +17,7 @@ import com.google.gson.JsonParser; import glide.api.GlideClusterClient; import glide.api.commands.servermodules.Json; -import glide.api.commands.servermodules.MultiJson; +import glide.api.commands.servermodules.JsonBatch; import glide.api.models.ClusterTransaction; import glide.api.models.GlideString; import glide.api.models.commands.ConditionalChange; @@ -1244,10 +1244,10 @@ public void transaction_tests() { String key5 = "{key}-5" + UUID.randomUUID(); String key6 = "{key}-6" + UUID.randomUUID(); - MultiJson.set(transaction, key1, "$", "{\"a\": \"one\", \"b\": [\"one\", \"two\"]}"); + JsonBatch.set(transaction, key1, "$", "{\"a\": \"one\", \"b\": [\"one\", \"two\"]}"); expectedResult.add(OK); - MultiJson.set( + JsonBatch.set( transaction, key1, "$", @@ -1255,172 +1255,172 @@ public void transaction_tests() { ConditionalChange.ONLY_IF_DOES_NOT_EXIST); expectedResult.add(null); - MultiJson.get(transaction, key1); + JsonBatch.get(transaction, key1); expectedResult.add("{\"a\":\"one\",\"b\":[\"one\",\"two\"]}"); - MultiJson.get(transaction, key1, new String[] {"$.a", "$.b"}); + JsonBatch.get(transaction, key1, new String[] {"$.a", "$.b"}); expectedResult.add("{\"$.a\":[\"one\"],\"$.b\":[[\"one\",\"two\"]]}"); - MultiJson.get(transaction, key1, JsonGetOptions.builder().space(" ").build()); + JsonBatch.get(transaction, key1, JsonGetOptions.builder().space(" ").build()); expectedResult.add("{\"a\": \"one\",\"b\": [\"one\",\"two\"]}"); - MultiJson.get( + JsonBatch.get( transaction, key1, new String[] {"$.a", "$.b"}, JsonGetOptions.builder().space(" ").build()); expectedResult.add("{\"$.a\": [\"one\"],\"$.b\": [[\"one\",\"two\"]]}"); - MultiJson.arrappend( + JsonBatch.arrappend( transaction, key1, "$.b", new String[] {"\"3\"", "\"4\"", "\"5\"", "\"6\""}); expectedResult.add(new Object[] {6L}); - MultiJson.arrindex(transaction, key1, "$..b", "\"one\""); + JsonBatch.arrindex(transaction, key1, "$..b", "\"one\""); expectedResult.add(new Object[] {0L}); - MultiJson.arrindex(transaction, key1, "$..b", "\"one\"", new JsonArrindexOptions(0L)); + JsonBatch.arrindex(transaction, key1, "$..b", "\"one\"", new JsonArrindexOptions(0L)); expectedResult.add(new Object[] {0L}); - MultiJson.arrinsert(transaction, key1, "$..b", 4, new String[] {"\"7\""}); + JsonBatch.arrinsert(transaction, key1, "$..b", 4, new String[] {"\"7\""}); expectedResult.add(new Object[] {7L}); - MultiJson.arrlen(transaction, key1, "$..b"); + JsonBatch.arrlen(transaction, key1, "$..b"); expectedResult.add(new Object[] {7L}); - MultiJson.arrpop(transaction, key1, "$..b", 6L); + JsonBatch.arrpop(transaction, key1, "$..b", 6L); expectedResult.add(new Object[] {"\"6\""}); - MultiJson.arrpop(transaction, key1, "$..b"); + JsonBatch.arrpop(transaction, key1, "$..b"); expectedResult.add(new Object[] {"\"5\""}); - MultiJson.arrtrim(transaction, key1, "$..b", 2, 3); + JsonBatch.arrtrim(transaction, key1, "$..b", 2, 3); expectedResult.add(new Object[] {2L}); - MultiJson.objlen(transaction, key1); + JsonBatch.objlen(transaction, key1); expectedResult.add(2L); - MultiJson.objlen(transaction, key1, "$..b"); + JsonBatch.objlen(transaction, key1, "$..b"); expectedResult.add(new Object[] {null}); - MultiJson.objkeys(transaction, key1, ".."); + JsonBatch.objkeys(transaction, key1, ".."); expectedResult.add(new Object[] {"a", "b"}); - MultiJson.objkeys(transaction, key1); + JsonBatch.objkeys(transaction, key1); expectedResult.add(new Object[] {"a", "b"}); - MultiJson.del(transaction, key1); + JsonBatch.del(transaction, key1); expectedResult.add(1L); - MultiJson.set( + JsonBatch.set( transaction, key1, "$", "{\"c\": [1, 2], \"d\": true, \"e\": [\"hello\", \"clouds\"], \"f\": {\"a\": \"hello\"}}"); expectedResult.add(OK); - MultiJson.del(transaction, key1, "$"); + JsonBatch.del(transaction, key1, "$"); expectedResult.add(1L); - MultiJson.set( + JsonBatch.set( transaction, key1, "$", "{\"c\": [1, 2], \"d\": true, \"e\": [\"hello\", \"clouds\"], \"f\": {\"a\": \"hello\"}}"); expectedResult.add(OK); - MultiJson.numincrby(transaction, key1, "$.c[*]", 10.0); + JsonBatch.numincrby(transaction, key1, "$.c[*]", 10.0); expectedResult.add("[11,12]"); - MultiJson.nummultby(transaction, key1, "$.c[*]", 10.0); + JsonBatch.nummultby(transaction, key1, "$.c[*]", 10.0); expectedResult.add("[110,120]"); - MultiJson.strappend(transaction, key1, "\"bar\"", "$..a"); + JsonBatch.strappend(transaction, key1, "\"bar\"", "$..a"); expectedResult.add(new Object[] {8L}); - MultiJson.strlen(transaction, key1, "$..a"); + JsonBatch.strlen(transaction, key1, "$..a"); expectedResult.add(new Object[] {8L}); - MultiJson.type(transaction, key1, "$..a"); + JsonBatch.type(transaction, key1, "$..a"); expectedResult.add(new Object[] {"string"}); - MultiJson.toggle(transaction, key1, "..d"); + JsonBatch.toggle(transaction, key1, "..d"); expectedResult.add(false); - MultiJson.resp(transaction, key1, "$..a"); + JsonBatch.resp(transaction, key1, "$..a"); expectedResult.add(new Object[] {"hellobar"}); - MultiJson.del(transaction, key1, "$..a"); + JsonBatch.del(transaction, key1, "$..a"); expectedResult.add(1L); // then delete the entire key - MultiJson.del(transaction, key1, "$"); + JsonBatch.del(transaction, key1, "$"); expectedResult.add(1L); // 2nd key - MultiJson.set(transaction, key2, "$", "[1, 2, true, null, \"tree\", \"tree2\" ]"); + JsonBatch.set(transaction, key2, "$", "[1, 2, true, null, \"tree\", \"tree2\" ]"); expectedResult.add(OK); - MultiJson.arrlen(transaction, key2); + JsonBatch.arrlen(transaction, key2); expectedResult.add(6L); - MultiJson.arrpop(transaction, key2); + JsonBatch.arrpop(transaction, key2); expectedResult.add("\"tree2\""); - MultiJson.debugFields(transaction, key2); + JsonBatch.debugFields(transaction, key2); expectedResult.add(5L); - MultiJson.debugFields(transaction, key2, "$"); + JsonBatch.debugFields(transaction, key2, "$"); expectedResult.add(new Object[] {5L}); // 3rd key - MultiJson.set(transaction, key3, "$", "\"abc\""); + JsonBatch.set(transaction, key3, "$", "\"abc\""); expectedResult.add(OK); - MultiJson.strappend(transaction, key3, "\"bar\""); + JsonBatch.strappend(transaction, key3, "\"bar\""); expectedResult.add(6L); - MultiJson.strlen(transaction, key3); + JsonBatch.strlen(transaction, key3); expectedResult.add(6L); - MultiJson.type(transaction, key3); + JsonBatch.type(transaction, key3); expectedResult.add("string"); - MultiJson.resp(transaction, key3); + JsonBatch.resp(transaction, key3); expectedResult.add("abcbar"); // 4th key - MultiJson.set(transaction, key4, "$", "true"); + JsonBatch.set(transaction, key4, "$", "true"); expectedResult.add(OK); - MultiJson.toggle(transaction, key4); + JsonBatch.toggle(transaction, key4); expectedResult.add(false); - MultiJson.debugMemory(transaction, key4); + JsonBatch.debugMemory(transaction, key4); expectedResult.add(24L); - MultiJson.debugMemory(transaction, key4, "$"); + JsonBatch.debugMemory(transaction, key4, "$"); expectedResult.add(new Object[] {16L}); - MultiJson.clear(transaction, key2, "$.a"); + JsonBatch.clear(transaction, key2, "$.a"); expectedResult.add(0L); - MultiJson.clear(transaction, key2); + JsonBatch.clear(transaction, key2); expectedResult.add(1L); - MultiJson.forget(transaction, key3); + JsonBatch.forget(transaction, key3); expectedResult.add(1L); - MultiJson.forget(transaction, key4, "$"); + JsonBatch.forget(transaction, key4, "$"); expectedResult.add(1L); // mget, key5 and key6 - MultiJson.set(transaction, key5, "$", "{\"a\": 1, \"b\": [\"one\", \"two\"]}"); + JsonBatch.set(transaction, key5, "$", "{\"a\": 1, \"b\": [\"one\", \"two\"]}"); expectedResult.add(OK); - MultiJson.set(transaction, key6, "$", "{\"a\": 1, \"c\": false}"); + JsonBatch.set(transaction, key6, "$", "{\"a\": 1, \"c\": false}"); expectedResult.add(OK); - MultiJson.mget(transaction, new String[] {key5, key6}, "$.c"); + JsonBatch.mget(transaction, new String[] {key5, key6}, "$.c"); expectedResult.add(new String[] {"[]", "[false]"}); Object[] results = client.exec(transaction).get(); diff --git a/node/THIRD_PARTY_LICENSES_NODE b/node/THIRD_PARTY_LICENSES_NODE index ee461e2b20..4f3283f499 100644 --- a/node/THIRD_PARTY_LICENSES_NODE +++ b/node/THIRD_PARTY_LICENSES_NODE @@ -25243,7 +25243,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- -Package: smallvec:1.13.2 +Package: time-macros:0.2.18 The following copyrights and licenses were found in the source code of this package: @@ -40172,7 +40172,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- -Package: mingo:6.5.2 The following copyrights and licenses were found in the source code of this package: diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index 7ed7a3da80..d24301f790 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -82,6 +82,7 @@ function initialize() { GlideClusterClient, GlideClientConfiguration, GlideJson, + JsonBatch, GlideFt, Field, TextField, @@ -238,6 +239,7 @@ function initialize() { FtSearchReturnType, GlideRecord, GlideJson, + JsonBatch, GlideString, JsonGetOptions, JsonArrPopOptions, diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 29979b7fc0..4fca78eed7 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -501,7 +501,10 @@ export type ReadFrom = | "preferReplica" /** Spread the requests between replicas in the same client's Aviliablity zone in a round robin manner. If no replica is available, route the requests to the primary.*/ - | "AZAffinity"; + | "AZAffinity" + /** Spread the read requests among all nodes within the client's Availability Zone (AZ) in a round robin manner, + prioritizing local replicas, then the local primary, and falling back to any replica or the primary if needed.*/ + | "AZAffinityReplicasAndPrimary"; /** * Configuration settings for creating a client. Shared settings for standalone and cluster clients. @@ -531,11 +534,11 @@ export type ReadFrom = * * ### Read Strategy * - * - Use `readFrom` to specify the client's read strategy (e.g., primary, preferReplica, AZAffinity). + * - Use `readFrom` to specify the client's read strategy (e.g., primary, preferReplica, AZAffinity, AZAffinityReplicasAndPrimary). * * ### Availability Zone * - * - Use `clientAz` to specify the client's availability zone, which can influence read operations when using `readFrom: 'AZAffinity'`. + * - Use `clientAz` to specify the client's availability zone, which can influence read operations when using `readFrom: 'AZAffinity'or `readFrom: 'AZAffinityReplicasAndPrimary'`. * * ### Decoder Settings * @@ -637,13 +640,15 @@ export interface BaseClientConfiguration { inflightRequestsLimit?: number; /** * Availability Zone of the client. - * If ReadFrom strategy is AZAffinity, this setting ensures that readonly commands are directed to replicas within the specified AZ if exits. + * If ReadFrom strategy is AZAffinity or AZAffinityReplicasAndPrimary, this setting ensures that readonly commands are directed to nodes within the specified AZ if they exist. * * @example * ```typescript * // Example configuration for setting client availability zone and read strategy * configuration.clientAz = 'us-east-1a'; // Sets the client's availability zone * configuration.readFrom = 'AZAffinity'; // Directs read operations to nodes within the same AZ + * Or + * configuration.readFrom = 'AZAffinityReplicasAndPrimary'; // Directs read operations to any node (primary or replica) within the same AZ * ``` */ clientAz?: string; @@ -6072,6 +6077,8 @@ export class BaseClient { primary: connection_request.ReadFrom.Primary, preferReplica: connection_request.ReadFrom.PreferReplica, AZAffinity: connection_request.ReadFrom.AZAffinity, + AZAffinityReplicasAndPrimary: + connection_request.ReadFrom.AZAffinityReplicasAndPrimary, }; /** diff --git a/node/src/server-modules/GlideJson.ts b/node/src/server-modules/GlideJson.ts index 4b9d1a2ded..1a59f0ba74 100644 --- a/node/src/server-modules/GlideJson.ts +++ b/node/src/server-modules/GlideJson.ts @@ -1166,15 +1166,15 @@ export class GlideJson { * @example * ```typescript * const transaction = new Transaction(); - * GlideMultiJson.set(transaction, "doc", ".", '{"a": 1.0, "b": 2}'); - * GlideMultiJson.get(transaction, "doc"); + * JsonBatch.set(transaction, "doc", ".", '{"a": 1.0, "b": 2}'); + * JsonBatch.get(transaction, "doc"); * const result = await client.exec(transaction); * - * console.log(result[0]); // Output: 'OK' - result of GlideMultiJson.set() - * console.log(result[1]); // Output: '{"a": 1.0, "b": 2}' - result of GlideMultiJson.get() + * console.log(result[0]); // Output: 'OK' - result of JsonBatch.set() + * console.log(result[1]); // Output: '{"a": 1.0, "b": 2}' - result of JsonBatch.get() * ``` */ -export class GlideMultiJson { +export class JsonBatch { /** * Sets the JSON value at the specified `path` stored at `key`. * diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index 9d444566bb..f144c9585e 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -2406,4 +2406,112 @@ describe("GlideClusterClient", () => { }, ); }); + describe("AZAffinityReplicasAndPrimary Read Strategy Tests", () => { + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + "should route GET commands to primary with the same AZ using protocol %p", + async (protocol) => { + // Skip test if version is below 8.0.0 + if (cluster.checkIfServerVersionLessThan("8.0.0")) return; + + const az = "us-east-1a"; + const other_az = "us-east-1b"; + const get_calls = 4; + + let client_for_config_set; + let client_for_testing_az; + + try { + // Stage 1: Configure nodes + client_for_config_set = + await GlideClusterClient.createClient( + getClientConfigurationOption( + azCluster.getAddresses(), + protocol, + { requestTimeout: 3000 }, + ), + ); + // Set all nodes for us-east-1b + await client_for_config_set.configResetStat(); + await client_for_config_set.configSet( + { "availability-zone": other_az }, + { route: "allNodes" }, + ); + + // Set AZ for one primary (the last one) to match the client's AZ + await client_for_config_set.configSet( + { "availability-zone": az }, + { route: { type: "primarySlotId", id: 12182 } }, + ); + + // Create client and verify configuration + client_for_testing_az = + await GlideClusterClient.createClient( + getClientConfigurationOption( + azCluster.getAddresses(), + protocol, + { + requestTimeout: 3000, + readFrom: "AZAffinityReplicasAndPrimary", + clientAz: az, + }, + ), + ); + + // Stage 3: Set test data and perform GET operations + const key = "foo_{12182}"; // Key targets slot 12182 + await client_for_testing_az.set(key, "testvalue"); + + for (let i = 0; i < get_calls; i++) { + await client_for_testing_az.get(key); + } + + // Stage 4: Verify GET commands were routed correctly + const info_result = (await client_for_testing_az.info({ + sections: [InfoOptions.All], + route: "allNodes", + })) as Record; + + let matching_entries_count = 0; + let total_get_calls = 0; + + Object.entries(info_result).forEach(([nodeId, infoStr]) => { + const isPrimaryNode = + infoStr.includes("role:master") || + infoStr.includes("role:primary"); + + // 1. Use the correct regex pattern + const azMatch = infoStr.match( + /availability_zone:(\S+)/, + ); + const nodeAZ = azMatch ? azMatch[1] : "unknown"; + + const isInClientAZ = nodeAZ === az; + const getCalls = parseInt( + (infoStr.match(/cmdstat_get:calls=(\d+)/) || + [])[1] || "0", + ); + total_get_calls += getCalls; + + if ( + isPrimaryNode && + getCalls === get_calls && + isInClientAZ + ) { + matching_entries_count++; + } else if (!isInClientAZ && getCalls > 0) { + throw new Error( + `WARNING: GET calls to node not in client AZ: ${nodeId}`, + ); + } + }); + + expect(matching_entries_count).toBe(1); // We expect only one primary in the client's AZ to have all the calls + expect(total_get_calls).toBe(get_calls); // We expect the total number of GET calls to match our input + } finally { + client_for_config_set?.close(); + client_for_testing_az?.close(); + } + }, + ); + }); }); diff --git a/node/tests/ServerModules.test.ts b/node/tests/ServerModules.test.ts index 96ac19cea3..4ea81c1fca 100644 --- a/node/tests/ServerModules.test.ts +++ b/node/tests/ServerModules.test.ts @@ -33,12 +33,12 @@ import { } from ".."; import { ValkeyCluster } from "../../utils/TestUtils"; import { + CreateJsonBatchCommands, flushAndCloseClient, getClientConfigurationOption, getServerVersion, + JsonBatchForArrCommands, parseEndpoints, - transactionMultiJson, - transactionMultiJsonForArrCommands, validateTransactionResponse, } from "./TestUtilities"; @@ -2313,7 +2313,7 @@ describe("Server Module Tests", () => { ).toBeNull(); }); - it("can send GlideMultiJson transactions for ARR commands", async () => { + it("can send JsonBatch transactions for ARR commands", async () => { client = await GlideClusterClient.createClient( getClientConfigurationOption( cluster.getAddresses(), @@ -2322,16 +2322,14 @@ describe("Server Module Tests", () => { ); const clusterTransaction = new ClusterTransaction(); const expectedRes = - await transactionMultiJsonForArrCommands( - clusterTransaction, - ); + await JsonBatchForArrCommands(clusterTransaction); const result = await client.exec(clusterTransaction); validateTransactionResponse(result, expectedRes); client.close(); }); - it("can send GlideMultiJson transactions general commands", async () => { + it("can send JsonBatch transactions general commands", async () => { client = await GlideClusterClient.createClient( getClientConfigurationOption( cluster.getAddresses(), @@ -2340,7 +2338,7 @@ describe("Server Module Tests", () => { ); const clusterTransaction = new ClusterTransaction(); const expectedRes = - await transactionMultiJson(clusterTransaction); + await CreateJsonBatchCommands(clusterTransaction); const result = await client.exec(clusterTransaction); validateTransactionResponse(result, expectedRes); diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 6c7eca4b9e..4a482f0885 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -26,12 +26,12 @@ import { GeospatialData, GlideClient, GlideClusterClient, - GlideMultiJson, GlideReturnType, GlideString, InfBoundary, InfoOptions, InsertPosition, + JsonBatch, ListDirection, ProtocolVersion, ReturnTypeMap, @@ -1915,7 +1915,7 @@ export async function transactionTest( * @param baseTransaction - A transaction. * @returns Array of tuples, where first element is a test name/description, second - expected return value. */ -export async function transactionMultiJsonForArrCommands( +export async function JsonBatchForArrCommands( baseTransaction: ClusterTransaction, ): Promise<[string, GlideReturnType][]> { const responseData: [string, GlideReturnType][] = []; @@ -1923,58 +1923,58 @@ export async function transactionMultiJsonForArrCommands( const jsonValue = { a: 1.0, b: 2 }; // JSON.SET - GlideMultiJson.set(baseTransaction, key, "$", JSON.stringify(jsonValue)); + JsonBatch.set(baseTransaction, key, "$", JSON.stringify(jsonValue)); responseData.push(['set(key, "{ a: 1.0, b: 2 }")', "OK"]); // JSON.CLEAR - GlideMultiJson.clear(baseTransaction, key, { path: "$" }); + JsonBatch.clear(baseTransaction, key, { path: "$" }); responseData.push(['clear(key, "bar")', 1]); - GlideMultiJson.set(baseTransaction, key, "$", JSON.stringify(jsonValue)); + JsonBatch.set(baseTransaction, key, "$", JSON.stringify(jsonValue)); responseData.push(['set(key, "$", "{ "a": 1, b: ["one", "two"] }")', "OK"]); // JSON.GET - GlideMultiJson.get(baseTransaction, key, { path: "." }); + JsonBatch.get(baseTransaction, key, { path: "." }); responseData.push(['get(key, {path: "."})', JSON.stringify(jsonValue)]); const jsonValue2 = { a: 1.0, b: [1, 2] }; - GlideMultiJson.set(baseTransaction, key, "$", JSON.stringify(jsonValue2)); + JsonBatch.set(baseTransaction, key, "$", JSON.stringify(jsonValue2)); responseData.push(['set(key, "$", "{ "a": 1, b: ["1", "2"] }")', "OK"]); // JSON.ARRAPPEND - GlideMultiJson.arrappend(baseTransaction, key, "$.b", ["3", "4"]); + JsonBatch.arrappend(baseTransaction, key, "$.b", ["3", "4"]); responseData.push(['arrappend(key, "$.b", [\'"3"\', \'"4"\'])', [4]]); // JSON.GET to check JSON.ARRAPPEND was successful. const jsonValueAfterAppend = { a: 1.0, b: [1, 2, 3, 4] }; - GlideMultiJson.get(baseTransaction, key, { path: "." }); + JsonBatch.get(baseTransaction, key, { path: "." }); responseData.push([ 'get(key, {path: "."})', JSON.stringify(jsonValueAfterAppend), ]); // JSON.ARRINDEX - GlideMultiJson.arrindex(baseTransaction, key, "$.b", "2"); + JsonBatch.arrindex(baseTransaction, key, "$.b", "2"); responseData.push(['arrindex(key, "$.b", "1")', [1]]); // JSON.ARRINSERT - GlideMultiJson.arrinsert(baseTransaction, key, "$.b", 2, ["5"]); + JsonBatch.arrinsert(baseTransaction, key, "$.b", 2, ["5"]); responseData.push(['arrinsert(key, "$.b", 4, [\'"5"\'])', [5]]); // JSON.GET to check JSON.ARRINSERT was successful. const jsonValueAfterArrInsert = { a: 1.0, b: [1, 2, 5, 3, 4] }; - GlideMultiJson.get(baseTransaction, key, { path: "." }); + JsonBatch.get(baseTransaction, key, { path: "." }); responseData.push([ 'get(key, {path: "."})', JSON.stringify(jsonValueAfterArrInsert), ]); // JSON.ARRLEN - GlideMultiJson.arrlen(baseTransaction, key, { path: "$.b" }); + JsonBatch.arrlen(baseTransaction, key, { path: "$.b" }); responseData.push(['arrlen(key, "$.b")', [5]]); // JSON.ARRPOP - GlideMultiJson.arrpop(baseTransaction, key, { + JsonBatch.arrpop(baseTransaction, key, { path: "$.b", index: 2, }); @@ -1982,19 +1982,19 @@ export async function transactionMultiJsonForArrCommands( // JSON.GET to check JSON.ARRPOP was successful. const jsonValueAfterArrpop = { a: 1.0, b: [1, 2, 3, 4] }; - GlideMultiJson.get(baseTransaction, key, { path: "." }); + JsonBatch.get(baseTransaction, key, { path: "." }); responseData.push([ 'get(key, {path: "."})', JSON.stringify(jsonValueAfterArrpop), ]); // JSON.ARRTRIM - GlideMultiJson.arrtrim(baseTransaction, key, "$.b", 1, 2); + JsonBatch.arrtrim(baseTransaction, key, "$.b", 1, 2); responseData.push(['arrtrim(key, "$.b", 2, 3)', [2]]); // JSON.GET to check JSON.ARRTRIM was successful. const jsonValueAfterArrTrim = { a: 1.0, b: [2, 3] }; - GlideMultiJson.get(baseTransaction, key, { path: "." }); + JsonBatch.get(baseTransaction, key, { path: "." }); responseData.push([ 'get(key, {path: "."})', JSON.stringify(jsonValueAfterArrTrim), @@ -2002,7 +2002,7 @@ export async function transactionMultiJsonForArrCommands( return responseData; } -export async function transactionMultiJson( +export async function CreateJsonBatchCommands( baseTransaction: ClusterTransaction, ): Promise<[string, GlideReturnType][]> { const responseData: [string, GlideReturnType][] = []; @@ -2010,64 +2010,64 @@ export async function transactionMultiJson( const jsonValue = { a: [1, 2], b: [3, 4], c: "c", d: true }; // JSON.SET to create a key for testing commands. - GlideMultiJson.set(baseTransaction, key, "$", JSON.stringify(jsonValue)); + JsonBatch.set(baseTransaction, key, "$", JSON.stringify(jsonValue)); responseData.push(['set(key, "$")', "OK"]); // JSON.DEBUG MEMORY - GlideMultiJson.debugMemory(baseTransaction, key, { path: "$.a" }); + JsonBatch.debugMemory(baseTransaction, key, { path: "$.a" }); responseData.push(['debugMemory(key, "{ path: "$.a" }")', [48]]); // JSON.DEBUG FIELDS - GlideMultiJson.debugFields(baseTransaction, key, { path: "$.a" }); + JsonBatch.debugFields(baseTransaction, key, { path: "$.a" }); responseData.push(['debugFields(key, "{ path: "$.a" }")', [2]]); // JSON.OBJLEN - GlideMultiJson.objlen(baseTransaction, key, { path: "." }); + JsonBatch.objlen(baseTransaction, key, { path: "." }); responseData.push(["objlen(key)", 4]); // JSON.OBJKEY - GlideMultiJson.objkeys(baseTransaction, key, { path: "." }); + JsonBatch.objkeys(baseTransaction, key, { path: "." }); responseData.push(['objkeys(key, "$.")', ["a", "b", "c", "d"]]); // JSON.NUMINCRBY - GlideMultiJson.numincrby(baseTransaction, key, "$.a[*]", 10.0); + JsonBatch.numincrby(baseTransaction, key, "$.a[*]", 10.0); responseData.push(['numincrby(key, "$.a[*]", 10.0)', "[11,12]"]); // JSON.NUMMULTBY - GlideMultiJson.nummultby(baseTransaction, key, "$.a[*]", 10.0); + JsonBatch.nummultby(baseTransaction, key, "$.a[*]", 10.0); responseData.push(['nummultby(key, "$.a[*]", 10.0)', "[110,120]"]); // // JSON.STRAPPEND - GlideMultiJson.strappend(baseTransaction, key, '"-test"', { path: "$.c" }); + JsonBatch.strappend(baseTransaction, key, '"-test"', { path: "$.c" }); responseData.push(['strappend(key, \'"-test"\', "$.c")', [6]]); // // JSON.STRLEN - GlideMultiJson.strlen(baseTransaction, key, { path: "$.c" }); + JsonBatch.strlen(baseTransaction, key, { path: "$.c" }); responseData.push(['strlen(key, "$.c")', [6]]); // JSON.TYPE - GlideMultiJson.type(baseTransaction, key, { path: "$.a" }); + JsonBatch.type(baseTransaction, key, { path: "$.a" }); responseData.push(['type(key, "$.a")', ["array"]]); // JSON.MGET const key2 = "{key}:2" + uuidv4(); const key3 = "{key}:3" + uuidv4(); const jsonValue2 = { b: [3, 4], c: "c", d: true }; - GlideMultiJson.set(baseTransaction, key2, "$", JSON.stringify(jsonValue2)); + JsonBatch.set(baseTransaction, key2, "$", JSON.stringify(jsonValue2)); responseData.push(['set(key2, "$")', "OK"]); - GlideMultiJson.mget(baseTransaction, [key, key2, key3], "$.a"); + JsonBatch.mget(baseTransaction, [key, key2, key3], "$.a"); responseData.push([ 'json.mget([key, key2, key3], "$.a")', ["[[110,120]]", "[]", null], ]); // JSON.TOGGLE - GlideMultiJson.toggle(baseTransaction, key, { path: "$.d" }); + JsonBatch.toggle(baseTransaction, key, { path: "$.d" }); responseData.push(['toggle(key2, "$.d")', [false]]); // JSON.RESP - GlideMultiJson.resp(baseTransaction, key, { path: "$" }); + JsonBatch.resp(baseTransaction, key, { path: "$" }); responseData.push([ 'resp(key, "$")', [ @@ -2082,11 +2082,11 @@ export async function transactionMultiJson( ]); // JSON.DEL - GlideMultiJson.del(baseTransaction, key, { path: "$.d" }); + JsonBatch.del(baseTransaction, key, { path: "$.d" }); responseData.push(['del(key, { path: "$.d" })', 1]); // JSON.FORGET - GlideMultiJson.forget(baseTransaction, key, { path: "$.c" }); + JsonBatch.forget(baseTransaction, key, { path: "$.c" }); responseData.push(['forget(key, {path: "$.c" })', 1]); return responseData; diff --git a/python/THIRD_PARTY_LICENSES_PYTHON b/python/THIRD_PARTY_LICENSES_PYTHON index ce9c3d4a98..3f87cf5504 100644 --- a/python/THIRD_PARTY_LICENSES_PYTHON +++ b/python/THIRD_PARTY_LICENSES_PYTHON @@ -25506,7 +25506,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---- -Package: smallvec:1.13.2 +Package: smallvec:1.14.0 The following copyrights and licenses were found in the source code of this package: diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index 9e3d808a8c..541d907023 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -33,7 +33,7 @@ OnlyIfEqual, UpdateOptions, ) -from glide.async_commands.server_modules import ft, glide_json, json_transaction +from glide.async_commands.server_modules import ft, glide_json, json_batch from glide.async_commands.server_modules.ft_options.ft_aggregate_options import ( FtAggregateApply, FtAggregateClause, @@ -273,7 +273,7 @@ "PubSubMsg", # Json "glide_json", - "json_transaction", + "json_batch", "JsonGetOptions", "JsonArrIndexOptions", "JsonArrPopOptions", diff --git a/python/python/glide/async_commands/server_modules/json_transaction.py b/python/python/glide/async_commands/server_modules/json_batch.py similarity index 99% rename from python/python/glide/async_commands/server_modules/json_transaction.py rename to python/python/glide/async_commands/server_modules/json_batch.py index ad0cc91158..08608be2eb 100644 --- a/python/python/glide/async_commands/server_modules/json_transaction.py +++ b/python/python/glide/async_commands/server_modules/json_batch.py @@ -3,12 +3,12 @@ Examples: >>> import json - >>> from glide import json_transaction + >>> from glide import json_batch >>> transaction = ClusterTransaction() >>> value = {'a': 1.0, 'b': 2} >>> json_str = json.dumps(value) # Convert Python dictionary to JSON string using json.dumps() - >>> json_transaction.set(transaction, "doc", "$", json_str) - >>> json_transaction.get(transaction, "doc", "$") # Returns the value at path '$' in the JSON document stored at `doc` as JSON string. + >>> json_batch.set(transaction, "doc", "$", json_str) + >>> json_batch.get(transaction, "doc", "$") # Returns the value at path '$' in the JSON document stored at `doc` as JSON string. >>> result = await glide_client.exec(transaction) >>> print result[0] # set result 'OK' # Indicates successful setting of the value at path '$' in the key stored at `doc`. diff --git a/python/python/glide/config.py b/python/python/glide/config.py index 9ee018d2a4..05136d8f59 100644 --- a/python/python/glide/config.py +++ b/python/python/glide/config.py @@ -46,6 +46,11 @@ class ReadFrom(Enum): Spread the read requests between replicas in the same client's AZ (Aviliablity zone) in a round robin manner, falling back to other replicas or the primary if needed """ + AZ_AFFINITY_REPLICAS_AND_PRIMARY = ProtobufReadFrom.AZAffinityReplicasAndPrimary + """ + Spread the read requests among nodes within the client's Availability Zone (AZ) in a round robin manner, + prioritizing local replicas, then the local primary, and falling back to any replica or the primary if needed. + """ class ProtocolVersion(Enum): @@ -194,6 +199,7 @@ def __init__( If not set, a default value will be used. client_az (Optional[str]): Availability Zone of the client. If ReadFrom strategy is AZAffinity, this setting ensures that readonly commands are directed to replicas within the specified AZ if exits. + If ReadFrom strategy is AZAffinityReplicasAndPrimary, this setting ensures that readonly commands are directed to nodes (first replicas then primary) within the specified AZ if they exist. advanced_config (Optional[AdvancedBaseClientConfiguration]): Advanced configuration settings for the client. """ self.addresses = addresses @@ -212,6 +218,11 @@ def __init__( "client_az must be set when read_from is set to AZ_AFFINITY" ) + if read_from == ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY and not client_az: + raise ValueError( + "client_az must be set when read_from is set to AZ_AFFINITY_REPLICAS_AND_PRIMARY" + ) + def _create_a_protobuf_conn_request( self, cluster_mode: bool = False ) -> ConnectionRequest: @@ -302,6 +313,7 @@ class GlideClientConfiguration(BaseClientConfiguration): If not set, a default value will be used. client_az (Optional[str]): Availability Zone of the client. If ReadFrom strategy is AZAffinity, this setting ensures that readonly commands are directed to replicas within the specified AZ if exits. + If ReadFrom strategy is AZAffinityReplicasAndPrimary, this setting ensures that readonly commands are directed to nodes (first replicas then primary) within the specified AZ if they exist. advanced_config (Optional[AdvancedGlideClientConfiguration]): Advanced configuration settings for the client, see `AdvancedGlideClientConfiguration`. """ @@ -458,6 +470,7 @@ class GlideClusterClientConfiguration(BaseClientConfiguration): If not set, a default value will be used. client_az (Optional[str]): Availability Zone of the client. If ReadFrom strategy is AZAffinity, this setting ensures that readonly commands are directed to replicas within the specified AZ if exits. + If ReadFrom strategy is AZAffinityReplicasAndPrimary, this setting ensures that readonly commands are directed to nodes (first replicas then primary) within the specified AZ if they exist. advanced_config (Optional[AdvancedGlideClusterClientConfiguration]) : Advanced configuration settings for the client, see `AdvancedGlideClusterClientConfiguration`. diff --git a/python/python/tests/test_config.py b/python/python/tests/test_config.py index 2476d8ec0f..b048def620 100644 --- a/python/python/tests/test_config.py +++ b/python/python/tests/test_config.py @@ -75,6 +75,21 @@ def test_convert_config_with_azaffinity_to_protobuf(): assert request.client_az == az +def test_convert_config_with_azaffinity_replicas_and_primary_to_protobuf(): + az = "us-east-1a" + config = BaseClientConfiguration( + [NodeAddress("127.0.0.1")], + use_tls=True, + read_from=ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY, + client_az=az, + ) + request = config._create_a_protobuf_conn_request() + assert isinstance(request, ConnectionRequest) + assert request.tls_mode is TlsMode.SecureTls + assert request.read_from == ProtobufReadFrom.AZAffinityReplicasAndPrimary + assert request.client_az == az + + def test_connection_timeout_in_protobuf_request(): connection_timeout = 5000 # in milliseconds config = GlideClientConfiguration( diff --git a/python/python/tests/test_read_from_strategy.py b/python/python/tests/test_read_from_strategy.py index cddb1e6f10..ddaf16b860 100644 --- a/python/python/tests/test_read_from_strategy.py +++ b/python/python/tests/test_read_from_strategy.py @@ -219,3 +219,107 @@ async def test_az_affinity_requires_client_az( read_from=ReadFrom.AZ_AFFINITY, request_timeout=2000, ) + + @pytest.mark.skip_if_version_below("8.0.0") + @pytest.mark.parametrize("cluster_mode", [True]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_az_affinity_replicas_and_primary_routes_to_primary( + self, + request, + cluster_mode: bool, + protocol: ProtocolVersion, + ): + """Test that the client with AZ_AFFINITY_REPLICAS_AND_PRIMARY routes to the primary in the same AZ""" + az = "us-east-1a" + other_az = "us-east-1b" + GET_CALLS = 4 + + client_for_config_set = None + client_for_testing_az = None + + try: + client_for_config_set = await create_client( + request, + cluster_mode, + protocol=protocol, + request_timeout=2000, + ) + + # Reset stats and set all nodes to other_az + await client_for_config_set.config_resetstat() + await client_for_config_set.custom_command( + ["CONFIG", "SET", "availability-zone", other_az], + AllNodes(), + ) + + # Set primary for slot 12182 to az + await client_for_config_set.custom_command( + ["CONFIG", "SET", "availability-zone", az], + route=SlotIdRoute(SlotType.PRIMARY, 12182), + ) + + # Verify primary AZ + primary_az = await client_for_config_set.custom_command( + ["CONFIG", "GET", "availability-zone"], + route=SlotIdRoute(SlotType.PRIMARY, 12182), + ) + assert ( + primary_az[b"availability-zone"].decode() == az + ), f"Primary for slot 12182 is not in the expected AZ {az}" + + # Create test client AFTER configuration + client_for_testing_az = await create_client( + request, + cluster_mode, + protocol=protocol, + read_from=ReadFrom.AZ_AFFINITY_REPLICAS_AND_PRIMARY, + client_az=az, + request_timeout=2000, + ) + + # Perform GET operations + for i in range(GET_CALLS): + await client_for_testing_az.get("foo") + + # Collect info from all nodes + info_result = await client_for_testing_az.info( + [ + InfoSection.SERVER, + InfoSection.REPLICATION, + InfoSection.COMMAND_STATS, + ], + AllNodes(), + ) + + matching_entries_count = 0 + total_get_calls = 0 + node_info_list = [] + + for node, node_info in info_result.items(): + info_str = node_info.decode() + is_primary = "role:master" in info_str + az_match = re.search(r"availability_zone:(\S+)", info_str) + node_az = az_match.group(1) if az_match else "" + get_calls_match = re.search(r"cmdstat_get:calls=(\d+)", info_str) + get_calls = int(get_calls_match.group(1)) if get_calls_match else 0 + + total_get_calls += get_calls + node_info_list.append((node_az, is_primary, get_calls)) + + if is_primary and node_az == az and get_calls == GET_CALLS: + matching_entries_count += 1 + elif node_az != az and get_calls > 0: + pytest.fail(f"GET calls found on node not in AZ {az}") + + assert ( + matching_entries_count == 1 + ), f"Exactly one primary in AZ should handle all calls. Matching entries: {matching_entries_count}, Total GET calls: {total_get_calls}" + assert ( + total_get_calls == GET_CALLS + ), f"Total GET calls mismatch, expected {GET_CALLS}, got {total_get_calls}" + + finally: + if client_for_testing_az: + await client_for_testing_az.close() + if client_for_config_set: + await client_for_config_set.close() diff --git a/python/python/tests/tests_server_modules/test_json.py b/python/python/tests/tests_server_modules/test_json.py index 0182943d82..207a48826c 100644 --- a/python/python/tests/tests_server_modules/test_json.py +++ b/python/python/tests/tests_server_modules/test_json.py @@ -9,7 +9,7 @@ import pytest from glide.async_commands.core import ConditionalChange, InfoSection from glide.async_commands.server_modules import glide_json as json -from glide.async_commands.server_modules import json_transaction +from glide.async_commands.server_modules import json_batch from glide.async_commands.server_modules.glide_json import ( JsonArrIndexOptions, JsonArrPopOptions, @@ -2107,7 +2107,7 @@ async def test_json_arrpop(self, glide_client: TGlideClient): @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_transaction_array(self, glide_client: GlideClusterClient): + async def test_json_batch_array(self, glide_client: GlideClusterClient): transaction = ClusterTransaction() key = get_random_string(5) @@ -2115,22 +2115,20 @@ async def test_json_transaction_array(self, glide_client: GlideClusterClient): json_value2 = {"a": 1.0, "b": [1, 2]} # Test 'set', 'get', and 'clear' commands - json_transaction.set(transaction, key, "$", OuterJson.dumps(json_value1)) - json_transaction.clear(transaction, key, "$") - json_transaction.set(transaction, key, "$", OuterJson.dumps(json_value1)) - json_transaction.get(transaction, key, ".") + json_batch.set(transaction, key, "$", OuterJson.dumps(json_value1)) + json_batch.clear(transaction, key, "$") + json_batch.set(transaction, key, "$", OuterJson.dumps(json_value1)) + json_batch.get(transaction, key, ".") # Test array related commands - json_transaction.set(transaction, key, "$", OuterJson.dumps(json_value2)) - json_transaction.arrappend(transaction, key, "$.b", ["3", "4"]) - json_transaction.arrindex(transaction, key, "$.b", "2") - json_transaction.arrinsert(transaction, key, "$.b", 2, ["5"]) - json_transaction.arrlen(transaction, key, "$.b") - json_transaction.arrpop( - transaction, key, JsonArrPopOptions(path="$.b", index=2) - ) - json_transaction.arrtrim(transaction, key, "$.b", 1, 2) - json_transaction.get(transaction, key, ".") + json_batch.set(transaction, key, "$", OuterJson.dumps(json_value2)) + json_batch.arrappend(transaction, key, "$.b", ["3", "4"]) + json_batch.arrindex(transaction, key, "$.b", "2") + json_batch.arrinsert(transaction, key, "$.b", 2, ["5"]) + json_batch.arrlen(transaction, key, "$.b") + json_batch.arrpop(transaction, key, JsonArrPopOptions(path="$.b", index=2)) + json_batch.arrtrim(transaction, key, "$.b", 1, 2) + json_batch.get(transaction, key, ".") result = await glide_client.exec(transaction) assert isinstance(result, list) @@ -2153,7 +2151,7 @@ async def test_json_transaction_array(self, glide_client: GlideClusterClient): @pytest.mark.parametrize("cluster_mode", [True]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) - async def test_json_transaction(self, glide_client: GlideClusterClient): + async def test_json_batch(self, glide_client: GlideClusterClient): transaction = ClusterTransaction() key = f"{{key}}-1{get_random_string(5)}" @@ -2161,43 +2159,43 @@ async def test_json_transaction(self, glide_client: GlideClusterClient): key3 = f"{{key}}-3{get_random_string(5)}" json_value = {"a": [1, 2], "b": [3, 4], "c": "c", "d": True} - json_transaction.set(transaction, key, "$", OuterJson.dumps(json_value)) + json_batch.set(transaction, key, "$", OuterJson.dumps(json_value)) # Test debug commands - json_transaction.debug_memory(transaction, key, "$.a") - json_transaction.debug_fields(transaction, key, "$.a") + json_batch.debug_memory(transaction, key, "$.a") + json_batch.debug_fields(transaction, key, "$.a") # Test obj commands - json_transaction.objlen(transaction, key, ".") - json_transaction.objkeys(transaction, key, ".") + json_batch.objlen(transaction, key, ".") + json_batch.objkeys(transaction, key, ".") # Test num commands - json_transaction.numincrby(transaction, key, "$.a[*]", 10.0) - json_transaction.nummultby(transaction, key, "$.a[*]", 10.0) + json_batch.numincrby(transaction, key, "$.a[*]", 10.0) + json_batch.nummultby(transaction, key, "$.a[*]", 10.0) # Test str commands - json_transaction.strappend(transaction, key, '"-test"', "$.c") - json_transaction.strlen(transaction, key, "$.c") + json_batch.strappend(transaction, key, '"-test"', "$.c") + json_batch.strlen(transaction, key, "$.c") # Test type command - json_transaction.type(transaction, key, "$.a") + json_batch.type(transaction, key, "$.a") # Test mget command json_value2 = {"b": [3, 4], "c": "c", "d": True} - json_transaction.set(transaction, key2, "$", OuterJson.dumps(json_value2)) - json_transaction.mget(transaction, [key, key2, key3], "$.a") + json_batch.set(transaction, key2, "$", OuterJson.dumps(json_value2)) + json_batch.mget(transaction, [key, key2, key3], "$.a") # Test toggle command - json_transaction.toggle(transaction, key, "$.d") + json_batch.toggle(transaction, key, "$.d") # Test resp command - json_transaction.resp(transaction, key, "$") + json_batch.resp(transaction, key, "$") # Test del command - json_transaction.delete(transaction, key, "$.d") + json_batch.delete(transaction, key, "$.d") # Test forget command - json_transaction.forget(transaction, key, "$.c") + json_batch.forget(transaction, key, "$.c") result = await glide_client.exec(transaction) assert isinstance(result, list)