You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

194 line
6.8 KiB

  1. package redis
  2. import (
  3. "context"
  4. "errors"
  5. )
  6. type BitMapCmdable interface {
  7. GetBit(ctx context.Context, key string, offset int64) *IntCmd
  8. SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
  9. BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
  10. BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
  11. BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
  12. BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
  13. BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd
  14. BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd
  15. BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd
  16. BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd
  17. BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
  18. BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
  19. BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd
  20. BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd
  21. BitFieldRO(ctx context.Context, key string, values ...interface{}) *IntSliceCmd
  22. }
  23. func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
  24. cmd := NewIntCmd(ctx, "getbit", key, offset)
  25. _ = c(ctx, cmd)
  26. return cmd
  27. }
  28. func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
  29. cmd := NewIntCmd(
  30. ctx,
  31. "setbit",
  32. key,
  33. offset,
  34. value,
  35. )
  36. _ = c(ctx, cmd)
  37. return cmd
  38. }
  39. type BitCount struct {
  40. Start, End int64
  41. Unit string // BYTE(default) | BIT
  42. }
  43. const BitCountIndexByte string = "BYTE"
  44. const BitCountIndexBit string = "BIT"
  45. func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
  46. args := make([]any, 2, 5)
  47. args[0] = "bitcount"
  48. args[1] = key
  49. if bitCount != nil {
  50. args = append(args, bitCount.Start, bitCount.End)
  51. if bitCount.Unit != "" {
  52. if bitCount.Unit != BitCountIndexByte && bitCount.Unit != BitCountIndexBit {
  53. cmd := NewIntCmd(ctx)
  54. cmd.SetErr(errors.New("redis: invalid bitcount index"))
  55. return cmd
  56. }
  57. args = append(args, bitCount.Unit)
  58. }
  59. }
  60. cmd := NewIntCmd(ctx, args...)
  61. _ = c(ctx, cmd)
  62. return cmd
  63. }
  64. func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
  65. args := make([]interface{}, 3+len(keys))
  66. args[0] = "bitop"
  67. args[1] = op
  68. args[2] = destKey
  69. for i, key := range keys {
  70. args[3+i] = key
  71. }
  72. cmd := NewIntCmd(ctx, args...)
  73. _ = c(ctx, cmd)
  74. return cmd
  75. }
  76. // BitOpAnd creates a new bitmap in which users are members of all given bitmaps
  77. func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
  78. return c.bitOp(ctx, "and", destKey, keys...)
  79. }
  80. // BitOpOr creates a new bitmap in which users are member of at least one given bitmap
  81. func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
  82. return c.bitOp(ctx, "or", destKey, keys...)
  83. }
  84. // BitOpXor creates a new bitmap in which users are the result of XORing all given bitmaps
  85. func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
  86. return c.bitOp(ctx, "xor", destKey, keys...)
  87. }
  88. // BitOpNot creates a new bitmap in which users are not members of a given bitmap
  89. func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
  90. return c.bitOp(ctx, "not", destKey, key)
  91. }
  92. // BitOpDiff creates a new bitmap in which users are members of bitmap X but not of any of bitmaps Y1, Y2, …
  93. // Introduced with Redis 8.2
  94. func (c cmdable) BitOpDiff(ctx context.Context, destKey string, keys ...string) *IntCmd {
  95. return c.bitOp(ctx, "diff", destKey, keys...)
  96. }
  97. // BitOpDiff1 creates a new bitmap in which users are members of one or more of bitmaps Y1, Y2, … but not members of bitmap X
  98. // Introduced with Redis 8.2
  99. func (c cmdable) BitOpDiff1(ctx context.Context, destKey string, keys ...string) *IntCmd {
  100. return c.bitOp(ctx, "diff1", destKey, keys...)
  101. }
  102. // BitOpAndOr creates a new bitmap in which users are members of bitmap X and also members of one or more of bitmaps Y1, Y2, …
  103. // Introduced with Redis 8.2
  104. func (c cmdable) BitOpAndOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
  105. return c.bitOp(ctx, "andor", destKey, keys...)
  106. }
  107. // BitOpOne creates a new bitmap in which users are members of exactly one of the given bitmaps
  108. // Introduced with Redis 8.2
  109. func (c cmdable) BitOpOne(ctx context.Context, destKey string, keys ...string) *IntCmd {
  110. return c.bitOp(ctx, "one", destKey, keys...)
  111. }
  112. // BitPos is an API before Redis version 7.0, cmd: bitpos key bit start end
  113. // if you need the `byte | bit` parameter, please use `BitPosSpan`.
  114. func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
  115. args := make([]interface{}, 3+len(pos))
  116. args[0] = "bitpos"
  117. args[1] = key
  118. args[2] = bit
  119. switch len(pos) {
  120. case 0:
  121. case 1:
  122. args[3] = pos[0]
  123. case 2:
  124. args[3] = pos[0]
  125. args[4] = pos[1]
  126. default:
  127. panic("too many arguments")
  128. }
  129. cmd := NewIntCmd(ctx, args...)
  130. _ = c(ctx, cmd)
  131. return cmd
  132. }
  133. // BitPosSpan supports the `byte | bit` parameters in redis version 7.0,
  134. // the bitpos command defaults to using byte type for the `start-end` range,
  135. // which means it counts in bytes from start to end. you can set the value
  136. // of "span" to determine the type of `start-end`.
  137. // span = "bit", cmd: bitpos key bit start end bit
  138. // span = "byte", cmd: bitpos key bit start end byte
  139. func (c cmdable) BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd {
  140. cmd := NewIntCmd(ctx, "bitpos", key, bit, start, end, span)
  141. _ = c(ctx, cmd)
  142. return cmd
  143. }
  144. // BitField accepts multiple values:
  145. // - BitField("set", "i1", "offset1", "value1","cmd2", "type2", "offset2", "value2")
  146. // - BitField([]string{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"})
  147. // - BitField([]interface{}{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"})
  148. func (c cmdable) BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd {
  149. args := make([]interface{}, 2, 2+len(values))
  150. args[0] = "bitfield"
  151. args[1] = key
  152. args = appendArgs(args, values)
  153. cmd := NewIntSliceCmd(ctx, args...)
  154. _ = c(ctx, cmd)
  155. return cmd
  156. }
  157. // BitFieldRO - Read-only variant of the BITFIELD command.
  158. // It is like the original BITFIELD but only accepts GET subcommand and can safely be used in read-only replicas.
  159. // - BitFieldRO(ctx, key, "<Encoding0>", "<Offset0>", "<Encoding1>","<Offset1>")
  160. func (c cmdable) BitFieldRO(ctx context.Context, key string, values ...interface{}) *IntSliceCmd {
  161. args := make([]interface{}, 2, 2+len(values))
  162. args[0] = "BITFIELD_RO"
  163. args[1] = key
  164. if len(values)%2 != 0 {
  165. panic("BitFieldRO: invalid number of arguments, must be even")
  166. }
  167. for i := 0; i < len(values); i += 2 {
  168. args = append(args, "GET", values[i], values[i+1])
  169. }
  170. cmd := NewIntSliceCmd(ctx, args...)
  171. _ = c(ctx, cmd)
  172. return cmd
  173. }