Skip to content

Commit ba08ade

Browse files
Merge pull request valkey-io#3407 from niharikabhavaraju/niharika-bitposcmd
GO: Implement Bitpos command
2 parents b095c94 + 58f0151 commit ba08ade

File tree

6 files changed

+271
-0
lines changed

6 files changed

+271
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* Go: Fix unsafe precondition violation for the slice::from_raw_parts ([#3350](https://github.com/valkey-io/valkey-glide/issues/3350))
2020
* Go: Add `GeoAdd` and the Geospatial interface ([#3366](https://github.com/valkey-io/valkey-glide/pull/3366))
2121
* Go: Add `LOLWUT` ([#3355](https://github.com/valkey-io/valkey-glide/pull/3355))
22+
* Go: Add `BITPOS` ([#3407](https://github.com/valkey-io/valkey-glide/pull/3407))
2223
* Go: Add `FLUSHALL` ([#3117](https://github.com/valkey-io/valkey-glide/pull/3117))
2324
* Go: Add `FLUSHDB` ([#3117](https://github.com/valkey-io/valkey-glide/pull/3117))
2425
* Go: Add password update api ([#3346](https://github.com/valkey-io/valkey-glide/pull/3346))

go/api/base_client.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5713,6 +5713,54 @@ func (client *baseClient) XClaimJustIdWithOptions(
57135713
return handleStringArrayResponse(result)
57145714
}
57155715

5716+
// Returns the position of the first bit matching the given bit value.
5717+
//
5718+
// Parameters:
5719+
//
5720+
// key - The key of the string.
5721+
// bit - The bit value to match. The value must be 0 or 1.
5722+
//
5723+
// Return value:
5724+
//
5725+
// The position of the first occurrence matching bit in the binary value of
5726+
// the string held at key. If bit is not found, a -1 is returned.
5727+
//
5728+
// [valkey.io]: https://valkey.io/commands/bitpos/
5729+
func (client *baseClient) BitPos(key string, bit int64) (int64, error) {
5730+
result, err := client.executeCommand(C.BitPos, []string{key, utils.IntToString(bit)})
5731+
if err != nil {
5732+
return defaultIntResponse, err
5733+
}
5734+
return handleIntResponse(result)
5735+
}
5736+
5737+
// Returns the position of the first bit matching the given bit value.
5738+
//
5739+
// Parameters:
5740+
//
5741+
// key - The key of the string.
5742+
// bit - The bit value to match. The value must be 0 or 1.
5743+
// bitposOptions - The [BitPosOptions] type.
5744+
//
5745+
// Return value:
5746+
//
5747+
// The position of the first occurrence matching bit in the binary value of
5748+
// the string held at key. If bit is not found, a -1 is returned.
5749+
//
5750+
// [valkey.io]: https://valkey.io/commands/bitpos/
5751+
func (client *baseClient) BitPosWithOptions(key string, bit int64, bitposOptions options.BitPosOptions) (int64, error) {
5752+
optionArgs, err := bitposOptions.ToArgs()
5753+
if err != nil {
5754+
return defaultIntResponse, err
5755+
}
5756+
commandArgs := append([]string{key, utils.IntToString(bit)}, optionArgs...)
5757+
result, err := client.executeCommand(C.BitPos, commandArgs)
5758+
if err != nil {
5759+
return defaultIntResponse, err
5760+
}
5761+
return handleIntResponse(result)
5762+
}
5763+
57165764
// Copies the value stored at the source to the destination key if the
57175765
// destination key does not yet exist.
57185766
//

go/api/bitmap_commands.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ type BitmapCommands interface {
1818

1919
BitCountWithOptions(key string, options options.BitCountOptions) (int64, error)
2020

21+
BitPos(key string, bit int64) (int64, error)
22+
23+
BitPosWithOptions(key string, bit int64, options options.BitPosOptions) (int64, error)
24+
2125
BitField(key string, subCommands []options.BitFieldSubCommands) ([]Result[int64], error)
2226

2327
BitFieldRO(key string, commands []options.BitFieldROCommands) ([]Result[int64], error)

go/api/bitmap_commands_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,3 +300,68 @@ func ExampleGlideClusterClient_BitOp() {
300300
// BitOp XOR Result: 6
301301
// BitOp NOT Result: 6
302302
}
303+
304+
func ExampleGlideClient_BitPos() {
305+
var client *GlideClient = getExampleGlideClient() // example helper function
306+
307+
client.SetBit("my_key", 7, 1)
308+
309+
result, err := client.BitPos("my_key", 1)
310+
if err != nil {
311+
fmt.Println("Glide example failed with an error: ", err)
312+
}
313+
fmt.Println(result)
314+
315+
// Output: 7
316+
}
317+
318+
func ExampleGlideClusterClient_BitPos() {
319+
var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function
320+
321+
client.SetBit("my_key", 7, 1)
322+
323+
result, err := client.BitPos("my_key", 1)
324+
if err != nil {
325+
fmt.Println("Glide example failed with an error: ", err)
326+
}
327+
fmt.Println(result)
328+
329+
// Output: 7
330+
}
331+
332+
func ExampleGlideClient_BitPosWithOptions() {
333+
var client *GlideClient = getExampleGlideClient() // example helper function
334+
335+
client.Set("my_key", "\x00\x01\x00")
336+
337+
options := options.NewBitPosOptions().
338+
SetStart(0).
339+
SetEnd(1)
340+
341+
result, err := client.BitPosWithOptions("my_key", 1, *options)
342+
if err != nil {
343+
fmt.Println("Glide example failed with an error: ", err)
344+
}
345+
fmt.Println(result)
346+
347+
// Output: 15
348+
}
349+
350+
func ExampleGlideClusterClient_BitPosWithOptions() {
351+
var client *GlideClusterClient = getExampleGlideClusterClient() // example helper function
352+
353+
client.Set("my_key", "\x00\x10\x00")
354+
355+
options := options.NewBitPosOptions().
356+
SetStart(10).
357+
SetEnd(14).
358+
SetBitmapIndexType(options.BIT)
359+
360+
result, err := client.BitPosWithOptions("my_key", 1, *options)
361+
if err != nil {
362+
fmt.Println("Glide example failed with an error: ", err)
363+
}
364+
fmt.Println(result)
365+
366+
// Output: 11
367+
}

go/api/options/bitpos_options.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
2+
3+
package options
4+
5+
import (
6+
"github.com/valkey-io/valkey-glide/go/utils"
7+
)
8+
9+
// Optional arguments to `BitPos` in [BitMapCommands]
10+
type BitPosOptions struct {
11+
start *int64
12+
end *int64
13+
bitMapIndexType BitmapIndexType
14+
}
15+
16+
func NewBitPosOptions() *BitPosOptions {
17+
return &BitPosOptions{}
18+
}
19+
20+
// SetStart defines start byte to calculate bitpos in bitpos command.
21+
func (options *BitPosOptions) SetStart(start int64) *BitPosOptions {
22+
options.start = &start
23+
return options
24+
}
25+
26+
// SetEnd defines end byte to calculate bitpos in bitpos command.
27+
func (options *BitPosOptions) SetEnd(end int64) *BitPosOptions {
28+
options.end = &end
29+
return options
30+
}
31+
32+
// SetBitmapIndexType to specify start and end are in BYTE or BIT
33+
func (options *BitPosOptions) SetBitmapIndexType(bitMapIndexType BitmapIndexType) *BitPosOptions {
34+
options.bitMapIndexType = bitMapIndexType
35+
return options
36+
}
37+
38+
// ToArgs converts the options to a list of arguments.
39+
func (opts *BitPosOptions) ToArgs() ([]string, error) {
40+
args := []string{}
41+
42+
if opts.start == nil {
43+
return args, nil
44+
}
45+
46+
args = append(args, utils.IntToString(*opts.start))
47+
48+
if opts.end == nil {
49+
return args, nil
50+
}
51+
52+
args = append(args, utils.IntToString(*opts.end))
53+
54+
if opts.bitMapIndexType == BIT || opts.bitMapIndexType == BYTE {
55+
args = append(args, string(opts.bitMapIndexType))
56+
}
57+
58+
return args, nil
59+
}

go/integTest/shared_commands_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8352,6 +8352,100 @@ func (suite *GlideTestSuite) TestBitField_MultipleOperations() {
83528352
})
83538353
}
83548354

8355+
func (suite *GlideTestSuite) TestBitPos_ExistingKey() {
8356+
suite.runWithDefaultClients(func(client api.BaseClient) {
8357+
key := uuid.New().String()
8358+
client.Set(key, "\x10")
8359+
result, err := client.BitPos(key, 1)
8360+
assert.NoError(suite.T(), err)
8361+
assert.Equal(suite.T(), int64(3), result)
8362+
})
8363+
}
8364+
8365+
func (suite *GlideTestSuite) TestBitPos_NonExistingKey() {
8366+
suite.runWithDefaultClients(func(client api.BaseClient) {
8367+
key := uuid.New().String()
8368+
result, err := client.BitPos(key, 0)
8369+
assert.NoError(suite.T(), err)
8370+
assert.Equal(suite.T(), int64(0), result)
8371+
})
8372+
}
8373+
8374+
func (suite *GlideTestSuite) TestBitPosWithOptions_StartEnd() {
8375+
suite.runWithDefaultClients(func(client api.BaseClient) {
8376+
key := uuid.New().String()
8377+
client.Set(key, "\x00\x01\x80")
8378+
8379+
opts := options.NewBitPosOptions().
8380+
SetStart(0).
8381+
SetEnd(1)
8382+
8383+
result, err := client.BitPosWithOptions(key, 1, *opts)
8384+
assert.NoError(suite.T(), err)
8385+
assert.Equal(suite.T(), int64(15), result)
8386+
})
8387+
}
8388+
8389+
func (suite *GlideTestSuite) TestBitPosWithOptions_BitmapIndexType() {
8390+
suite.SkipIfServerVersionLowerThanBy("7.0.0")
8391+
suite.runWithDefaultClients(func(client api.BaseClient) {
8392+
key := uuid.New().String()
8393+
client.Set(key, "\x00\x02\x00")
8394+
8395+
opts := options.NewBitPosOptions().
8396+
SetStart(1).
8397+
SetEnd(2).
8398+
SetBitmapIndexType(options.BYTE)
8399+
8400+
result, err := client.BitPosWithOptions(key, 1, *opts)
8401+
assert.NoError(suite.T(), err)
8402+
assert.Equal(suite.T(), int64(14), result)
8403+
})
8404+
}
8405+
8406+
func (suite *GlideTestSuite) TestBitPosWithOptions_BitIndexType() {
8407+
suite.SkipIfServerVersionLowerThanBy("7.0.0")
8408+
suite.runWithDefaultClients(func(client api.BaseClient) {
8409+
key := uuid.New().String()
8410+
client.Set(key, "\x00\x10\x00")
8411+
8412+
opts := options.NewBitPosOptions().
8413+
SetStart(10).
8414+
SetEnd(14).
8415+
SetBitmapIndexType(options.BIT)
8416+
8417+
result, err := client.BitPosWithOptions(key, 1, *opts)
8418+
assert.NoError(suite.T(), err)
8419+
assert.Equal(suite.T(), int64(11), result)
8420+
})
8421+
}
8422+
8423+
func (suite *GlideTestSuite) TestBitPos_FindBitZero() {
8424+
suite.runWithDefaultClients(func(client api.BaseClient) {
8425+
key := uuid.New().String()
8426+
client.Set(key, "\xFF\xF7")
8427+
8428+
result, err := client.BitPos(key, 0)
8429+
assert.NoError(suite.T(), err)
8430+
assert.Equal(suite.T(), int64(12), result)
8431+
})
8432+
}
8433+
8434+
func (suite *GlideTestSuite) TestBitPosWithOptions_NegativeEnd() {
8435+
suite.runWithDefaultClients(func(client api.BaseClient) {
8436+
key := uuid.New().String()
8437+
client.Set(key, "\x00\x01\x80")
8438+
8439+
opts := options.NewBitPosOptions().
8440+
SetStart(0).
8441+
SetEnd(-2)
8442+
8443+
result, err := client.BitPosWithOptions(key, 1, *opts)
8444+
assert.NoError(suite.T(), err)
8445+
assert.Equal(suite.T(), int64(15), result)
8446+
})
8447+
}
8448+
83558449
func (suite *GlideTestSuite) TestBitField_Failures() {
83568450
suite.runWithDefaultClients(func(client api.BaseClient) {
83578451
key := uuid.New().String()

0 commit comments

Comments
 (0)