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.

304 lines
9.5 KiB

  1. package redis
  2. import (
  3. "context"
  4. "time"
  5. )
  6. type StringCmdable interface {
  7. Append(ctx context.Context, key, value string) *IntCmd
  8. Decr(ctx context.Context, key string) *IntCmd
  9. DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
  10. Get(ctx context.Context, key string) *StringCmd
  11. GetRange(ctx context.Context, key string, start, end int64) *StringCmd
  12. GetSet(ctx context.Context, key string, value interface{}) *StringCmd
  13. GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd
  14. GetDel(ctx context.Context, key string) *StringCmd
  15. Incr(ctx context.Context, key string) *IntCmd
  16. IncrBy(ctx context.Context, key string, value int64) *IntCmd
  17. IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
  18. LCS(ctx context.Context, q *LCSQuery) *LCSCmd
  19. MGet(ctx context.Context, keys ...string) *SliceCmd
  20. MSet(ctx context.Context, values ...interface{}) *StatusCmd
  21. MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
  22. Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
  23. SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd
  24. SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
  25. SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
  26. SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
  27. SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
  28. StrLen(ctx context.Context, key string) *IntCmd
  29. }
  30. func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
  31. cmd := NewIntCmd(ctx, "append", key, value)
  32. _ = c(ctx, cmd)
  33. return cmd
  34. }
  35. func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
  36. cmd := NewIntCmd(ctx, "decr", key)
  37. _ = c(ctx, cmd)
  38. return cmd
  39. }
  40. func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
  41. cmd := NewIntCmd(ctx, "decrby", key, decrement)
  42. _ = c(ctx, cmd)
  43. return cmd
  44. }
  45. // Get Redis `GET key` command. It returns redis.Nil error when key does not exist.
  46. func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
  47. cmd := NewStringCmd(ctx, "get", key)
  48. _ = c(ctx, cmd)
  49. return cmd
  50. }
  51. func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
  52. cmd := NewStringCmd(ctx, "getrange", key, start, end)
  53. _ = c(ctx, cmd)
  54. return cmd
  55. }
  56. func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
  57. cmd := NewStringCmd(ctx, "getset", key, value)
  58. _ = c(ctx, cmd)
  59. return cmd
  60. }
  61. // GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist).
  62. // Requires Redis >= 6.2.0.
  63. func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd {
  64. args := make([]interface{}, 0, 4)
  65. args = append(args, "getex", key)
  66. if expiration > 0 {
  67. if usePrecise(expiration) {
  68. args = append(args, "px", formatMs(ctx, expiration))
  69. } else {
  70. args = append(args, "ex", formatSec(ctx, expiration))
  71. }
  72. } else if expiration == 0 {
  73. args = append(args, "persist")
  74. }
  75. cmd := NewStringCmd(ctx, args...)
  76. _ = c(ctx, cmd)
  77. return cmd
  78. }
  79. // GetDel redis-server version >= 6.2.0.
  80. func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd {
  81. cmd := NewStringCmd(ctx, "getdel", key)
  82. _ = c(ctx, cmd)
  83. return cmd
  84. }
  85. func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
  86. cmd := NewIntCmd(ctx, "incr", key)
  87. _ = c(ctx, cmd)
  88. return cmd
  89. }
  90. func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
  91. cmd := NewIntCmd(ctx, "incrby", key, value)
  92. _ = c(ctx, cmd)
  93. return cmd
  94. }
  95. func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
  96. cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
  97. _ = c(ctx, cmd)
  98. return cmd
  99. }
  100. func (c cmdable) LCS(ctx context.Context, q *LCSQuery) *LCSCmd {
  101. cmd := NewLCSCmd(ctx, q)
  102. _ = c(ctx, cmd)
  103. return cmd
  104. }
  105. func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
  106. args := make([]interface{}, 1+len(keys))
  107. args[0] = "mget"
  108. for i, key := range keys {
  109. args[1+i] = key
  110. }
  111. cmd := NewSliceCmd(ctx, args...)
  112. _ = c(ctx, cmd)
  113. return cmd
  114. }
  115. // MSet is like Set but accepts multiple values:
  116. // - MSet("key1", "value1", "key2", "value2")
  117. // - MSet([]string{"key1", "value1", "key2", "value2"})
  118. // - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
  119. // - MSet(struct), For struct types, see HSet description.
  120. func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
  121. args := make([]interface{}, 1, 1+len(values))
  122. args[0] = "mset"
  123. args = appendArgs(args, values)
  124. cmd := NewStatusCmd(ctx, args...)
  125. _ = c(ctx, cmd)
  126. return cmd
  127. }
  128. // MSetNX is like SetNX but accepts multiple values:
  129. // - MSetNX("key1", "value1", "key2", "value2")
  130. // - MSetNX([]string{"key1", "value1", "key2", "value2"})
  131. // - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
  132. // - MSetNX(struct), For struct types, see HSet description.
  133. func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
  134. args := make([]interface{}, 1, 1+len(values))
  135. args[0] = "msetnx"
  136. args = appendArgs(args, values)
  137. cmd := NewBoolCmd(ctx, args...)
  138. _ = c(ctx, cmd)
  139. return cmd
  140. }
  141. // Set Redis `SET key value [expiration]` command.
  142. // Use expiration for `SETEx`-like behavior.
  143. //
  144. // Zero expiration means the key has no expiration time.
  145. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  146. // otherwise you will receive an error: (error) ERR syntax error.
  147. func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
  148. args := make([]interface{}, 3, 5)
  149. args[0] = "set"
  150. args[1] = key
  151. args[2] = value
  152. if expiration > 0 {
  153. if usePrecise(expiration) {
  154. args = append(args, "px", formatMs(ctx, expiration))
  155. } else {
  156. args = append(args, "ex", formatSec(ctx, expiration))
  157. }
  158. } else if expiration == KeepTTL {
  159. args = append(args, "keepttl")
  160. }
  161. cmd := NewStatusCmd(ctx, args...)
  162. _ = c(ctx, cmd)
  163. return cmd
  164. }
  165. // SetArgs provides arguments for the SetArgs function.
  166. type SetArgs struct {
  167. // Mode can be `NX` or `XX` or empty.
  168. Mode string
  169. // Zero `TTL` or `Expiration` means that the key has no expiration time.
  170. TTL time.Duration
  171. ExpireAt time.Time
  172. // When Get is true, the command returns the old value stored at key, or nil when key did not exist.
  173. Get bool
  174. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  175. // otherwise you will receive an error: (error) ERR syntax error.
  176. KeepTTL bool
  177. }
  178. // SetArgs supports all the options that the SET command supports.
  179. // It is the alternative to the Set function when you want
  180. // to have more control over the options.
  181. func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd {
  182. args := []interface{}{"set", key, value}
  183. if a.KeepTTL {
  184. args = append(args, "keepttl")
  185. }
  186. if !a.ExpireAt.IsZero() {
  187. args = append(args, "exat", a.ExpireAt.Unix())
  188. }
  189. if a.TTL > 0 {
  190. if usePrecise(a.TTL) {
  191. args = append(args, "px", formatMs(ctx, a.TTL))
  192. } else {
  193. args = append(args, "ex", formatSec(ctx, a.TTL))
  194. }
  195. }
  196. if a.Mode != "" {
  197. args = append(args, a.Mode)
  198. }
  199. if a.Get {
  200. args = append(args, "get")
  201. }
  202. cmd := NewStatusCmd(ctx, args...)
  203. _ = c(ctx, cmd)
  204. return cmd
  205. }
  206. // SetEx Redis `SETEx key expiration value` command.
  207. func (c cmdable) SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
  208. cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value)
  209. _ = c(ctx, cmd)
  210. return cmd
  211. }
  212. // SetNX Redis `SET key value [expiration] NX` command.
  213. //
  214. // Zero expiration means the key has no expiration time.
  215. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  216. // otherwise you will receive an error: (error) ERR syntax error.
  217. func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
  218. var cmd *BoolCmd
  219. switch expiration {
  220. case 0:
  221. // Use old `SETNX` to support old Redis versions.
  222. cmd = NewBoolCmd(ctx, "setnx", key, value)
  223. case KeepTTL:
  224. cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
  225. default:
  226. if usePrecise(expiration) {
  227. cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
  228. } else {
  229. cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
  230. }
  231. }
  232. _ = c(ctx, cmd)
  233. return cmd
  234. }
  235. // SetXX Redis `SET key value [expiration] XX` command.
  236. //
  237. // Zero expiration means the key has no expiration time.
  238. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  239. // otherwise you will receive an error: (error) ERR syntax error.
  240. func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
  241. var cmd *BoolCmd
  242. switch expiration {
  243. case 0:
  244. cmd = NewBoolCmd(ctx, "set", key, value, "xx")
  245. case KeepTTL:
  246. cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
  247. default:
  248. if usePrecise(expiration) {
  249. cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
  250. } else {
  251. cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
  252. }
  253. }
  254. _ = c(ctx, cmd)
  255. return cmd
  256. }
  257. func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
  258. cmd := NewIntCmd(ctx, "setrange", key, offset, value)
  259. _ = c(ctx, cmd)
  260. return cmd
  261. }
  262. func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
  263. cmd := NewIntCmd(ctx, "strlen", key)
  264. _ = c(ctx, cmd)
  265. return cmd
  266. }