From 678bf21b488419750f213e429b9fb84b5844d1dc Mon Sep 17 00:00:00 2001 From: Chayim Date: Tue, 19 Sep 2023 18:53:47 +0300 Subject: [PATCH 1/8] Updating redis binary for makefile to 7.2.1 (#2693) * updating redis binary from makefile to 7.2.0 * redis 7.2.1 --------- Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b59c39554..cf1f6428d 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ bench: testdeps testdata/redis: mkdir -p $@ - wget -qO- https://download.redis.io/releases/redis-7.2-rc3.tar.gz | tar xvz --strip-components=1 -C $@ + wget -qO- https://download.redis.io/releases/redis-7.2.1.tar.gz | tar xvz --strip-components=1 -C $@ testdata/redis/src/redis-server: testdata/redis cd $< && make all From 54a106ee19668505a9bdf04246401fa3c10d5293 Mon Sep 17 00:00:00 2001 From: Chayim Date: Wed, 20 Sep 2023 09:28:28 +0300 Subject: [PATCH 2/8] Adding stale issues workflow (#2700) --- .github/workflows/stale-issues.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/stale-issues.yml diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml new file mode 100644 index 000000000..32fd9e817 --- /dev/null +++ b/.github/workflows/stale-issues.yml @@ -0,0 +1,25 @@ +name: "Close stale issues" +on: + schedule: + - cron: "0 0 * * *" + +permissions: {} +jobs: + stale: + permissions: + issues: write # to close stale issues (actions/stale) + pull-requests: write # to close stale PRs (actions/stale) + + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v3 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-issue-message: 'This issue is marked stale. It will be closed in 30 days if it is not updated.' + stale-pr-message: 'This pull request is marked stale. It will be closed in 30 days if it is not updated.' + days-before-stale: 365 + days-before-close: 30 + stale-issue-label: "Stale" + stale-pr-label: "Stale" + operations-per-run: 10 + remove-stale-when-updated: true From 0b6be62b7175a3bf958962bcf39936af3bc90869 Mon Sep 17 00:00:00 2001 From: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> Date: Wed, 20 Sep 2023 10:33:09 +0300 Subject: [PATCH 3/8] Identify client on connect (#2708) * Update CLIENT-SETINFO to support suffixes * Update CLIENT-SETINFO * fix acl log test * add setinfo option to cluster * change to DisableIndentity * change to DisableIndentity --- bench_decode_test.go | 3 +++ cluster.go | 21 +++++++++++---------- commands.go | 5 ++++- commands_test.go | 3 +-- options.go | 3 +++ redis.go | 9 ++++++++- 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/bench_decode_test.go b/bench_decode_test.go index de53064f2..50e339086 100644 --- a/bench_decode_test.go +++ b/bench_decode_test.go @@ -30,6 +30,7 @@ func NewClientStub(resp []byte) *ClientStub { Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { return stub.stubConn(initHello), nil }, + DisableIndentity: true, }) return stub } @@ -45,6 +46,8 @@ func NewClusterClientStub(resp []byte) *ClientStub { Dialer: func(ctx context.Context, network, addr string) (net.Conn, error) { return stub.stubConn(initHello), nil }, + DisableIndentity: true, + ClusterSlots: func(_ context.Context) ([]ClusterSlot, error) { return []ClusterSlot{ { diff --git a/cluster.go b/cluster.go index 941838dd0..b30e22637 100644 --- a/cluster.go +++ b/cluster.go @@ -83,7 +83,8 @@ type ClusterOptions struct { ConnMaxIdleTime time.Duration ConnMaxLifetime time.Duration - TLSConfig *tls.Config + TLSConfig *tls.Config + DisableIndentity bool // Disable set-lib on connect. Default is false. } func (opt *ClusterOptions) init() { @@ -277,15 +278,15 @@ func (opt *ClusterOptions) clientOptions() *Options { ReadTimeout: opt.ReadTimeout, WriteTimeout: opt.WriteTimeout, - PoolFIFO: opt.PoolFIFO, - PoolSize: opt.PoolSize, - PoolTimeout: opt.PoolTimeout, - MinIdleConns: opt.MinIdleConns, - MaxIdleConns: opt.MaxIdleConns, - ConnMaxIdleTime: opt.ConnMaxIdleTime, - ConnMaxLifetime: opt.ConnMaxLifetime, - - TLSConfig: opt.TLSConfig, + PoolFIFO: opt.PoolFIFO, + PoolSize: opt.PoolSize, + PoolTimeout: opt.PoolTimeout, + MinIdleConns: opt.MinIdleConns, + MaxIdleConns: opt.MaxIdleConns, + ConnMaxIdleTime: opt.ConnMaxIdleTime, + ConnMaxLifetime: opt.ConnMaxLifetime, + DisableIndentity: opt.DisableIndentity, + TLSConfig: opt.TLSConfig, // If ClusterSlots is populated, then we probably have an artificial // cluster whose nodes are not in clustering mode (otherwise there isn't // much use for ClusterSlots config). This means we cannot execute the diff --git a/commands.go b/commands.go index 4a3cd9ace..2b2abfb75 100644 --- a/commands.go +++ b/commands.go @@ -4,9 +4,11 @@ import ( "context" "encoding" "errors" + "fmt" "io" "net" "reflect" + "runtime" "strings" "time" @@ -584,7 +586,8 @@ func (c statefulCmdable) ClientSetInfo(ctx context.Context, info LibraryInfo) *S var cmd *StatusCmd if info.LibName != nil { - cmd = NewStatusCmd(ctx, "client", "setinfo", "LIB-NAME", *info.LibName) + libName := fmt.Sprintf("go-redis(%s,%s)", *info.LibName, runtime.Version()) + cmd = NewStatusCmd(ctx, "client", "setinfo", "LIB-NAME", libName) } else { cmd = NewStatusCmd(ctx, "client", "setinfo", "LIB-VER", *info.LibVer) } diff --git a/commands_test.go b/commands_test.go index c8ea0f7bd..b77447682 100644 --- a/commands_test.go +++ b/commands_test.go @@ -2052,10 +2052,9 @@ var _ = Describe("Commands", func() { logEntries, err := client.ACLLog(ctx, 10).Result() Expect(err).NotTo(HaveOccurred()) - Expect(len(logEntries)).To(Equal(3)) + Expect(len(logEntries)).To(Equal(4)) for _, entry := range logEntries { - Expect(entry.Count).To(BeNumerically("==", 1)) Expect(entry.Reason).To(Equal("command")) Expect(entry.Context).To(Equal("toplevel")) Expect(entry.Object).NotTo(BeEmpty()) diff --git a/options.go b/options.go index bb4816b27..f10bad38b 100644 --- a/options.go +++ b/options.go @@ -136,6 +136,9 @@ type Options struct { // Enables read only queries on slave/follower nodes. readOnly bool + + // // Disable set-lib on connect. Default is false. + DisableIndentity bool } func (opt *Options) init() { diff --git a/redis.go b/redis.go index c7fbd0de8..9430eb75c 100644 --- a/redis.go +++ b/redis.go @@ -299,7 +299,14 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error { // difficult to rely on error strings to determine all results. return err } - + if !c.opt.DisableIndentity { + libName := "" + libVer := Version() + libInfo := LibraryInfo{LibName: &libName} + conn.ClientSetInfo(ctx, libInfo) + libInfo = LibraryInfo{LibVer: &libVer} + conn.ClientSetInfo(ctx, libInfo) + } _, err := conn.Pipelined(ctx, func(pipe Pipeliner) error { if !auth && password != "" { if username != "" { From 736351c7cf80e56102cb05bb7029bdc8579f0352 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 10:41:10 +0300 Subject: [PATCH 4/8] chore(deps): bump actions/checkout from 3 to 4 (#2702) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/doctests.yaml | 2 +- .github/workflows/golangci-lint.yml | 2 +- .github/workflows/spellcheck.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 403e199d0..4dacf2a13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test run: make test diff --git a/.github/workflows/doctests.yaml b/.github/workflows/doctests.yaml index 00b0063bf..dac223363 100644 --- a/.github/workflows/doctests.yaml +++ b/.github/workflows/doctests.yaml @@ -34,7 +34,7 @@ jobs: go-version: ${{ matrix.go-version }} - name: Checkout code - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Test doc examples working-directory: ./doctests diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index d3232ecbd..e35ee85c0 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -21,6 +21,6 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: golangci-lint uses: golangci/golangci-lint-action@v3 diff --git a/.github/workflows/spellcheck.yml b/.github/workflows/spellcheck.yml index e15284155..3bd776cf1 100644 --- a/.github/workflows/spellcheck.yml +++ b/.github/workflows/spellcheck.yml @@ -6,7 +6,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Check Spelling uses: rojopolis/spellcheck-github-actions@0.33.1 with: From 33edd3de6858f9c3312d1536249f4a987f1583bd Mon Sep 17 00:00:00 2001 From: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> Date: Wed, 20 Sep 2023 10:42:09 +0300 Subject: [PATCH 5/8] Rename probablistic commands with args (#2701) Co-authored-by: Chayim --- probabilistic.go | 18 +++++++++--------- probabilistic_test.go | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/probabilistic.go b/probabilistic.go index 8e32bca98..969ce8281 100644 --- a/probabilistic.go +++ b/probabilistic.go @@ -24,7 +24,7 @@ type probabilisticCmdable interface { BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd - BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd + BFReserveWithArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd BFScanDump(ctx context.Context, key string, iterator int64) *ScanDumpCmd BFLoadChunk(ctx context.Context, key string, iterator int64, data interface{}) *StatusCmd @@ -38,7 +38,7 @@ type probabilisticCmdable interface { CFInsertNX(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd CFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd - CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd + CFReserveWithArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd CFReserveExpansion(ctx context.Context, key string, capacity int64, expansion int64) *StatusCmd CFReserveBucketSize(ctx context.Context, key string, capacity int64, bucketsize int64) *StatusCmd CFReserveMaxIterations(ctx context.Context, key string, capacity int64, maxiterations int64) *StatusCmd @@ -143,11 +143,11 @@ func (c cmdable) BFReserveNonScaling(ctx context.Context, key string, errorRate return cmd } -// BFReserveArgs creates an empty Bloom filter with a single sub-filter +// BFReserveWithArgs creates an empty Bloom filter with a single sub-filter // for the initial specified capacity and with an upper bound error_rate. // This function also allows for specifying additional options such as expansion rate and non-scaling behavior. // For more information - https://redis.io/commands/bf.reserve/ -func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd { +func (c cmdable) BFReserveWithArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd { args := []interface{}{"BF.RESERVE", key} if options != nil { if options.Error != 0 { @@ -493,10 +493,10 @@ func (c cmdable) CFReserveMaxIterations(ctx context.Context, key string, capacit return cmd } -// CFReserveArgs creates an empty Cuckoo filter with the specified options. +// CFReserveWithArgs creates an empty Cuckoo filter with the specified options. // This function allows for specifying additional options such as bucket size and maximum number of iterations. // For more information - https://redis.io/commands/cf.reserve/ -func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd { +func (c cmdable) CFReserveWithArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd { args := []interface{}{"CF.RESERVE", key, options.Capacity} if options.BucketSize != 0 { args = append(args, "BUCKETSIZE", options.BucketSize) @@ -679,7 +679,7 @@ func (c cmdable) CFInfo(ctx context.Context, key string) *CFInfoCmd { // For more information - https://redis.io/commands/cf.insert/ func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd { args := []interface{}{"CF.INSERT", key} - args = c.getCfInsertArgs(args, options, elements...) + args = c.getCfInsertWithArgs(args, options, elements...) cmd := NewBoolSliceCmd(ctx, args...) _ = c(ctx, cmd) @@ -693,14 +693,14 @@ func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOpti // For more information - https://redis.io/commands/cf.insertnx/ func (c cmdable) CFInsertNX(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd { args := []interface{}{"CF.INSERTNX", key} - args = c.getCfInsertArgs(args, options, elements...) + args = c.getCfInsertWithArgs(args, options, elements...) cmd := NewIntSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } -func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, elements ...interface{}) []interface{} { +func (c cmdable) getCfInsertWithArgs(args []interface{}, options *CFInsertOptions, elements ...interface{}) []interface{} { if options != nil { if options.Capacity != 0 { args = append(args, "CAPACITY", options.Capacity) diff --git a/probabilistic_test.go b/probabilistic_test.go index 4b0dde646..b493abd46 100644 --- a/probabilistic_test.go +++ b/probabilistic_test.go @@ -227,14 +227,14 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expect(infBefore).To(BeEquivalentTo(infAfter)) }) - It("should BFReserveArgs", Label("bloom", "bfreserveargs"), func() { + It("should BFReserveWithArgs", Label("bloom", "bfreserveargs"), func() { options := &redis.BFReserveOptions{ Capacity: 2000, Error: 0.001, Expansion: 3, NonScaling: false, } - err := client.BFReserveArgs(ctx, "testbf", options).Err() + err := client.BFReserveWithArgs(ctx, "testbf", options).Err() Expect(err).NotTo(HaveOccurred()) result, err := client.BFInfo(ctx, "testbf").Result() @@ -352,7 +352,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expect(infBefore).To(BeEquivalentTo(infAfter)) }) - It("should CFInfo and CFReserveArgs", Label("cuckoo", "cfinfo", "cfreserveargs"), func() { + It("should CFInfo and CFReserveWithArgs", Label("cuckoo", "cfinfo", "cfreserveargs"), func() { args := &redis.CFReserveOptions{ Capacity: 2048, BucketSize: 3, @@ -360,7 +360,7 @@ var _ = Describe("Probabilistic commands", Label("probabilistic"), func() { Expansion: 2, } - err := client.CFReserveArgs(ctx, "testcf1", args).Err() + err := client.CFReserveWithArgs(ctx, "testcf1", args).Err() Expect(err).NotTo(HaveOccurred()) result, err := client.CFInfo(ctx, "testcf1").Result() From e502cdc7501bbc9f27243feedabe875d0c9456af Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Wed, 20 Sep 2023 09:42:31 +0200 Subject: [PATCH 6/8] Adding Go 1.21.x for CI coverage (#2697) * Update build.yml Add support to go 1.21.x * Update doctests.yaml --------- Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/doctests.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4dacf2a13..231233f79 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [1.19.x, 1.20.x] + go-version: [1.19.x, 1.20.x, 1.21.x] services: redis: diff --git a/.github/workflows/doctests.yaml b/.github/workflows/doctests.yaml index dac223363..708dfcd3f 100644 --- a/.github/workflows/doctests.yaml +++ b/.github/workflows/doctests.yaml @@ -25,7 +25,7 @@ jobs: strategy: fail-fast: false matrix: - go-version: [ "1.18", "1.19", "1.20" ] + go-version: [ "1.18", "1.19", "1.20", "1.21" ] steps: - name: Set up ${{ matrix.go-version }} @@ -38,4 +38,4 @@ jobs: - name: Test doc examples working-directory: ./doctests - run: go test \ No newline at end of file + run: go test From 71dd81cded1241a47f5196d5e581c59cb6cb4e8a Mon Sep 17 00:00:00 2001 From: Chayim Date: Wed, 20 Sep 2023 10:42:45 +0300 Subject: [PATCH 7/8] CONTRIBUTING guideliens (#2718) --- CONTRIBUTING.md | 101 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++ 2 files changed, 105 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..90030b89f --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,101 @@ +# Contributing + +## Introduction + +We appreciate your interest in considering contributing to go-redis. +Community contributions mean a lot to us. + +## Contributions we need + +You may already know how you'd like to contribute, whether it's a fix for a bug you +encountered, or a new feature your team wants to use. + +If you don't know where to start, consider improving +documentation, bug triaging, and writing tutorials are all examples of +helpful contributions that mean less work for you. + +## Your First Contribution + +Unsure where to begin contributing? You can start by looking through +[help-wanted +issues](https://github.com/redis/go-redis/issues?q=is%3Aopen+is%3Aissue+label%3ahelp-wanted). + +Never contributed to open source before? Here are a couple of friendly +tutorials: + +- +- + +## Getting Started + +Here's how to get started with your code contribution: + +1. Create your own fork of go-redis +2. Do the changes in your fork +3. If you need a development environment, run `make test`. Note: this clones and builds the latest release of [redis](https://redis.io). You also need a redis-stack-server docker, in order to run the capabilities tests. This can be started by running: + ```docker run -p 6379:6379 -it redis/redis-stack-server:edge``` +4. While developing, make sure the tests pass by running `make tests` +5. If you like the change and think the project could use it, send a + pull request + +To see what else is part of the automation, run `invoke -l` + +## Testing + +Call `make test` to run all tests, including linters. + +Continuous Integration uses these same wrappers to run all of these +tests against multiple versions of python. Feel free to test your +changes against all the go versions supported, as declared by the +[build.yml](./.github/workflows/build.yml) file. + +### Troubleshooting + +If you get any errors when running `make test`, make sure +that you are using supported versions of Docker and go. + +## How to Report a Bug + +### Security Vulnerabilities + +**NOTE**: If you find a security vulnerability, do NOT open an issue. +Email [Redis Open Source ()](mailto:oss@redis.com) instead. + +In order to determine whether you are dealing with a security issue, ask +yourself these two questions: + +- Can I access something that's not mine, or something I shouldn't + have access to? +- Can I disable something for other people? + +If the answer to either of those two questions are *yes*, then you're +probably dealing with a security issue. Note that even if you answer +*no* to both questions, you may still be dealing with a security +issue, so if you're unsure, just email [us](mailto:oss@redis.com). + +### Everything Else + +When filing an issue, make sure to answer these five questions: + +1. What version of go-redis are you using? +2. What version of redis are you using? +3. What did you do? +4. What did you expect to see? +5. What did you see instead? + +## Suggest a feature or enhancement + +If you'd like to contribute a new feature, make sure you check our +issue list to see if someone has already proposed it. Work may already +be underway on the feature you want or we may have rejected a +feature like it already. + +If you don't see anything, open a new issue that describes the feature +you would like and how it should work. + +## Code review process + +The core team regularly looks at pull requests. We will provide +feedback as soon as possible. After receiving our feedback, please respond +within two weeks. After that time, we may close your PR if it isn't +showing any activity. diff --git a/README.md b/README.md index 3486e8e5a..1005868c0 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,10 @@ func ExampleClient() { rdb := redis.NewClient(opts) ``` +## Contributing + +Please see [out contributing guidelines](CONTRIBUTING.md) to help us improve this library! + ## Look and feel Some corner cases: From 1a7d2f4ad4e91b9fac784aa1b94254f838863e3b Mon Sep 17 00:00:00 2001 From: loveY <35476126+wzlove@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:49:46 +0800 Subject: [PATCH 8/8] upgrade bitfield cmd to `add multiple values` (#2648) Co-authored-by: wangzheng1 Co-authored-by: ofekshenawa <104765379+ofekshenawa@users.noreply.github.com> --- commands.go | 18 +++++++++++------- commands_test.go | 4 ++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/commands.go b/commands.go index 2b2abfb75..96d909911 100644 --- a/commands.go +++ b/commands.go @@ -238,7 +238,7 @@ type Cmdable interface { BitOpNot(ctx context.Context, destKey string, key string) *IntCmd BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd - BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd + BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd @@ -1369,12 +1369,16 @@ func (c cmdable) BitPosSpan(ctx context.Context, key string, bit int8, start, en return cmd } -func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd { - a := make([]interface{}, 0, 2+len(args)) - a = append(a, "bitfield") - a = append(a, key) - a = append(a, args...) - cmd := NewIntSliceCmd(ctx, a...) +// BitField accepts multiple values: +// - BitField("set", "i1", "offset1", "value1","cmd2", "type2", "offset2", "value2") +// - BitField([]string{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"}) +// - BitField([]interface{}{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"}) +func (c cmdable) BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd { + args := make([]interface{}, 2, 2+len(values)) + args[0] = "bitfield" + args[1] = key + args = appendArgs(args, values) + cmd := NewIntSliceCmd(ctx, args...) _ = c(ctx, cmd) return cmd } diff --git a/commands_test.go b/commands_test.go index b77447682..9b1c63e81 100644 --- a/commands_test.go +++ b/commands_test.go @@ -1253,6 +1253,10 @@ var _ = Describe("Commands", func() { nn, err := client.BitField(ctx, "mykey", "INCRBY", "i5", 100, 1, "GET", "u4", 0).Result() Expect(err).NotTo(HaveOccurred()) Expect(nn).To(Equal([]int64{1, 0})) + + nn, err = client.BitField(ctx, "mykey", "set", "i1", 1, 1, "GET", "u4", 0).Result() + Expect(err).NotTo(HaveOccurred()) + Expect(nn).To(Equal([]int64{0, 4})) }) It("should Decr", func() {