Skip to content
158 changes: 156 additions & 2 deletions set_commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"github.com/redis/go-redis/v9/internal/hashtag"
)

// SetCmdable is an interface for Redis set commands.
// Sets are unordered collections of unique strings.
type SetCmdable interface {
SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
SCard(ctx context.Context, key string) *IntCmd
Expand All @@ -29,8 +31,15 @@ type SetCmdable interface {
SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
}

//------------------------------------------------------------------------------

// SAdd Redis `SADD key member [member ...]` command.
// Adds the specified members to the set stored at key.
// Specified members that are already members of this set are ignored.
// If key does not exist, a new set is created before adding the specified members.
//
// Returns the number of elements that were added to the set, not including all
// the elements already present in the set.
//
// [SADD](https://redis.io/docs/latest/commands/sadd/)
func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
args := make([]interface{}, 2, 2+len(members))
args[0] = "sadd"
Expand All @@ -41,12 +50,25 @@ func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *
return cmd
}

// SCard Redis `SCARD key` command.
// Returns the set cardinality (number of elements) of the set stored at key.
// Returns 0 if key does not exist.
//
// [SCARD](https://redis.io/docs/latest/commands/scard/)
func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
cmd := NewIntCmd(ctx, "scard", key)
_ = c(ctx, cmd)
return cmd
}

// SDiff Redis `SDIFF key [key ...]` command.
// Returns the members of the set resulting from the difference between the first set
// and all the successive sets.
// Keys that do not exist are considered to be empty sets.
//
// Returns a slice of members of the resulting set.
//
// [SDIFF](https://redis.io/docs/latest/commands/sdiff/)
func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
args := make([]interface{}, 1+len(keys))
args[0] = "sdiff"
Expand All @@ -58,6 +80,14 @@ func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
return cmd
}

// SDiffStore Redis `SDIFFSTORE destination key [key ...]` command.
// Stores the members of the set resulting from the difference between the first set
// and all the successive sets into destination.
// If destination already exists, it is overwritten.
//
// Returns the number of elements in the resulting set.
//
// [SDIFFSTORE](https://redis.io/docs/latest/commands/sdiffstore/)
func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
args := make([]interface{}, 2+len(keys))
args[0] = "sdiffstore"
Expand All @@ -70,6 +100,14 @@ func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...str
return cmd
}

// SInter Redis `SINTER key [key ...]` command.
// Returns the members of the set resulting from the intersection of all the given sets.
// Keys that do not exist are considered to be empty sets.
// With one of the keys being an empty set, the resulting set is also empty.
//
// Returns a slice of members of the resulting set.
//
// [SINTER](https://redis.io/docs/latest/commands/sinter/)
func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
args := make([]interface{}, 1+len(keys))
args[0] = "sinter"
Expand All @@ -81,6 +119,17 @@ func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
return cmd
}

// SInterCard Redis `SINTERCARD numkeys key [key ...] [LIMIT limit]` command.
// Returns the cardinality of the set resulting from the intersection of all the given sets.
// Keys that do not exist are considered to be empty sets.
// With one of the keys being an empty set, the resulting set is also empty.
//
// The limit parameter sets an upper bound on the number of results returned.
// If limit is 0, no limit is applied.
//
// Returns the number of elements in the resulting set.
//
// [SINTERCARD](https://redis.io/docs/latest/commands/sintercard/)
func (c cmdable) SInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd {
numKeys := len(keys)
args := make([]interface{}, 4+numKeys)
Expand All @@ -96,6 +145,14 @@ func (c cmdable) SInterCard(ctx context.Context, limit int64, keys ...string) *I
return cmd
}

// SInterStore Redis `SINTERSTORE destination key [key ...]` command.
// Stores the members of the set resulting from the intersection of all the given sets
// into destination.
// If destination already exists, it is overwritten.
//
// Returns the number of elements in the resulting set.
//
// [SINTERSTORE](https://redis.io/docs/latest/commands/sinterstore/)
func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
args := make([]interface{}, 2+len(keys))
args[0] = "sinterstore"
Expand All @@ -108,13 +165,26 @@ func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...st
return cmd
}

// SIsMember Redis `SISMEMBER key member` command.
// Returns if member is a member of the set stored at key.
// Returns true if the element is a member of the set, false if it is not a member
// or if key does not exist.
//
// [SISMEMBER](https://redis.io/docs/latest/commands/sismember/)
func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
cmd := NewBoolCmd(ctx, "sismember", key, member)
_ = c(ctx, cmd)
return cmd
}

// SMIsMember Redis `SMISMEMBER key member [member ...]` command.
// Returns whether each member is a member of the set stored at key.
// For each member, returns true if the element is a member of the set, false if it is not
// a member or if key does not exist.
//
// Returns a slice of booleans, one for each member, indicating membership.
//
// [SMISMEMBER](https://redis.io/docs/latest/commands/smismember/)
func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd {
args := make([]interface{}, 2, 2+len(members))
args[0] = "smismember"
Expand All @@ -126,53 +196,109 @@ func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interfac
}

// SMembers Redis `SMEMBERS key` command output as a slice.
// Returns all the members of the set value stored at key.
// Returns an empty slice if key does not exist.
//
// Returns a slice of all members of the set.
//
// [SMEMBERS](https://redis.io/docs/latest/commands/smembers/)
func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
cmd := NewStringSliceCmd(ctx, "smembers", key)
_ = c(ctx, cmd)
return cmd
}

// SMembersMap Redis `SMEMBERS key` command output as a map.
// Returns all the members of the set value stored at key as a map.
// Returns an empty map if key does not exist.
//
// Returns a map where keys are the set members and values are empty structs.
//
// [SMEMBERS](https://redis.io/docs/latest/commands/smembers/)
func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
cmd := NewStringStructMapCmd(ctx, "smembers", key)
_ = c(ctx, cmd)
return cmd
}

// SMove Redis `SMOVE source destination member` command.
// Moves member from the set at source to the set at destination.
// This operation is atomic. In every given moment the element will appear to be a member
// of source or destination for other clients.
//
// Returns true if the element is moved, false if the element is not a member of source
// and no operation was performed.
//
// [SMOVE](https://redis.io/docs/latest/commands/smove/)
func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
cmd := NewBoolCmd(ctx, "smove", source, destination, member)
_ = c(ctx, cmd)
return cmd
}

// SPop Redis `SPOP key` command.
// Removes and returns one or more random members from the set value stored at key.
// This version returns a single random member.
//
// Returns the removed member, or nil if key does not exist.
//
// [SPOP](https://redis.io/docs/latest/commands/spop/)
func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
cmd := NewStringCmd(ctx, "spop", key)
_ = c(ctx, cmd)
return cmd
}

// SPopN Redis `SPOP key count` command.
// Removes and returns one or more random members from the set value stored at key.
// This version returns up to count random members.
//
// Returns a slice of removed members. If key does not exist, returns an empty slice.
//
// [SPOP](https://redis.io/docs/latest/commands/spop/)
func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
cmd := NewStringSliceCmd(ctx, "spop", key, count)
_ = c(ctx, cmd)
return cmd
}

// SRandMember Redis `SRANDMEMBER key` command.
// Returns a random member from the set value stored at key.
// This version returns a single random member without removing it.
//
// Returns the random member, or nil if key does not exist or the set is empty.
//
// [SRANDMEMBER](https://redis.io/docs/latest/commands/srandmember/)
func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
cmd := NewStringCmd(ctx, "srandmember", key)
_ = c(ctx, cmd)
return cmd
}

// SRandMemberN Redis `SRANDMEMBER key count` command.
// Returns an array of random members from the set value stored at key.
// This version returns up to count random members without removing them.
// When called with a positive count, returns distinct elements.
// When called with a negative count, allows for repeated elements.
//
// Returns a slice of random members. If key does not exist, returns an empty slice.
//
// [SRANDMEMBER](https://redis.io/docs/latest/commands/srandmember/)
func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
_ = c(ctx, cmd)
return cmd
}

// SRem Redis `SREM key member [member ...]` command.
// Removes the specified members from the set stored at key.
// Specified members that are not a member of this set are ignored.
// If key does not exist, it is treated as an empty set and this command returns 0.
//
// Returns the number of members that were removed from the set, not including
// non-existing members.
//
// [SREM](https://redis.io/docs/latest/commands/srem/)
func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
args := make([]interface{}, 2, 2+len(members))
args[0] = "srem"
Expand All @@ -183,6 +309,13 @@ func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *
return cmd
}

// SUnion Redis `SUNION key [key ...]` command.
// Returns the members of the set resulting from the union of all the given sets.
// Keys that do not exist are considered to be empty sets.
//
// Returns a slice of members of the resulting set.
//
// [SUNION](https://redis.io/docs/latest/commands/sunion/)
func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
args := make([]interface{}, 1+len(keys))
args[0] = "sunion"
Expand All @@ -194,6 +327,14 @@ func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
return cmd
}

// SUnionStore Redis `SUNIONSTORE destination key [key ...]` command.
// Stores the members of the set resulting from the union of all the given sets
// into destination.
// If destination already exists, it is overwritten.
//
// Returns the number of elements in the resulting set.
//
// [SUNIONSTORE](https://redis.io/docs/latest/commands/sunionstore/)
func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
args := make([]interface{}, 2+len(keys))
args[0] = "sunionstore"
Expand All @@ -206,6 +347,19 @@ func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...st
return cmd
}

// SScan Redis `SSCAN key cursor [MATCH pattern] [COUNT count]` command.
// Incrementally iterates the set elements stored at key.
// This is a cursor-based iterator that allows scanning large sets efficiently.
//
// Parameters:
// - cursor: The cursor value for the iteration (use 0 to start a new scan)
// - match: Optional pattern to match elements (empty string means no pattern)
// - count: Optional hint about how many elements to return per iteration
//
// Returns a ScanCmd that can be used to iterate through all members of the set.
// Use the returned cursor from each iteration to continue scanning.
//
// [SSCAN](https://redis.io/docs/latest/commands/sscan/)
func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
args := []interface{}{"sscan", key, cursor}
if match != "" {
Expand Down
Loading