Skip to content

Commit

Permalink
Go: Implement GetBit, SetBit, BitCount and Wait commands (#2918)
Browse files Browse the repository at this point in the history
* Added bitmap commands,wait commands

Signed-off-by: Niharika Bhavaraju <[email protected]>
  • Loading branch information
niharikabhavaraju authored Jan 21, 2025
1 parent 490c3d4 commit 918162b
Show file tree
Hide file tree
Showing 5 changed files with 421 additions and 0 deletions.
148 changes: 148 additions & 0 deletions go/api/base_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type BaseClient interface {
ConnectionManagementCommands
HyperLogLogCommands
GenericBaseCommands
BitmapCommands
// Close terminates the client by closing all associated resources.
Close()
}
Expand Down Expand Up @@ -3162,3 +3163,150 @@ func (client *baseClient) XAck(key string, group string, ids []string) (int64, e
}
return handleIntResponse(result)
}

// Sets or clears the bit at offset in the string value stored at key.
// The offset is a zero-based index, with `0` being the first element of
// the list, `1` being the next element, and so on. The offset must be
// less than `2^32` and greater than or equal to `0` If a key is
// non-existent then the bit at offset is set to value and the preceding
// bits are set to `0`.
//
// Parameters:
//
// key - The key of the string.
// offset - The index of the bit to be set.
// value - The bit value to set at offset The value must be `0` or `1`.
//
// Return value:
//
// The bit value that was previously stored at offset.
//
// Example:
//
// result, err := client.SetBit("key", 1, 1)
// result: 1
//
// [valkey.io]: https://valkey.io/commands/setbit/
func (client *baseClient) SetBit(key string, offset int64, value int64) (int64, error) {
result, err := client.executeCommand(C.SetBit, []string{key, utils.IntToString(offset), utils.IntToString(value)})
if err != nil {
return defaultIntResponse, err
}
return handleIntResponse(result)
}

// Returns the bit value at offset in the string value stored at key.
//
// offset should be greater than or equal to zero.
//
// Parameters:
//
// key - The key of the string.
// offset - The index of the bit to return.
//
// Return value:
// The bit at offset of the string. Returns zero if the key is empty or if the positive
// offset exceeds the length of the string.
//
// Example:
//
// result, err := client.GetBit("key1", 1, 1)
// result: 1
//
// [valkey.io]: https://valkey.io/commands/getbit/
func (client *baseClient) GetBit(key string, offset int64) (int64, error) {
result, err := client.executeCommand(C.GetBit, []string{key, utils.IntToString(offset)})
if err != nil {
return defaultIntResponse, err
}
return handleIntResponse(result)
}

// Wait blocks the current client until all the previous write commands are successfully
// transferred and acknowledged by at least the specified number of replicas or if the timeout is reached,
// whichever is earlier
//
// Parameters:
//
// numberOfReplicas - The number of replicas to reach.
// timeout - The timeout value specified in milliseconds. A value of `0` will
// block indefinitely.
//
// Return value:
// The number of replicas reached by all the writes performed in the context of the current connection.
//
// Example:
//
// result, err := client.Wait(1, 1000)
// if err != nil {
// // handle error
// }
// fmt.Println(result.Value()) // Output: 1 // if cluster has 2 replicasets
//
// [valkey.io]: https://valkey.io/commands/wait/
func (client *baseClient) Wait(numberOfReplicas int64, timeout int64) (int64, error) {
result, err := client.executeCommand(C.Wait, []string{utils.IntToString(numberOfReplicas), utils.IntToString(timeout)})
if err != nil {
return defaultIntResponse, err
}
return handleIntResponse(result)
}

// Counts the number of set bits (population counting) in a string stored at key.
//
// Parameters:
//
// key - The key for the string to count the set bits of.
//
// Return value:
// The number of set bits in the string. Returns zero if the key is missing as it is
// treated as an empty string.
//
// Example:
//
// result, err := client.BitCount("mykey")
// result: 26
//
// [valkey.io]: https://valkey.io/commands/bitcount/
func (client *baseClient) BitCount(key string) (int64, error) {
result, err := client.executeCommand(C.BitCount, []string{key})
if err != nil {
return defaultIntResponse, err
}
return handleIntResponse(result)
}

// Counts the number of set bits (population counting) in a string stored at key. The
// offsets start and end are zero-based indexes, with `0` being the first element of the
// list, `1` being the next element and so on. These offsets can also be negative numbers
// indicating offsets starting at the end of the list, with `-1` being the last element
// of the list, `-2` being the penultimate, and so on.
//
// Parameters:
//
// key - The key for the string to count the set bits of.
// options - The offset options - see [options.BitOffsetOptions].
//
// Return value:
// The number of set bits in the string interval specified by start, end, and options.
// Returns zero if the key is missing as it is treated as an empty string.
//
// Example:
//
// opts := NewBitCountOptionsBuilder().SetStart(1).SetEnd(1).SetBitmapIndexType(options.BYTE)
// result, err := client.BitCount("mykey",options)
// result: 6
//
// [valkey.io]: https://valkey.io/commands/bitcount/
func (client *baseClient) BitCountWithOptions(key string, opts *options.BitCountOptions) (int64, error) {
optionArgs, err := opts.ToArgs()
if err != nil {
return defaultIntResponse, err
}
commandArgs := append([]string{key}, optionArgs...)
result, err := client.executeCommand(C.BitCount, commandArgs)
if err != nil {
return defaultIntResponse, err
}
return handleIntResponse(result)
}
20 changes: 20 additions & 0 deletions go/api/bitmap_commands.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0

package api

import "github.com/valkey-io/valkey-glide/go/glide/api/options"

// Supports commands and transactions for the "Bitmap" group of commands for standalone and cluster clients.
//
// See [valkey.io] for details.
//
// [valkey.io]: https://valkey.io/commands/#bitmap
type BitmapCommands interface {
SetBit(key string, offset int64, value int64) (int64, error)

GetBit(key string, offset int64) (int64, error)

BitCount(key string) (int64, error)

BitCountWithOptions(key string, options *options.BitCountOptions) (int64, error)
}
2 changes: 2 additions & 0 deletions go/api/generic_base_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,4 +703,6 @@ type GenericBaseCommands interface {
//
// [valkey.io]: https://valkey.io/commands/sort/
SortReadOnlyWithOptions(key string, sortOptions *options.SortOptions) ([]Result[string], error)

Wait(numberOfReplicas int64, timeout int64) (int64, error)
}
63 changes: 63 additions & 0 deletions go/api/options/bitcount_options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0

package options

import (
"github.com/valkey-io/valkey-glide/go/glide/utils"
)

type BitmapIndexType string

const (
BYTE BitmapIndexType = "BYTE"
BIT BitmapIndexType = "BIT"
)

// Optional arguments to `BitCount` in [BitMapCommands]
type BitCountOptions struct {
start *int64
end *int64
bitMapIndexType BitmapIndexType
}

func NewBitCountOptionsBuilder() *BitCountOptions {
return &BitCountOptions{}
}

// SetStart defines start byte to calculate bitcount in bitcount command.
func (options *BitCountOptions) SetStart(start int64) *BitCountOptions {
options.start = &start
return options
}

// SetEnd defines start byte to calculate bitcount in bitcount command.
func (options *BitCountOptions) SetEnd(end int64) *BitCountOptions {
options.end = &end
return options
}

// SetBitmapIndexType to specify start and end are in BYTE or BIT
func (options *BitCountOptions) SetBitmapIndexType(bitMapIndexType BitmapIndexType) *BitCountOptions {
options.bitMapIndexType = bitMapIndexType
return options
}

// ToArgs converts the options to a list of arguments.
func (opts *BitCountOptions) ToArgs() ([]string, error) {
args := []string{}
var err error

if opts.start != nil {
args = append(args, utils.IntToString(*opts.start))
if opts.end != nil {
args = append(args, utils.IntToString(*opts.end))
if opts.bitMapIndexType != "" {
if opts.bitMapIndexType == BIT || opts.bitMapIndexType == BYTE {
args = append(args, string(opts.bitMapIndexType))
}
}
}
}

return args, err
}
Loading

0 comments on commit 918162b

Please sign in to comment.