Skip to content

feat(bitop): add support for the new bitop operations #3409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/actions/run-tests/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ runs:

# Mapping of redis version to redis testing containers
declare -A redis_version_mapping=(
["8.2.x"]="8.2-M01-pre"
["8.0.x"]="8.0.2"
["7.4.x"]="rs-7.4.0-v5"
["7.2.x"]="rs-7.2.0-v17"
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
fail-fast: false
matrix:
redis-version:
- "8.2.x" # Redis CE 8.2
- "8.0.x" # Redis CE 8.0
- "7.4.x" # Redis stack 7.4
go-version:
Expand All @@ -43,6 +44,7 @@ jobs:

# Mapping of redis version to redis testing containers
declare -A redis_version_mapping=(
["8.2.x"]="8.2-M01-pre"
["8.0.x"]="8.0.2"
["7.4.x"]="rs-7.4.0-v5"
)
Expand Down Expand Up @@ -72,6 +74,7 @@ jobs:
fail-fast: false
matrix:
redis-version:
- "8.2.x" # Redis CE 8.2
- "8.0.x" # Redis CE 8.0
- "7.4.x" # Redis stack 7.4
- "7.2.x" # Redis stack 7.2
Expand Down
20 changes: 20 additions & 0 deletions bitmap_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ type BitMapCmdable interface {
BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd
BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd
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
Expand Down Expand Up @@ -90,6 +94,22 @@ func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *
return c.bitOp(ctx, "xor", destKey, keys...)
}

func (c cmdable) BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "diff", destKey, keys...)
}

func (c cmdable) BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "diff1", destKey, keys...)
}

func (c cmdable) BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "andor", destKey, keys...)
}

func (c cmdable) BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd {
return c.bitOp(ctx, "one", destKey, keys...)
}

func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
return c.bitOp(ctx, "not", destKey, key)
}
Expand Down
9 changes: 9 additions & 0 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5138,6 +5138,9 @@ type ClientInfo struct {
OutputListLength int // oll, output list length (replies are queued in this list when the buffer is full)
OutputMemory int // omem, output buffer memory usage
TotalMemory int // tot-mem, total memory consumed by this client in its various buffers
TotalNetIn int // tot-net-in, total network input
TotalNetOut int // tot-net-out, total network output
TotalCmds int // tot-cmds, total number of commands processed
IoThread int // io-thread id
Events string // file descriptor events (see below)
LastCmd string // cmd, last command played
Expand Down Expand Up @@ -5303,6 +5306,12 @@ func parseClientInfo(txt string) (info *ClientInfo, err error) {
info.OutputMemory, err = strconv.Atoi(val)
case "tot-mem":
info.TotalMemory, err = strconv.Atoi(val)
case "tot-net-in":
info.TotalNetIn, err = strconv.Atoi(val)
case "tot-net-out":
info.TotalNetOut, err = strconv.Atoi(val)
case "tot-cmds":
info.TotalCmds, err = strconv.Atoi(val)
case "events":
info.Events = val
case "cmd":
Expand Down
76 changes: 76 additions & 0 deletions commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1469,6 +1469,82 @@ var _ = Describe("Commands", func() {
Expect(get.Val()).To(Equal("\xf0"))
})

It("should BitOpDiff", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP DIFF is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpDiff := client.BitOpDiff(ctx, "dest", "key1", "key2")
Expect(bitOpDiff.Err()).NotTo(HaveOccurred())
Expect(bitOpDiff.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\xf0"))
})

It("should BitOpDiff1", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP DIFF is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpDiff1 := client.BitOpDiff1(ctx, "dest", "key1", "key2")
Expect(bitOpDiff1.Err()).NotTo(HaveOccurred())
Expect(bitOpDiff1.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\x00"))
})

It("should BitOpAndOr", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP ANDOR is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpAndOr := client.BitOpAndOr(ctx, "dest", "key1", "key2")
Expect(bitOpAndOr.Err()).NotTo(HaveOccurred())
Expect(bitOpAndOr.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\x0f"))
})

It("should BitOpOne", Label("NonRedisEnterprise"), func() {
SkipBeforeRedisVersion(8.2, "BITOP ONE is available since Redis 8.2")
set := client.Set(ctx, "key1", "\xff", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

set = client.Set(ctx, "key2", "\x0f", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expect(set.Val()).To(Equal("OK"))

bitOpOne := client.BitOpOne(ctx, "dest", "key1", "key2")
Expect(bitOpOne.Err()).NotTo(HaveOccurred())
Expect(bitOpOne.Val()).To(Equal(int64(1)))

get := client.Get(ctx, "dest")
Expect(get.Err()).NotTo(HaveOccurred())
Expect(get.Val()).To(Equal("\xf0"))
})

It("should BitOpNot", Label("NonRedisEnterprise"), func() {
set := client.Set(ctx, "key1", "\x00", 0)
Expect(set.Err()).NotTo(HaveOccurred())
Expand Down
Loading