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.

3476 lines
101 KiB

  1. package redis
  2. import (
  3. "context"
  4. "errors"
  5. "io"
  6. "time"
  7. "github.com/go-redis/redis/v8/internal"
  8. )
  9. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  10. // otherwise you will receive an error: (error) ERR syntax error.
  11. // For example:
  12. //
  13. // rdb.Set(ctx, key, value, redis.KeepTTL)
  14. const KeepTTL = -1
  15. func usePrecise(dur time.Duration) bool {
  16. return dur < time.Second || dur%time.Second != 0
  17. }
  18. func formatMs(ctx context.Context, dur time.Duration) int64 {
  19. if dur > 0 && dur < time.Millisecond {
  20. internal.Logger.Printf(
  21. ctx,
  22. "specified duration is %s, but minimal supported value is %s - truncating to 1ms",
  23. dur, time.Millisecond,
  24. )
  25. return 1
  26. }
  27. return int64(dur / time.Millisecond)
  28. }
  29. func formatSec(ctx context.Context, dur time.Duration) int64 {
  30. if dur > 0 && dur < time.Second {
  31. internal.Logger.Printf(
  32. ctx,
  33. "specified duration is %s, but minimal supported value is %s - truncating to 1s",
  34. dur, time.Second,
  35. )
  36. return 1
  37. }
  38. return int64(dur / time.Second)
  39. }
  40. func appendArgs(dst, src []interface{}) []interface{} {
  41. if len(src) == 1 {
  42. return appendArg(dst, src[0])
  43. }
  44. dst = append(dst, src...)
  45. return dst
  46. }
  47. func appendArg(dst []interface{}, arg interface{}) []interface{} {
  48. switch arg := arg.(type) {
  49. case []string:
  50. for _, s := range arg {
  51. dst = append(dst, s)
  52. }
  53. return dst
  54. case []interface{}:
  55. dst = append(dst, arg...)
  56. return dst
  57. case map[string]interface{}:
  58. for k, v := range arg {
  59. dst = append(dst, k, v)
  60. }
  61. return dst
  62. case map[string]string:
  63. for k, v := range arg {
  64. dst = append(dst, k, v)
  65. }
  66. return dst
  67. default:
  68. return append(dst, arg)
  69. }
  70. }
  71. type Cmdable interface {
  72. Pipeline() Pipeliner
  73. Pipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
  74. TxPipelined(ctx context.Context, fn func(Pipeliner) error) ([]Cmder, error)
  75. TxPipeline() Pipeliner
  76. Command(ctx context.Context) *CommandsInfoCmd
  77. ClientGetName(ctx context.Context) *StringCmd
  78. Echo(ctx context.Context, message interface{}) *StringCmd
  79. Ping(ctx context.Context) *StatusCmd
  80. Quit(ctx context.Context) *StatusCmd
  81. Del(ctx context.Context, keys ...string) *IntCmd
  82. Unlink(ctx context.Context, keys ...string) *IntCmd
  83. Dump(ctx context.Context, key string) *StringCmd
  84. Exists(ctx context.Context, keys ...string) *IntCmd
  85. Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
  86. ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
  87. ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
  88. ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
  89. ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
  90. ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
  91. Keys(ctx context.Context, pattern string) *StringSliceCmd
  92. Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd
  93. Move(ctx context.Context, key string, db int) *BoolCmd
  94. ObjectRefCount(ctx context.Context, key string) *IntCmd
  95. ObjectEncoding(ctx context.Context, key string) *StringCmd
  96. ObjectIdleTime(ctx context.Context, key string) *DurationCmd
  97. Persist(ctx context.Context, key string) *BoolCmd
  98. PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
  99. PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
  100. PTTL(ctx context.Context, key string) *DurationCmd
  101. RandomKey(ctx context.Context) *StringCmd
  102. Rename(ctx context.Context, key, newkey string) *StatusCmd
  103. RenameNX(ctx context.Context, key, newkey string) *BoolCmd
  104. Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
  105. RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
  106. Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd
  107. SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd
  108. SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd
  109. Touch(ctx context.Context, keys ...string) *IntCmd
  110. TTL(ctx context.Context, key string) *DurationCmd
  111. Type(ctx context.Context, key string) *StatusCmd
  112. Append(ctx context.Context, key, value string) *IntCmd
  113. Decr(ctx context.Context, key string) *IntCmd
  114. DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
  115. Get(ctx context.Context, key string) *StringCmd
  116. GetRange(ctx context.Context, key string, start, end int64) *StringCmd
  117. GetSet(ctx context.Context, key string, value interface{}) *StringCmd
  118. GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd
  119. GetDel(ctx context.Context, key string) *StringCmd
  120. Incr(ctx context.Context, key string) *IntCmd
  121. IncrBy(ctx context.Context, key string, value int64) *IntCmd
  122. IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
  123. MGet(ctx context.Context, keys ...string) *SliceCmd
  124. MSet(ctx context.Context, values ...interface{}) *StatusCmd
  125. MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
  126. Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
  127. SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd
  128. // TODO: rename to SetEx
  129. SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
  130. SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
  131. SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
  132. SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
  133. StrLen(ctx context.Context, key string) *IntCmd
  134. Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *IntCmd
  135. GetBit(ctx context.Context, key string, offset int64) *IntCmd
  136. SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
  137. BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
  138. BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
  139. BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
  140. BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
  141. BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
  142. BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
  143. BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd
  144. Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd
  145. ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd
  146. SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
  147. HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
  148. ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
  149. HDel(ctx context.Context, key string, fields ...string) *IntCmd
  150. HExists(ctx context.Context, key, field string) *BoolCmd
  151. HGet(ctx context.Context, key, field string) *StringCmd
  152. HGetAll(ctx context.Context, key string) *StringStringMapCmd
  153. HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
  154. HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
  155. HKeys(ctx context.Context, key string) *StringSliceCmd
  156. HLen(ctx context.Context, key string) *IntCmd
  157. HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
  158. HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
  159. HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
  160. HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
  161. HVals(ctx context.Context, key string) *StringSliceCmd
  162. HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd
  163. BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
  164. BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
  165. BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd
  166. LIndex(ctx context.Context, key string, index int64) *StringCmd
  167. LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd
  168. LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd
  169. LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd
  170. LLen(ctx context.Context, key string) *IntCmd
  171. LPop(ctx context.Context, key string) *StringCmd
  172. LPopCount(ctx context.Context, key string, count int) *StringSliceCmd
  173. LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd
  174. LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd
  175. LPush(ctx context.Context, key string, values ...interface{}) *IntCmd
  176. LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
  177. LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
  178. LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
  179. LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd
  180. LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd
  181. RPop(ctx context.Context, key string) *StringCmd
  182. RPopCount(ctx context.Context, key string, count int) *StringSliceCmd
  183. RPopLPush(ctx context.Context, source, destination string) *StringCmd
  184. RPush(ctx context.Context, key string, values ...interface{}) *IntCmd
  185. RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
  186. LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd
  187. BLMove(ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration) *StringCmd
  188. SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
  189. SCard(ctx context.Context, key string) *IntCmd
  190. SDiff(ctx context.Context, keys ...string) *StringSliceCmd
  191. SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
  192. SInter(ctx context.Context, keys ...string) *StringSliceCmd
  193. SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd
  194. SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd
  195. SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd
  196. SMembers(ctx context.Context, key string) *StringSliceCmd
  197. SMembersMap(ctx context.Context, key string) *StringStructMapCmd
  198. SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd
  199. SPop(ctx context.Context, key string) *StringCmd
  200. SPopN(ctx context.Context, key string, count int64) *StringSliceCmd
  201. SRandMember(ctx context.Context, key string) *StringCmd
  202. SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd
  203. SRem(ctx context.Context, key string, members ...interface{}) *IntCmd
  204. SUnion(ctx context.Context, keys ...string) *StringSliceCmd
  205. SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
  206. XAdd(ctx context.Context, a *XAddArgs) *StringCmd
  207. XDel(ctx context.Context, stream string, ids ...string) *IntCmd
  208. XLen(ctx context.Context, stream string) *IntCmd
  209. XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
  210. XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
  211. XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
  212. XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
  213. XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
  214. XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
  215. XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
  216. XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
  217. XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
  218. XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
  219. XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
  220. XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
  221. XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
  222. XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
  223. XPending(ctx context.Context, stream, group string) *XPendingCmd
  224. XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
  225. XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
  226. XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
  227. XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd
  228. XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd
  229. // TODO: XTrim and XTrimApprox remove in v9.
  230. XTrim(ctx context.Context, key string, maxLen int64) *IntCmd
  231. XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd
  232. XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd
  233. XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd
  234. XTrimMinID(ctx context.Context, key string, minID string) *IntCmd
  235. XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd
  236. XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
  237. XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
  238. XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd
  239. XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd
  240. BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
  241. BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
  242. // TODO: remove
  243. // ZAddCh
  244. // ZIncr
  245. // ZAddNXCh
  246. // ZAddXXCh
  247. // ZIncrNX
  248. // ZIncrXX
  249. // in v9.
  250. // use ZAddArgs and ZAddArgsIncr.
  251. ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd
  252. ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd
  253. ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd
  254. ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd
  255. ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd
  256. ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd
  257. ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd
  258. ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd
  259. ZIncr(ctx context.Context, key string, member *Z) *FloatCmd
  260. ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd
  261. ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd
  262. ZCard(ctx context.Context, key string) *IntCmd
  263. ZCount(ctx context.Context, key, min, max string) *IntCmd
  264. ZLexCount(ctx context.Context, key, min, max string) *IntCmd
  265. ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
  266. ZInter(ctx context.Context, store *ZStore) *StringSliceCmd
  267. ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
  268. ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
  269. ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
  270. ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
  271. ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
  272. ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
  273. ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
  274. ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
  275. ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
  276. ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
  277. ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd
  278. ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd
  279. ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd
  280. ZRank(ctx context.Context, key, member string) *IntCmd
  281. ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
  282. ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
  283. ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
  284. ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
  285. ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
  286. ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
  287. ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
  288. ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
  289. ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
  290. ZRevRank(ctx context.Context, key, member string) *IntCmd
  291. ZScore(ctx context.Context, key, member string) *FloatCmd
  292. ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
  293. ZUnion(ctx context.Context, store ZStore) *StringSliceCmd
  294. ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd
  295. ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd
  296. ZDiff(ctx context.Context, keys ...string) *StringSliceCmd
  297. ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd
  298. ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
  299. PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd
  300. PFCount(ctx context.Context, keys ...string) *IntCmd
  301. PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd
  302. BgRewriteAOF(ctx context.Context) *StatusCmd
  303. BgSave(ctx context.Context) *StatusCmd
  304. ClientKill(ctx context.Context, ipPort string) *StatusCmd
  305. ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd
  306. ClientList(ctx context.Context) *StringCmd
  307. ClientPause(ctx context.Context, dur time.Duration) *BoolCmd
  308. ClientID(ctx context.Context) *IntCmd
  309. ConfigGet(ctx context.Context, parameter string) *SliceCmd
  310. ConfigResetStat(ctx context.Context) *StatusCmd
  311. ConfigSet(ctx context.Context, parameter, value string) *StatusCmd
  312. ConfigRewrite(ctx context.Context) *StatusCmd
  313. DBSize(ctx context.Context) *IntCmd
  314. FlushAll(ctx context.Context) *StatusCmd
  315. FlushAllAsync(ctx context.Context) *StatusCmd
  316. FlushDB(ctx context.Context) *StatusCmd
  317. FlushDBAsync(ctx context.Context) *StatusCmd
  318. Info(ctx context.Context, section ...string) *StringCmd
  319. LastSave(ctx context.Context) *IntCmd
  320. Save(ctx context.Context) *StatusCmd
  321. Shutdown(ctx context.Context) *StatusCmd
  322. ShutdownSave(ctx context.Context) *StatusCmd
  323. ShutdownNoSave(ctx context.Context) *StatusCmd
  324. SlaveOf(ctx context.Context, host, port string) *StatusCmd
  325. Time(ctx context.Context) *TimeCmd
  326. DebugObject(ctx context.Context, key string) *StringCmd
  327. ReadOnly(ctx context.Context) *StatusCmd
  328. ReadWrite(ctx context.Context) *StatusCmd
  329. MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd
  330. Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
  331. EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
  332. ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
  333. ScriptFlush(ctx context.Context) *StatusCmd
  334. ScriptKill(ctx context.Context) *StatusCmd
  335. ScriptLoad(ctx context.Context, script string) *StringCmd
  336. Publish(ctx context.Context, channel string, message interface{}) *IntCmd
  337. PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd
  338. PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd
  339. PubSubNumPat(ctx context.Context) *IntCmd
  340. ClusterSlots(ctx context.Context) *ClusterSlotsCmd
  341. ClusterNodes(ctx context.Context) *StringCmd
  342. ClusterMeet(ctx context.Context, host, port string) *StatusCmd
  343. ClusterForget(ctx context.Context, nodeID string) *StatusCmd
  344. ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
  345. ClusterResetSoft(ctx context.Context) *StatusCmd
  346. ClusterResetHard(ctx context.Context) *StatusCmd
  347. ClusterInfo(ctx context.Context) *StringCmd
  348. ClusterKeySlot(ctx context.Context, key string) *IntCmd
  349. ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
  350. ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
  351. ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
  352. ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
  353. ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
  354. ClusterSaveConfig(ctx context.Context) *StatusCmd
  355. ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
  356. ClusterFailover(ctx context.Context) *StatusCmd
  357. ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
  358. ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
  359. GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd
  360. GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd
  361. GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd
  362. GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd
  363. GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd
  364. GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd
  365. GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd
  366. GeoSearchLocation(ctx context.Context, key string, q *GeoSearchLocationQuery) *GeoSearchLocationCmd
  367. GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd
  368. GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd
  369. GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd
  370. }
  371. type StatefulCmdable interface {
  372. Cmdable
  373. Auth(ctx context.Context, password string) *StatusCmd
  374. AuthACL(ctx context.Context, username, password string) *StatusCmd
  375. Select(ctx context.Context, index int) *StatusCmd
  376. SwapDB(ctx context.Context, index1, index2 int) *StatusCmd
  377. ClientSetName(ctx context.Context, name string) *BoolCmd
  378. }
  379. var (
  380. _ Cmdable = (*Client)(nil)
  381. _ Cmdable = (*Tx)(nil)
  382. _ Cmdable = (*Ring)(nil)
  383. _ Cmdable = (*ClusterClient)(nil)
  384. )
  385. type cmdable func(ctx context.Context, cmd Cmder) error
  386. type statefulCmdable func(ctx context.Context, cmd Cmder) error
  387. //------------------------------------------------------------------------------
  388. func (c statefulCmdable) Auth(ctx context.Context, password string) *StatusCmd {
  389. cmd := NewStatusCmd(ctx, "auth", password)
  390. _ = c(ctx, cmd)
  391. return cmd
  392. }
  393. // AuthACL Perform an AUTH command, using the given user and pass.
  394. // Should be used to authenticate the current connection with one of the connections defined in the ACL list
  395. // when connecting to a Redis 6.0 instance, or greater, that is using the Redis ACL system.
  396. func (c statefulCmdable) AuthACL(ctx context.Context, username, password string) *StatusCmd {
  397. cmd := NewStatusCmd(ctx, "auth", username, password)
  398. _ = c(ctx, cmd)
  399. return cmd
  400. }
  401. func (c cmdable) Wait(ctx context.Context, numSlaves int, timeout time.Duration) *IntCmd {
  402. cmd := NewIntCmd(ctx, "wait", numSlaves, int(timeout/time.Millisecond))
  403. cmd.setReadTimeout(timeout)
  404. _ = c(ctx, cmd)
  405. return cmd
  406. }
  407. func (c statefulCmdable) Select(ctx context.Context, index int) *StatusCmd {
  408. cmd := NewStatusCmd(ctx, "select", index)
  409. _ = c(ctx, cmd)
  410. return cmd
  411. }
  412. func (c statefulCmdable) SwapDB(ctx context.Context, index1, index2 int) *StatusCmd {
  413. cmd := NewStatusCmd(ctx, "swapdb", index1, index2)
  414. _ = c(ctx, cmd)
  415. return cmd
  416. }
  417. // ClientSetName assigns a name to the connection.
  418. func (c statefulCmdable) ClientSetName(ctx context.Context, name string) *BoolCmd {
  419. cmd := NewBoolCmd(ctx, "client", "setname", name)
  420. _ = c(ctx, cmd)
  421. return cmd
  422. }
  423. //------------------------------------------------------------------------------
  424. func (c cmdable) Command(ctx context.Context) *CommandsInfoCmd {
  425. cmd := NewCommandsInfoCmd(ctx, "command")
  426. _ = c(ctx, cmd)
  427. return cmd
  428. }
  429. // ClientGetName returns the name of the connection.
  430. func (c cmdable) ClientGetName(ctx context.Context) *StringCmd {
  431. cmd := NewStringCmd(ctx, "client", "getname")
  432. _ = c(ctx, cmd)
  433. return cmd
  434. }
  435. func (c cmdable) Echo(ctx context.Context, message interface{}) *StringCmd {
  436. cmd := NewStringCmd(ctx, "echo", message)
  437. _ = c(ctx, cmd)
  438. return cmd
  439. }
  440. func (c cmdable) Ping(ctx context.Context) *StatusCmd {
  441. cmd := NewStatusCmd(ctx, "ping")
  442. _ = c(ctx, cmd)
  443. return cmd
  444. }
  445. func (c cmdable) Quit(_ context.Context) *StatusCmd {
  446. panic("not implemented")
  447. }
  448. func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
  449. args := make([]interface{}, 1+len(keys))
  450. args[0] = "del"
  451. for i, key := range keys {
  452. args[1+i] = key
  453. }
  454. cmd := NewIntCmd(ctx, args...)
  455. _ = c(ctx, cmd)
  456. return cmd
  457. }
  458. func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
  459. args := make([]interface{}, 1+len(keys))
  460. args[0] = "unlink"
  461. for i, key := range keys {
  462. args[1+i] = key
  463. }
  464. cmd := NewIntCmd(ctx, args...)
  465. _ = c(ctx, cmd)
  466. return cmd
  467. }
  468. func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
  469. cmd := NewStringCmd(ctx, "dump", key)
  470. _ = c(ctx, cmd)
  471. return cmd
  472. }
  473. func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
  474. args := make([]interface{}, 1+len(keys))
  475. args[0] = "exists"
  476. for i, key := range keys {
  477. args[1+i] = key
  478. }
  479. cmd := NewIntCmd(ctx, args...)
  480. _ = c(ctx, cmd)
  481. return cmd
  482. }
  483. func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
  484. return c.expire(ctx, key, expiration, "")
  485. }
  486. func (c cmdable) ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
  487. return c.expire(ctx, key, expiration, "NX")
  488. }
  489. func (c cmdable) ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
  490. return c.expire(ctx, key, expiration, "XX")
  491. }
  492. func (c cmdable) ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
  493. return c.expire(ctx, key, expiration, "GT")
  494. }
  495. func (c cmdable) ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
  496. return c.expire(ctx, key, expiration, "LT")
  497. }
  498. func (c cmdable) expire(
  499. ctx context.Context, key string, expiration time.Duration, mode string,
  500. ) *BoolCmd {
  501. args := make([]interface{}, 3, 4)
  502. args[0] = "expire"
  503. args[1] = key
  504. args[2] = formatSec(ctx, expiration)
  505. if mode != "" {
  506. args = append(args, mode)
  507. }
  508. cmd := NewBoolCmd(ctx, args...)
  509. _ = c(ctx, cmd)
  510. return cmd
  511. }
  512. func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
  513. cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix())
  514. _ = c(ctx, cmd)
  515. return cmd
  516. }
  517. func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {
  518. cmd := NewStringSliceCmd(ctx, "keys", pattern)
  519. _ = c(ctx, cmd)
  520. return cmd
  521. }
  522. func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd {
  523. cmd := NewStatusCmd(
  524. ctx,
  525. "migrate",
  526. host,
  527. port,
  528. key,
  529. db,
  530. formatMs(ctx, timeout),
  531. )
  532. cmd.setReadTimeout(timeout)
  533. _ = c(ctx, cmd)
  534. return cmd
  535. }
  536. func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
  537. cmd := NewBoolCmd(ctx, "move", key, db)
  538. _ = c(ctx, cmd)
  539. return cmd
  540. }
  541. func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
  542. cmd := NewIntCmd(ctx, "object", "refcount", key)
  543. _ = c(ctx, cmd)
  544. return cmd
  545. }
  546. func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd {
  547. cmd := NewStringCmd(ctx, "object", "encoding", key)
  548. _ = c(ctx, cmd)
  549. return cmd
  550. }
  551. func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd {
  552. cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key)
  553. _ = c(ctx, cmd)
  554. return cmd
  555. }
  556. func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
  557. cmd := NewBoolCmd(ctx, "persist", key)
  558. _ = c(ctx, cmd)
  559. return cmd
  560. }
  561. func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
  562. cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration))
  563. _ = c(ctx, cmd)
  564. return cmd
  565. }
  566. func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
  567. cmd := NewBoolCmd(
  568. ctx,
  569. "pexpireat",
  570. key,
  571. tm.UnixNano()/int64(time.Millisecond),
  572. )
  573. _ = c(ctx, cmd)
  574. return cmd
  575. }
  576. func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
  577. cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key)
  578. _ = c(ctx, cmd)
  579. return cmd
  580. }
  581. func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
  582. cmd := NewStringCmd(ctx, "randomkey")
  583. _ = c(ctx, cmd)
  584. return cmd
  585. }
  586. func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd {
  587. cmd := NewStatusCmd(ctx, "rename", key, newkey)
  588. _ = c(ctx, cmd)
  589. return cmd
  590. }
  591. func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd {
  592. cmd := NewBoolCmd(ctx, "renamenx", key, newkey)
  593. _ = c(ctx, cmd)
  594. return cmd
  595. }
  596. func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
  597. cmd := NewStatusCmd(
  598. ctx,
  599. "restore",
  600. key,
  601. formatMs(ctx, ttl),
  602. value,
  603. )
  604. _ = c(ctx, cmd)
  605. return cmd
  606. }
  607. func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
  608. cmd := NewStatusCmd(
  609. ctx,
  610. "restore",
  611. key,
  612. formatMs(ctx, ttl),
  613. value,
  614. "replace",
  615. )
  616. _ = c(ctx, cmd)
  617. return cmd
  618. }
  619. type Sort struct {
  620. By string
  621. Offset, Count int64
  622. Get []string
  623. Order string
  624. Alpha bool
  625. }
  626. func (sort *Sort) args(key string) []interface{} {
  627. args := []interface{}{"sort", key}
  628. if sort.By != "" {
  629. args = append(args, "by", sort.By)
  630. }
  631. if sort.Offset != 0 || sort.Count != 0 {
  632. args = append(args, "limit", sort.Offset, sort.Count)
  633. }
  634. for _, get := range sort.Get {
  635. args = append(args, "get", get)
  636. }
  637. if sort.Order != "" {
  638. args = append(args, sort.Order)
  639. }
  640. if sort.Alpha {
  641. args = append(args, "alpha")
  642. }
  643. return args
  644. }
  645. func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
  646. cmd := NewStringSliceCmd(ctx, sort.args(key)...)
  647. _ = c(ctx, cmd)
  648. return cmd
  649. }
  650. func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd {
  651. args := sort.args(key)
  652. if store != "" {
  653. args = append(args, "store", store)
  654. }
  655. cmd := NewIntCmd(ctx, args...)
  656. _ = c(ctx, cmd)
  657. return cmd
  658. }
  659. func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd {
  660. cmd := NewSliceCmd(ctx, sort.args(key)...)
  661. _ = c(ctx, cmd)
  662. return cmd
  663. }
  664. func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
  665. args := make([]interface{}, len(keys)+1)
  666. args[0] = "touch"
  667. for i, key := range keys {
  668. args[i+1] = key
  669. }
  670. cmd := NewIntCmd(ctx, args...)
  671. _ = c(ctx, cmd)
  672. return cmd
  673. }
  674. func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
  675. cmd := NewDurationCmd(ctx, time.Second, "ttl", key)
  676. _ = c(ctx, cmd)
  677. return cmd
  678. }
  679. func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
  680. cmd := NewStatusCmd(ctx, "type", key)
  681. _ = c(ctx, cmd)
  682. return cmd
  683. }
  684. func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
  685. cmd := NewIntCmd(ctx, "append", key, value)
  686. _ = c(ctx, cmd)
  687. return cmd
  688. }
  689. func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
  690. cmd := NewIntCmd(ctx, "decr", key)
  691. _ = c(ctx, cmd)
  692. return cmd
  693. }
  694. func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
  695. cmd := NewIntCmd(ctx, "decrby", key, decrement)
  696. _ = c(ctx, cmd)
  697. return cmd
  698. }
  699. // Get Redis `GET key` command. It returns redis.Nil error when key does not exist.
  700. func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
  701. cmd := NewStringCmd(ctx, "get", key)
  702. _ = c(ctx, cmd)
  703. return cmd
  704. }
  705. func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
  706. cmd := NewStringCmd(ctx, "getrange", key, start, end)
  707. _ = c(ctx, cmd)
  708. return cmd
  709. }
  710. func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
  711. cmd := NewStringCmd(ctx, "getset", key, value)
  712. _ = c(ctx, cmd)
  713. return cmd
  714. }
  715. // GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist).
  716. // Requires Redis >= 6.2.0.
  717. func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd {
  718. args := make([]interface{}, 0, 4)
  719. args = append(args, "getex", key)
  720. if expiration > 0 {
  721. if usePrecise(expiration) {
  722. args = append(args, "px", formatMs(ctx, expiration))
  723. } else {
  724. args = append(args, "ex", formatSec(ctx, expiration))
  725. }
  726. } else if expiration == 0 {
  727. args = append(args, "persist")
  728. }
  729. cmd := NewStringCmd(ctx, args...)
  730. _ = c(ctx, cmd)
  731. return cmd
  732. }
  733. // GetDel redis-server version >= 6.2.0.
  734. func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd {
  735. cmd := NewStringCmd(ctx, "getdel", key)
  736. _ = c(ctx, cmd)
  737. return cmd
  738. }
  739. func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
  740. cmd := NewIntCmd(ctx, "incr", key)
  741. _ = c(ctx, cmd)
  742. return cmd
  743. }
  744. func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
  745. cmd := NewIntCmd(ctx, "incrby", key, value)
  746. _ = c(ctx, cmd)
  747. return cmd
  748. }
  749. func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
  750. cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
  751. _ = c(ctx, cmd)
  752. return cmd
  753. }
  754. func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
  755. args := make([]interface{}, 1+len(keys))
  756. args[0] = "mget"
  757. for i, key := range keys {
  758. args[1+i] = key
  759. }
  760. cmd := NewSliceCmd(ctx, args...)
  761. _ = c(ctx, cmd)
  762. return cmd
  763. }
  764. // MSet is like Set but accepts multiple values:
  765. // - MSet("key1", "value1", "key2", "value2")
  766. // - MSet([]string{"key1", "value1", "key2", "value2"})
  767. // - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
  768. func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
  769. args := make([]interface{}, 1, 1+len(values))
  770. args[0] = "mset"
  771. args = appendArgs(args, values)
  772. cmd := NewStatusCmd(ctx, args...)
  773. _ = c(ctx, cmd)
  774. return cmd
  775. }
  776. // MSetNX is like SetNX but accepts multiple values:
  777. // - MSetNX("key1", "value1", "key2", "value2")
  778. // - MSetNX([]string{"key1", "value1", "key2", "value2"})
  779. // - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
  780. func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
  781. args := make([]interface{}, 1, 1+len(values))
  782. args[0] = "msetnx"
  783. args = appendArgs(args, values)
  784. cmd := NewBoolCmd(ctx, args...)
  785. _ = c(ctx, cmd)
  786. return cmd
  787. }
  788. // Set Redis `SET key value [expiration]` command.
  789. // Use expiration for `SETEX`-like behavior.
  790. //
  791. // Zero expiration means the key has no expiration time.
  792. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  793. // otherwise you will receive an error: (error) ERR syntax error.
  794. func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
  795. args := make([]interface{}, 3, 5)
  796. args[0] = "set"
  797. args[1] = key
  798. args[2] = value
  799. if expiration > 0 {
  800. if usePrecise(expiration) {
  801. args = append(args, "px", formatMs(ctx, expiration))
  802. } else {
  803. args = append(args, "ex", formatSec(ctx, expiration))
  804. }
  805. } else if expiration == KeepTTL {
  806. args = append(args, "keepttl")
  807. }
  808. cmd := NewStatusCmd(ctx, args...)
  809. _ = c(ctx, cmd)
  810. return cmd
  811. }
  812. // SetArgs provides arguments for the SetArgs function.
  813. type SetArgs struct {
  814. // Mode can be `NX` or `XX` or empty.
  815. Mode string
  816. // Zero `TTL` or `Expiration` means that the key has no expiration time.
  817. TTL time.Duration
  818. ExpireAt time.Time
  819. // When Get is true, the command returns the old value stored at key, or nil when key did not exist.
  820. Get bool
  821. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  822. // otherwise you will receive an error: (error) ERR syntax error.
  823. KeepTTL bool
  824. }
  825. // SetArgs supports all the options that the SET command supports.
  826. // It is the alternative to the Set function when you want
  827. // to have more control over the options.
  828. func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd {
  829. args := []interface{}{"set", key, value}
  830. if a.KeepTTL {
  831. args = append(args, "keepttl")
  832. }
  833. if !a.ExpireAt.IsZero() {
  834. args = append(args, "exat", a.ExpireAt.Unix())
  835. }
  836. if a.TTL > 0 {
  837. if usePrecise(a.TTL) {
  838. args = append(args, "px", formatMs(ctx, a.TTL))
  839. } else {
  840. args = append(args, "ex", formatSec(ctx, a.TTL))
  841. }
  842. }
  843. if a.Mode != "" {
  844. args = append(args, a.Mode)
  845. }
  846. if a.Get {
  847. args = append(args, "get")
  848. }
  849. cmd := NewStatusCmd(ctx, args...)
  850. _ = c(ctx, cmd)
  851. return cmd
  852. }
  853. // SetEX Redis `SETEX key expiration value` command.
  854. func (c cmdable) SetEX(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
  855. cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value)
  856. _ = c(ctx, cmd)
  857. return cmd
  858. }
  859. // SetNX Redis `SET key value [expiration] NX` command.
  860. //
  861. // Zero expiration means the key has no expiration time.
  862. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  863. // otherwise you will receive an error: (error) ERR syntax error.
  864. func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
  865. var cmd *BoolCmd
  866. switch expiration {
  867. case 0:
  868. // Use old `SETNX` to support old Redis versions.
  869. cmd = NewBoolCmd(ctx, "setnx", key, value)
  870. case KeepTTL:
  871. cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
  872. default:
  873. if usePrecise(expiration) {
  874. cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
  875. } else {
  876. cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
  877. }
  878. }
  879. _ = c(ctx, cmd)
  880. return cmd
  881. }
  882. // SetXX Redis `SET key value [expiration] XX` command.
  883. //
  884. // Zero expiration means the key has no expiration time.
  885. // KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
  886. // otherwise you will receive an error: (error) ERR syntax error.
  887. func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
  888. var cmd *BoolCmd
  889. switch expiration {
  890. case 0:
  891. cmd = NewBoolCmd(ctx, "set", key, value, "xx")
  892. case KeepTTL:
  893. cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
  894. default:
  895. if usePrecise(expiration) {
  896. cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
  897. } else {
  898. cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
  899. }
  900. }
  901. _ = c(ctx, cmd)
  902. return cmd
  903. }
  904. func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
  905. cmd := NewIntCmd(ctx, "setrange", key, offset, value)
  906. _ = c(ctx, cmd)
  907. return cmd
  908. }
  909. func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
  910. cmd := NewIntCmd(ctx, "strlen", key)
  911. _ = c(ctx, cmd)
  912. return cmd
  913. }
  914. func (c cmdable) Copy(ctx context.Context, sourceKey, destKey string, db int, replace bool) *IntCmd {
  915. args := []interface{}{"copy", sourceKey, destKey, "DB", db}
  916. if replace {
  917. args = append(args, "REPLACE")
  918. }
  919. cmd := NewIntCmd(ctx, args...)
  920. _ = c(ctx, cmd)
  921. return cmd
  922. }
  923. //------------------------------------------------------------------------------
  924. func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
  925. cmd := NewIntCmd(ctx, "getbit", key, offset)
  926. _ = c(ctx, cmd)
  927. return cmd
  928. }
  929. func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
  930. cmd := NewIntCmd(
  931. ctx,
  932. "setbit",
  933. key,
  934. offset,
  935. value,
  936. )
  937. _ = c(ctx, cmd)
  938. return cmd
  939. }
  940. type BitCount struct {
  941. Start, End int64
  942. }
  943. func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
  944. args := []interface{}{"bitcount", key}
  945. if bitCount != nil {
  946. args = append(
  947. args,
  948. bitCount.Start,
  949. bitCount.End,
  950. )
  951. }
  952. cmd := NewIntCmd(ctx, args...)
  953. _ = c(ctx, cmd)
  954. return cmd
  955. }
  956. func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
  957. args := make([]interface{}, 3+len(keys))
  958. args[0] = "bitop"
  959. args[1] = op
  960. args[2] = destKey
  961. for i, key := range keys {
  962. args[3+i] = key
  963. }
  964. cmd := NewIntCmd(ctx, args...)
  965. _ = c(ctx, cmd)
  966. return cmd
  967. }
  968. func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
  969. return c.bitOp(ctx, "and", destKey, keys...)
  970. }
  971. func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
  972. return c.bitOp(ctx, "or", destKey, keys...)
  973. }
  974. func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
  975. return c.bitOp(ctx, "xor", destKey, keys...)
  976. }
  977. func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
  978. return c.bitOp(ctx, "not", destKey, key)
  979. }
  980. func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
  981. args := make([]interface{}, 3+len(pos))
  982. args[0] = "bitpos"
  983. args[1] = key
  984. args[2] = bit
  985. switch len(pos) {
  986. case 0:
  987. case 1:
  988. args[3] = pos[0]
  989. case 2:
  990. args[3] = pos[0]
  991. args[4] = pos[1]
  992. default:
  993. panic("too many arguments")
  994. }
  995. cmd := NewIntCmd(ctx, args...)
  996. _ = c(ctx, cmd)
  997. return cmd
  998. }
  999. func (c cmdable) BitField(ctx context.Context, key string, args ...interface{}) *IntSliceCmd {
  1000. a := make([]interface{}, 0, 2+len(args))
  1001. a = append(a, "bitfield")
  1002. a = append(a, key)
  1003. a = append(a, args...)
  1004. cmd := NewIntSliceCmd(ctx, a...)
  1005. _ = c(ctx, cmd)
  1006. return cmd
  1007. }
  1008. //------------------------------------------------------------------------------
  1009. func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {
  1010. args := []interface{}{"scan", cursor}
  1011. if match != "" {
  1012. args = append(args, "match", match)
  1013. }
  1014. if count > 0 {
  1015. args = append(args, "count", count)
  1016. }
  1017. cmd := NewScanCmd(ctx, c, args...)
  1018. _ = c(ctx, cmd)
  1019. return cmd
  1020. }
  1021. func (c cmdable) ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd {
  1022. args := []interface{}{"scan", cursor}
  1023. if match != "" {
  1024. args = append(args, "match", match)
  1025. }
  1026. if count > 0 {
  1027. args = append(args, "count", count)
  1028. }
  1029. if keyType != "" {
  1030. args = append(args, "type", keyType)
  1031. }
  1032. cmd := NewScanCmd(ctx, c, args...)
  1033. _ = c(ctx, cmd)
  1034. return cmd
  1035. }
  1036. func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
  1037. args := []interface{}{"sscan", key, cursor}
  1038. if match != "" {
  1039. args = append(args, "match", match)
  1040. }
  1041. if count > 0 {
  1042. args = append(args, "count", count)
  1043. }
  1044. cmd := NewScanCmd(ctx, c, args...)
  1045. _ = c(ctx, cmd)
  1046. return cmd
  1047. }
  1048. func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
  1049. args := []interface{}{"hscan", key, cursor}
  1050. if match != "" {
  1051. args = append(args, "match", match)
  1052. }
  1053. if count > 0 {
  1054. args = append(args, "count", count)
  1055. }
  1056. cmd := NewScanCmd(ctx, c, args...)
  1057. _ = c(ctx, cmd)
  1058. return cmd
  1059. }
  1060. func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
  1061. args := []interface{}{"zscan", key, cursor}
  1062. if match != "" {
  1063. args = append(args, "match", match)
  1064. }
  1065. if count > 0 {
  1066. args = append(args, "count", count)
  1067. }
  1068. cmd := NewScanCmd(ctx, c, args...)
  1069. _ = c(ctx, cmd)
  1070. return cmd
  1071. }
  1072. //------------------------------------------------------------------------------
  1073. func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
  1074. args := make([]interface{}, 2+len(fields))
  1075. args[0] = "hdel"
  1076. args[1] = key
  1077. for i, field := range fields {
  1078. args[2+i] = field
  1079. }
  1080. cmd := NewIntCmd(ctx, args...)
  1081. _ = c(ctx, cmd)
  1082. return cmd
  1083. }
  1084. func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
  1085. cmd := NewBoolCmd(ctx, "hexists", key, field)
  1086. _ = c(ctx, cmd)
  1087. return cmd
  1088. }
  1089. func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
  1090. cmd := NewStringCmd(ctx, "hget", key, field)
  1091. _ = c(ctx, cmd)
  1092. return cmd
  1093. }
  1094. func (c cmdable) HGetAll(ctx context.Context, key string) *StringStringMapCmd {
  1095. cmd := NewStringStringMapCmd(ctx, "hgetall", key)
  1096. _ = c(ctx, cmd)
  1097. return cmd
  1098. }
  1099. func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
  1100. cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
  1101. _ = c(ctx, cmd)
  1102. return cmd
  1103. }
  1104. func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
  1105. cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
  1106. _ = c(ctx, cmd)
  1107. return cmd
  1108. }
  1109. func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
  1110. cmd := NewStringSliceCmd(ctx, "hkeys", key)
  1111. _ = c(ctx, cmd)
  1112. return cmd
  1113. }
  1114. func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
  1115. cmd := NewIntCmd(ctx, "hlen", key)
  1116. _ = c(ctx, cmd)
  1117. return cmd
  1118. }
  1119. // HMGet returns the values for the specified fields in the hash stored at key.
  1120. // It returns an interface{} to distinguish between empty string and nil value.
  1121. func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
  1122. args := make([]interface{}, 2+len(fields))
  1123. args[0] = "hmget"
  1124. args[1] = key
  1125. for i, field := range fields {
  1126. args[2+i] = field
  1127. }
  1128. cmd := NewSliceCmd(ctx, args...)
  1129. _ = c(ctx, cmd)
  1130. return cmd
  1131. }
  1132. // HSet accepts values in following formats:
  1133. // - HSet("myhash", "key1", "value1", "key2", "value2")
  1134. // - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
  1135. // - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
  1136. //
  1137. // Note that it requires Redis v4 for multiple field/value pairs support.
  1138. func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
  1139. args := make([]interface{}, 2, 2+len(values))
  1140. args[0] = "hset"
  1141. args[1] = key
  1142. args = appendArgs(args, values)
  1143. cmd := NewIntCmd(ctx, args...)
  1144. _ = c(ctx, cmd)
  1145. return cmd
  1146. }
  1147. // HMSet is a deprecated version of HSet left for compatibility with Redis 3.
  1148. func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
  1149. args := make([]interface{}, 2, 2+len(values))
  1150. args[0] = "hmset"
  1151. args[1] = key
  1152. args = appendArgs(args, values)
  1153. cmd := NewBoolCmd(ctx, args...)
  1154. _ = c(ctx, cmd)
  1155. return cmd
  1156. }
  1157. func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
  1158. cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
  1159. _ = c(ctx, cmd)
  1160. return cmd
  1161. }
  1162. func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
  1163. cmd := NewStringSliceCmd(ctx, "hvals", key)
  1164. _ = c(ctx, cmd)
  1165. return cmd
  1166. }
  1167. // HRandField redis-server version >= 6.2.0.
  1168. func (c cmdable) HRandField(ctx context.Context, key string, count int, withValues bool) *StringSliceCmd {
  1169. args := make([]interface{}, 0, 4)
  1170. // Although count=0 is meaningless, redis accepts count=0.
  1171. args = append(args, "hrandfield", key, count)
  1172. if withValues {
  1173. args = append(args, "withvalues")
  1174. }
  1175. cmd := NewStringSliceCmd(ctx, args...)
  1176. _ = c(ctx, cmd)
  1177. return cmd
  1178. }
  1179. //------------------------------------------------------------------------------
  1180. func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
  1181. args := make([]interface{}, 1+len(keys)+1)
  1182. args[0] = "blpop"
  1183. for i, key := range keys {
  1184. args[1+i] = key
  1185. }
  1186. args[len(args)-1] = formatSec(ctx, timeout)
  1187. cmd := NewStringSliceCmd(ctx, args...)
  1188. cmd.setReadTimeout(timeout)
  1189. _ = c(ctx, cmd)
  1190. return cmd
  1191. }
  1192. func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
  1193. args := make([]interface{}, 1+len(keys)+1)
  1194. args[0] = "brpop"
  1195. for i, key := range keys {
  1196. args[1+i] = key
  1197. }
  1198. args[len(keys)+1] = formatSec(ctx, timeout)
  1199. cmd := NewStringSliceCmd(ctx, args...)
  1200. cmd.setReadTimeout(timeout)
  1201. _ = c(ctx, cmd)
  1202. return cmd
  1203. }
  1204. func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd {
  1205. cmd := NewStringCmd(
  1206. ctx,
  1207. "brpoplpush",
  1208. source,
  1209. destination,
  1210. formatSec(ctx, timeout),
  1211. )
  1212. cmd.setReadTimeout(timeout)
  1213. _ = c(ctx, cmd)
  1214. return cmd
  1215. }
  1216. func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd {
  1217. cmd := NewStringCmd(ctx, "lindex", key, index)
  1218. _ = c(ctx, cmd)
  1219. return cmd
  1220. }
  1221. func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd {
  1222. cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value)
  1223. _ = c(ctx, cmd)
  1224. return cmd
  1225. }
  1226. func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
  1227. cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value)
  1228. _ = c(ctx, cmd)
  1229. return cmd
  1230. }
  1231. func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
  1232. cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value)
  1233. _ = c(ctx, cmd)
  1234. return cmd
  1235. }
  1236. func (c cmdable) LLen(ctx context.Context, key string) *IntCmd {
  1237. cmd := NewIntCmd(ctx, "llen", key)
  1238. _ = c(ctx, cmd)
  1239. return cmd
  1240. }
  1241. func (c cmdable) LPop(ctx context.Context, key string) *StringCmd {
  1242. cmd := NewStringCmd(ctx, "lpop", key)
  1243. _ = c(ctx, cmd)
  1244. return cmd
  1245. }
  1246. func (c cmdable) LPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
  1247. cmd := NewStringSliceCmd(ctx, "lpop", key, count)
  1248. _ = c(ctx, cmd)
  1249. return cmd
  1250. }
  1251. type LPosArgs struct {
  1252. Rank, MaxLen int64
  1253. }
  1254. func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd {
  1255. args := []interface{}{"lpos", key, value}
  1256. if a.Rank != 0 {
  1257. args = append(args, "rank", a.Rank)
  1258. }
  1259. if a.MaxLen != 0 {
  1260. args = append(args, "maxlen", a.MaxLen)
  1261. }
  1262. cmd := NewIntCmd(ctx, args...)
  1263. _ = c(ctx, cmd)
  1264. return cmd
  1265. }
  1266. func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd {
  1267. args := []interface{}{"lpos", key, value, "count", count}
  1268. if a.Rank != 0 {
  1269. args = append(args, "rank", a.Rank)
  1270. }
  1271. if a.MaxLen != 0 {
  1272. args = append(args, "maxlen", a.MaxLen)
  1273. }
  1274. cmd := NewIntSliceCmd(ctx, args...)
  1275. _ = c(ctx, cmd)
  1276. return cmd
  1277. }
  1278. func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
  1279. args := make([]interface{}, 2, 2+len(values))
  1280. args[0] = "lpush"
  1281. args[1] = key
  1282. args = appendArgs(args, values)
  1283. cmd := NewIntCmd(ctx, args...)
  1284. _ = c(ctx, cmd)
  1285. return cmd
  1286. }
  1287. func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
  1288. args := make([]interface{}, 2, 2+len(values))
  1289. args[0] = "lpushx"
  1290. args[1] = key
  1291. args = appendArgs(args, values)
  1292. cmd := NewIntCmd(ctx, args...)
  1293. _ = c(ctx, cmd)
  1294. return cmd
  1295. }
  1296. func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
  1297. cmd := NewStringSliceCmd(
  1298. ctx,
  1299. "lrange",
  1300. key,
  1301. start,
  1302. stop,
  1303. )
  1304. _ = c(ctx, cmd)
  1305. return cmd
  1306. }
  1307. func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd {
  1308. cmd := NewIntCmd(ctx, "lrem", key, count, value)
  1309. _ = c(ctx, cmd)
  1310. return cmd
  1311. }
  1312. func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd {
  1313. cmd := NewStatusCmd(ctx, "lset", key, index, value)
  1314. _ = c(ctx, cmd)
  1315. return cmd
  1316. }
  1317. func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd {
  1318. cmd := NewStatusCmd(
  1319. ctx,
  1320. "ltrim",
  1321. key,
  1322. start,
  1323. stop,
  1324. )
  1325. _ = c(ctx, cmd)
  1326. return cmd
  1327. }
  1328. func (c cmdable) RPop(ctx context.Context, key string) *StringCmd {
  1329. cmd := NewStringCmd(ctx, "rpop", key)
  1330. _ = c(ctx, cmd)
  1331. return cmd
  1332. }
  1333. func (c cmdable) RPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
  1334. cmd := NewStringSliceCmd(ctx, "rpop", key, count)
  1335. _ = c(ctx, cmd)
  1336. return cmd
  1337. }
  1338. func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd {
  1339. cmd := NewStringCmd(ctx, "rpoplpush", source, destination)
  1340. _ = c(ctx, cmd)
  1341. return cmd
  1342. }
  1343. func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
  1344. args := make([]interface{}, 2, 2+len(values))
  1345. args[0] = "rpush"
  1346. args[1] = key
  1347. args = appendArgs(args, values)
  1348. cmd := NewIntCmd(ctx, args...)
  1349. _ = c(ctx, cmd)
  1350. return cmd
  1351. }
  1352. func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
  1353. args := make([]interface{}, 2, 2+len(values))
  1354. args[0] = "rpushx"
  1355. args[1] = key
  1356. args = appendArgs(args, values)
  1357. cmd := NewIntCmd(ctx, args...)
  1358. _ = c(ctx, cmd)
  1359. return cmd
  1360. }
  1361. func (c cmdable) LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd {
  1362. cmd := NewStringCmd(ctx, "lmove", source, destination, srcpos, destpos)
  1363. _ = c(ctx, cmd)
  1364. return cmd
  1365. }
  1366. func (c cmdable) BLMove(
  1367. ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration,
  1368. ) *StringCmd {
  1369. cmd := NewStringCmd(ctx, "blmove", source, destination, srcpos, destpos, formatSec(ctx, timeout))
  1370. cmd.setReadTimeout(timeout)
  1371. _ = c(ctx, cmd)
  1372. return cmd
  1373. }
  1374. //------------------------------------------------------------------------------
  1375. func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
  1376. args := make([]interface{}, 2, 2+len(members))
  1377. args[0] = "sadd"
  1378. args[1] = key
  1379. args = appendArgs(args, members)
  1380. cmd := NewIntCmd(ctx, args...)
  1381. _ = c(ctx, cmd)
  1382. return cmd
  1383. }
  1384. func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
  1385. cmd := NewIntCmd(ctx, "scard", key)
  1386. _ = c(ctx, cmd)
  1387. return cmd
  1388. }
  1389. func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
  1390. args := make([]interface{}, 1+len(keys))
  1391. args[0] = "sdiff"
  1392. for i, key := range keys {
  1393. args[1+i] = key
  1394. }
  1395. cmd := NewStringSliceCmd(ctx, args...)
  1396. _ = c(ctx, cmd)
  1397. return cmd
  1398. }
  1399. func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
  1400. args := make([]interface{}, 2+len(keys))
  1401. args[0] = "sdiffstore"
  1402. args[1] = destination
  1403. for i, key := range keys {
  1404. args[2+i] = key
  1405. }
  1406. cmd := NewIntCmd(ctx, args...)
  1407. _ = c(ctx, cmd)
  1408. return cmd
  1409. }
  1410. func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
  1411. args := make([]interface{}, 1+len(keys))
  1412. args[0] = "sinter"
  1413. for i, key := range keys {
  1414. args[1+i] = key
  1415. }
  1416. cmd := NewStringSliceCmd(ctx, args...)
  1417. _ = c(ctx, cmd)
  1418. return cmd
  1419. }
  1420. func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
  1421. args := make([]interface{}, 2+len(keys))
  1422. args[0] = "sinterstore"
  1423. args[1] = destination
  1424. for i, key := range keys {
  1425. args[2+i] = key
  1426. }
  1427. cmd := NewIntCmd(ctx, args...)
  1428. _ = c(ctx, cmd)
  1429. return cmd
  1430. }
  1431. func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
  1432. cmd := NewBoolCmd(ctx, "sismember", key, member)
  1433. _ = c(ctx, cmd)
  1434. return cmd
  1435. }
  1436. // SMIsMember Redis `SMISMEMBER key member [member ...]` command.
  1437. func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd {
  1438. args := make([]interface{}, 2, 2+len(members))
  1439. args[0] = "smismember"
  1440. args[1] = key
  1441. args = appendArgs(args, members)
  1442. cmd := NewBoolSliceCmd(ctx, args...)
  1443. _ = c(ctx, cmd)
  1444. return cmd
  1445. }
  1446. // SMembers Redis `SMEMBERS key` command output as a slice.
  1447. func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
  1448. cmd := NewStringSliceCmd(ctx, "smembers", key)
  1449. _ = c(ctx, cmd)
  1450. return cmd
  1451. }
  1452. // SMembersMap Redis `SMEMBERS key` command output as a map.
  1453. func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
  1454. cmd := NewStringStructMapCmd(ctx, "smembers", key)
  1455. _ = c(ctx, cmd)
  1456. return cmd
  1457. }
  1458. func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
  1459. cmd := NewBoolCmd(ctx, "smove", source, destination, member)
  1460. _ = c(ctx, cmd)
  1461. return cmd
  1462. }
  1463. // SPop Redis `SPOP key` command.
  1464. func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
  1465. cmd := NewStringCmd(ctx, "spop", key)
  1466. _ = c(ctx, cmd)
  1467. return cmd
  1468. }
  1469. // SPopN Redis `SPOP key count` command.
  1470. func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
  1471. cmd := NewStringSliceCmd(ctx, "spop", key, count)
  1472. _ = c(ctx, cmd)
  1473. return cmd
  1474. }
  1475. // SRandMember Redis `SRANDMEMBER key` command.
  1476. func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
  1477. cmd := NewStringCmd(ctx, "srandmember", key)
  1478. _ = c(ctx, cmd)
  1479. return cmd
  1480. }
  1481. // SRandMemberN Redis `SRANDMEMBER key count` command.
  1482. func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
  1483. cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
  1484. _ = c(ctx, cmd)
  1485. return cmd
  1486. }
  1487. func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
  1488. args := make([]interface{}, 2, 2+len(members))
  1489. args[0] = "srem"
  1490. args[1] = key
  1491. args = appendArgs(args, members)
  1492. cmd := NewIntCmd(ctx, args...)
  1493. _ = c(ctx, cmd)
  1494. return cmd
  1495. }
  1496. func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
  1497. args := make([]interface{}, 1+len(keys))
  1498. args[0] = "sunion"
  1499. for i, key := range keys {
  1500. args[1+i] = key
  1501. }
  1502. cmd := NewStringSliceCmd(ctx, args...)
  1503. _ = c(ctx, cmd)
  1504. return cmd
  1505. }
  1506. func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
  1507. args := make([]interface{}, 2+len(keys))
  1508. args[0] = "sunionstore"
  1509. args[1] = destination
  1510. for i, key := range keys {
  1511. args[2+i] = key
  1512. }
  1513. cmd := NewIntCmd(ctx, args...)
  1514. _ = c(ctx, cmd)
  1515. return cmd
  1516. }
  1517. //------------------------------------------------------------------------------
  1518. // XAddArgs accepts values in the following formats:
  1519. // - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
  1520. // - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
  1521. // - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
  1522. //
  1523. // Note that map will not preserve the order of key-value pairs.
  1524. // MaxLen/MaxLenApprox and MinID are in conflict, only one of them can be used.
  1525. type XAddArgs struct {
  1526. Stream string
  1527. NoMkStream bool
  1528. MaxLen int64 // MAXLEN N
  1529. // Deprecated: use MaxLen+Approx, remove in v9.
  1530. MaxLenApprox int64 // MAXLEN ~ N
  1531. MinID string
  1532. // Approx causes MaxLen and MinID to use "~" matcher (instead of "=").
  1533. Approx bool
  1534. Limit int64
  1535. ID string
  1536. Values interface{}
  1537. }
  1538. // XAdd a.Limit has a bug, please confirm it and use it.
  1539. // issue: https://github.com/redis/redis/issues/9046
  1540. func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
  1541. args := make([]interface{}, 0, 11)
  1542. args = append(args, "xadd", a.Stream)
  1543. if a.NoMkStream {
  1544. args = append(args, "nomkstream")
  1545. }
  1546. switch {
  1547. case a.MaxLen > 0:
  1548. if a.Approx {
  1549. args = append(args, "maxlen", "~", a.MaxLen)
  1550. } else {
  1551. args = append(args, "maxlen", a.MaxLen)
  1552. }
  1553. case a.MaxLenApprox > 0:
  1554. // TODO remove in v9.
  1555. args = append(args, "maxlen", "~", a.MaxLenApprox)
  1556. case a.MinID != "":
  1557. if a.Approx {
  1558. args = append(args, "minid", "~", a.MinID)
  1559. } else {
  1560. args = append(args, "minid", a.MinID)
  1561. }
  1562. }
  1563. if a.Limit > 0 {
  1564. args = append(args, "limit", a.Limit)
  1565. }
  1566. if a.ID != "" {
  1567. args = append(args, a.ID)
  1568. } else {
  1569. args = append(args, "*")
  1570. }
  1571. args = appendArg(args, a.Values)
  1572. cmd := NewStringCmd(ctx, args...)
  1573. _ = c(ctx, cmd)
  1574. return cmd
  1575. }
  1576. func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
  1577. args := []interface{}{"xdel", stream}
  1578. for _, id := range ids {
  1579. args = append(args, id)
  1580. }
  1581. cmd := NewIntCmd(ctx, args...)
  1582. _ = c(ctx, cmd)
  1583. return cmd
  1584. }
  1585. func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
  1586. cmd := NewIntCmd(ctx, "xlen", stream)
  1587. _ = c(ctx, cmd)
  1588. return cmd
  1589. }
  1590. func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
  1591. cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
  1592. _ = c(ctx, cmd)
  1593. return cmd
  1594. }
  1595. func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
  1596. cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
  1597. _ = c(ctx, cmd)
  1598. return cmd
  1599. }
  1600. func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
  1601. cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
  1602. _ = c(ctx, cmd)
  1603. return cmd
  1604. }
  1605. func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
  1606. cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
  1607. _ = c(ctx, cmd)
  1608. return cmd
  1609. }
  1610. type XReadArgs struct {
  1611. Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
  1612. Count int64
  1613. Block time.Duration
  1614. }
  1615. func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
  1616. args := make([]interface{}, 0, 6+len(a.Streams))
  1617. args = append(args, "xread")
  1618. keyPos := int8(1)
  1619. if a.Count > 0 {
  1620. args = append(args, "count")
  1621. args = append(args, a.Count)
  1622. keyPos += 2
  1623. }
  1624. if a.Block >= 0 {
  1625. args = append(args, "block")
  1626. args = append(args, int64(a.Block/time.Millisecond))
  1627. keyPos += 2
  1628. }
  1629. args = append(args, "streams")
  1630. keyPos++
  1631. for _, s := range a.Streams {
  1632. args = append(args, s)
  1633. }
  1634. cmd := NewXStreamSliceCmd(ctx, args...)
  1635. if a.Block >= 0 {
  1636. cmd.setReadTimeout(a.Block)
  1637. }
  1638. cmd.SetFirstKeyPos(keyPos)
  1639. _ = c(ctx, cmd)
  1640. return cmd
  1641. }
  1642. func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
  1643. return c.XRead(ctx, &XReadArgs{
  1644. Streams: streams,
  1645. Block: -1,
  1646. })
  1647. }
  1648. func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
  1649. cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
  1650. _ = c(ctx, cmd)
  1651. return cmd
  1652. }
  1653. func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
  1654. cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
  1655. _ = c(ctx, cmd)
  1656. return cmd
  1657. }
  1658. func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
  1659. cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
  1660. _ = c(ctx, cmd)
  1661. return cmd
  1662. }
  1663. func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
  1664. cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
  1665. _ = c(ctx, cmd)
  1666. return cmd
  1667. }
  1668. func (c cmdable) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
  1669. cmd := NewIntCmd(ctx, "xgroup", "createconsumer", stream, group, consumer)
  1670. _ = c(ctx, cmd)
  1671. return cmd
  1672. }
  1673. func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
  1674. cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
  1675. _ = c(ctx, cmd)
  1676. return cmd
  1677. }
  1678. type XReadGroupArgs struct {
  1679. Group string
  1680. Consumer string
  1681. Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
  1682. Count int64
  1683. Block time.Duration
  1684. NoAck bool
  1685. }
  1686. func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
  1687. args := make([]interface{}, 0, 10+len(a.Streams))
  1688. args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
  1689. keyPos := int8(4)
  1690. if a.Count > 0 {
  1691. args = append(args, "count", a.Count)
  1692. keyPos += 2
  1693. }
  1694. if a.Block >= 0 {
  1695. args = append(args, "block", int64(a.Block/time.Millisecond))
  1696. keyPos += 2
  1697. }
  1698. if a.NoAck {
  1699. args = append(args, "noack")
  1700. keyPos++
  1701. }
  1702. args = append(args, "streams")
  1703. keyPos++
  1704. for _, s := range a.Streams {
  1705. args = append(args, s)
  1706. }
  1707. cmd := NewXStreamSliceCmd(ctx, args...)
  1708. if a.Block >= 0 {
  1709. cmd.setReadTimeout(a.Block)
  1710. }
  1711. cmd.SetFirstKeyPos(keyPos)
  1712. _ = c(ctx, cmd)
  1713. return cmd
  1714. }
  1715. func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
  1716. args := []interface{}{"xack", stream, group}
  1717. for _, id := range ids {
  1718. args = append(args, id)
  1719. }
  1720. cmd := NewIntCmd(ctx, args...)
  1721. _ = c(ctx, cmd)
  1722. return cmd
  1723. }
  1724. func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
  1725. cmd := NewXPendingCmd(ctx, "xpending", stream, group)
  1726. _ = c(ctx, cmd)
  1727. return cmd
  1728. }
  1729. type XPendingExtArgs struct {
  1730. Stream string
  1731. Group string
  1732. Idle time.Duration
  1733. Start string
  1734. End string
  1735. Count int64
  1736. Consumer string
  1737. }
  1738. func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
  1739. args := make([]interface{}, 0, 9)
  1740. args = append(args, "xpending", a.Stream, a.Group)
  1741. if a.Idle != 0 {
  1742. args = append(args, "idle", formatMs(ctx, a.Idle))
  1743. }
  1744. args = append(args, a.Start, a.End, a.Count)
  1745. if a.Consumer != "" {
  1746. args = append(args, a.Consumer)
  1747. }
  1748. cmd := NewXPendingExtCmd(ctx, args...)
  1749. _ = c(ctx, cmd)
  1750. return cmd
  1751. }
  1752. type XAutoClaimArgs struct {
  1753. Stream string
  1754. Group string
  1755. MinIdle time.Duration
  1756. Start string
  1757. Count int64
  1758. Consumer string
  1759. }
  1760. func (c cmdable) XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd {
  1761. args := xAutoClaimArgs(ctx, a)
  1762. cmd := NewXAutoClaimCmd(ctx, args...)
  1763. _ = c(ctx, cmd)
  1764. return cmd
  1765. }
  1766. func (c cmdable) XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd {
  1767. args := xAutoClaimArgs(ctx, a)
  1768. args = append(args, "justid")
  1769. cmd := NewXAutoClaimJustIDCmd(ctx, args...)
  1770. _ = c(ctx, cmd)
  1771. return cmd
  1772. }
  1773. func xAutoClaimArgs(ctx context.Context, a *XAutoClaimArgs) []interface{} {
  1774. args := make([]interface{}, 0, 8)
  1775. args = append(args, "xautoclaim", a.Stream, a.Group, a.Consumer, formatMs(ctx, a.MinIdle), a.Start)
  1776. if a.Count > 0 {
  1777. args = append(args, "count", a.Count)
  1778. }
  1779. return args
  1780. }
  1781. type XClaimArgs struct {
  1782. Stream string
  1783. Group string
  1784. Consumer string
  1785. MinIdle time.Duration
  1786. Messages []string
  1787. }
  1788. func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
  1789. args := xClaimArgs(a)
  1790. cmd := NewXMessageSliceCmd(ctx, args...)
  1791. _ = c(ctx, cmd)
  1792. return cmd
  1793. }
  1794. func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
  1795. args := xClaimArgs(a)
  1796. args = append(args, "justid")
  1797. cmd := NewStringSliceCmd(ctx, args...)
  1798. _ = c(ctx, cmd)
  1799. return cmd
  1800. }
  1801. func xClaimArgs(a *XClaimArgs) []interface{} {
  1802. args := make([]interface{}, 0, 5+len(a.Messages))
  1803. args = append(args,
  1804. "xclaim",
  1805. a.Stream,
  1806. a.Group, a.Consumer,
  1807. int64(a.MinIdle/time.Millisecond))
  1808. for _, id := range a.Messages {
  1809. args = append(args, id)
  1810. }
  1811. return args
  1812. }
  1813. // xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default).
  1814. // example:
  1815. // XTRIM key MAXLEN/MINID threshold LIMIT limit.
  1816. // XTRIM key MAXLEN/MINID ~ threshold LIMIT limit.
  1817. // The redis-server version is lower than 6.2, please set limit to 0.
  1818. func (c cmdable) xTrim(
  1819. ctx context.Context, key, strategy string,
  1820. approx bool, threshold interface{}, limit int64,
  1821. ) *IntCmd {
  1822. args := make([]interface{}, 0, 7)
  1823. args = append(args, "xtrim", key, strategy)
  1824. if approx {
  1825. args = append(args, "~")
  1826. }
  1827. args = append(args, threshold)
  1828. if limit > 0 {
  1829. args = append(args, "limit", limit)
  1830. }
  1831. cmd := NewIntCmd(ctx, args...)
  1832. _ = c(ctx, cmd)
  1833. return cmd
  1834. }
  1835. // Deprecated: use XTrimMaxLen, remove in v9.
  1836. func (c cmdable) XTrim(ctx context.Context, key string, maxLen int64) *IntCmd {
  1837. return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
  1838. }
  1839. // Deprecated: use XTrimMaxLenApprox, remove in v9.
  1840. func (c cmdable) XTrimApprox(ctx context.Context, key string, maxLen int64) *IntCmd {
  1841. return c.xTrim(ctx, key, "maxlen", true, maxLen, 0)
  1842. }
  1843. // XTrimMaxLen No `~` rules are used, `limit` cannot be used.
  1844. // cmd: XTRIM key MAXLEN maxLen
  1845. func (c cmdable) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd {
  1846. return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
  1847. }
  1848. // XTrimMaxLenApprox LIMIT has a bug, please confirm it and use it.
  1849. // issue: https://github.com/redis/redis/issues/9046
  1850. // cmd: XTRIM key MAXLEN ~ maxLen LIMIT limit
  1851. func (c cmdable) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd {
  1852. return c.xTrim(ctx, key, "maxlen", true, maxLen, limit)
  1853. }
  1854. // XTrimMinID No `~` rules are used, `limit` cannot be used.
  1855. // cmd: XTRIM key MINID minID
  1856. func (c cmdable) XTrimMinID(ctx context.Context, key string, minID string) *IntCmd {
  1857. return c.xTrim(ctx, key, "minid", false, minID, 0)
  1858. }
  1859. // XTrimMinIDApprox LIMIT has a bug, please confirm it and use it.
  1860. // issue: https://github.com/redis/redis/issues/9046
  1861. // cmd: XTRIM key MINID ~ minID LIMIT limit
  1862. func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd {
  1863. return c.xTrim(ctx, key, "minid", true, minID, limit)
  1864. }
  1865. func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd {
  1866. cmd := NewXInfoConsumersCmd(ctx, key, group)
  1867. _ = c(ctx, cmd)
  1868. return cmd
  1869. }
  1870. func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
  1871. cmd := NewXInfoGroupsCmd(ctx, key)
  1872. _ = c(ctx, cmd)
  1873. return cmd
  1874. }
  1875. func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
  1876. cmd := NewXInfoStreamCmd(ctx, key)
  1877. _ = c(ctx, cmd)
  1878. return cmd
  1879. }
  1880. // XInfoStreamFull XINFO STREAM FULL [COUNT count]
  1881. // redis-server >= 6.0.
  1882. func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd {
  1883. args := make([]interface{}, 0, 6)
  1884. args = append(args, "xinfo", "stream", key, "full")
  1885. if count > 0 {
  1886. args = append(args, "count", count)
  1887. }
  1888. cmd := NewXInfoStreamFullCmd(ctx, args...)
  1889. _ = c(ctx, cmd)
  1890. return cmd
  1891. }
  1892. //------------------------------------------------------------------------------
  1893. // Z represents sorted set member.
  1894. type Z struct {
  1895. Score float64
  1896. Member interface{}
  1897. }
  1898. // ZWithKey represents sorted set member including the name of the key where it was popped.
  1899. type ZWithKey struct {
  1900. Z
  1901. Key string
  1902. }
  1903. // ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore.
  1904. type ZStore struct {
  1905. Keys []string
  1906. Weights []float64
  1907. // Can be SUM, MIN or MAX.
  1908. Aggregate string
  1909. }
  1910. func (z ZStore) len() (n int) {
  1911. n = len(z.Keys)
  1912. if len(z.Weights) > 0 {
  1913. n += 1 + len(z.Weights)
  1914. }
  1915. if z.Aggregate != "" {
  1916. n += 2
  1917. }
  1918. return n
  1919. }
  1920. func (z ZStore) appendArgs(args []interface{}) []interface{} {
  1921. for _, key := range z.Keys {
  1922. args = append(args, key)
  1923. }
  1924. if len(z.Weights) > 0 {
  1925. args = append(args, "weights")
  1926. for _, weights := range z.Weights {
  1927. args = append(args, weights)
  1928. }
  1929. }
  1930. if z.Aggregate != "" {
  1931. args = append(args, "aggregate", z.Aggregate)
  1932. }
  1933. return args
  1934. }
  1935. // BZPopMax Redis `BZPOPMAX key [key ...] timeout` command.
  1936. func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
  1937. args := make([]interface{}, 1+len(keys)+1)
  1938. args[0] = "bzpopmax"
  1939. for i, key := range keys {
  1940. args[1+i] = key
  1941. }
  1942. args[len(args)-1] = formatSec(ctx, timeout)
  1943. cmd := NewZWithKeyCmd(ctx, args...)
  1944. cmd.setReadTimeout(timeout)
  1945. _ = c(ctx, cmd)
  1946. return cmd
  1947. }
  1948. // BZPopMin Redis `BZPOPMIN key [key ...] timeout` command.
  1949. func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
  1950. args := make([]interface{}, 1+len(keys)+1)
  1951. args[0] = "bzpopmin"
  1952. for i, key := range keys {
  1953. args[1+i] = key
  1954. }
  1955. args[len(args)-1] = formatSec(ctx, timeout)
  1956. cmd := NewZWithKeyCmd(ctx, args...)
  1957. cmd.setReadTimeout(timeout)
  1958. _ = c(ctx, cmd)
  1959. return cmd
  1960. }
  1961. // ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
  1962. type ZAddArgs struct {
  1963. NX bool
  1964. XX bool
  1965. LT bool
  1966. GT bool
  1967. Ch bool
  1968. Members []Z
  1969. }
  1970. func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} {
  1971. a := make([]interface{}, 0, 6+2*len(args.Members))
  1972. a = append(a, "zadd", key)
  1973. // The GT, LT and NX options are mutually exclusive.
  1974. if args.NX {
  1975. a = append(a, "nx")
  1976. } else {
  1977. if args.XX {
  1978. a = append(a, "xx")
  1979. }
  1980. if args.GT {
  1981. a = append(a, "gt")
  1982. } else if args.LT {
  1983. a = append(a, "lt")
  1984. }
  1985. }
  1986. if args.Ch {
  1987. a = append(a, "ch")
  1988. }
  1989. if incr {
  1990. a = append(a, "incr")
  1991. }
  1992. for _, m := range args.Members {
  1993. a = append(a, m.Score)
  1994. a = append(a, m.Member)
  1995. }
  1996. return a
  1997. }
  1998. func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd {
  1999. cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
  2000. _ = c(ctx, cmd)
  2001. return cmd
  2002. }
  2003. func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd {
  2004. cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...)
  2005. _ = c(ctx, cmd)
  2006. return cmd
  2007. }
  2008. // TODO: Compatible with v8 api, will be removed in v9.
  2009. func (c cmdable) zAdd(ctx context.Context, key string, args ZAddArgs, members ...*Z) *IntCmd {
  2010. args.Members = make([]Z, len(members))
  2011. for i, m := range members {
  2012. args.Members[i] = *m
  2013. }
  2014. cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
  2015. _ = c(ctx, cmd)
  2016. return cmd
  2017. }
  2018. // ZAdd Redis `ZADD key score member [score member ...]` command.
  2019. func (c cmdable) ZAdd(ctx context.Context, key string, members ...*Z) *IntCmd {
  2020. return c.zAdd(ctx, key, ZAddArgs{}, members...)
  2021. }
  2022. // ZAddNX Redis `ZADD key NX score member [score member ...]` command.
  2023. func (c cmdable) ZAddNX(ctx context.Context, key string, members ...*Z) *IntCmd {
  2024. return c.zAdd(ctx, key, ZAddArgs{
  2025. NX: true,
  2026. }, members...)
  2027. }
  2028. // ZAddXX Redis `ZADD key XX score member [score member ...]` command.
  2029. func (c cmdable) ZAddXX(ctx context.Context, key string, members ...*Z) *IntCmd {
  2030. return c.zAdd(ctx, key, ZAddArgs{
  2031. XX: true,
  2032. }, members...)
  2033. }
  2034. // ZAddCh Redis `ZADD key CH score member [score member ...]` command.
  2035. // Deprecated: Use
  2036. // client.ZAddArgs(ctx, ZAddArgs{
  2037. // Ch: true,
  2038. // Members: []Z,
  2039. // })
  2040. // remove in v9.
  2041. func (c cmdable) ZAddCh(ctx context.Context, key string, members ...*Z) *IntCmd {
  2042. return c.zAdd(ctx, key, ZAddArgs{
  2043. Ch: true,
  2044. }, members...)
  2045. }
  2046. // ZAddNXCh Redis `ZADD key NX CH score member [score member ...]` command.
  2047. // Deprecated: Use
  2048. // client.ZAddArgs(ctx, ZAddArgs{
  2049. // NX: true,
  2050. // Ch: true,
  2051. // Members: []Z,
  2052. // })
  2053. // remove in v9.
  2054. func (c cmdable) ZAddNXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
  2055. return c.zAdd(ctx, key, ZAddArgs{
  2056. NX: true,
  2057. Ch: true,
  2058. }, members...)
  2059. }
  2060. // ZAddXXCh Redis `ZADD key XX CH score member [score member ...]` command.
  2061. // Deprecated: Use
  2062. // client.ZAddArgs(ctx, ZAddArgs{
  2063. // XX: true,
  2064. // Ch: true,
  2065. // Members: []Z,
  2066. // })
  2067. // remove in v9.
  2068. func (c cmdable) ZAddXXCh(ctx context.Context, key string, members ...*Z) *IntCmd {
  2069. return c.zAdd(ctx, key, ZAddArgs{
  2070. XX: true,
  2071. Ch: true,
  2072. }, members...)
  2073. }
  2074. // ZIncr Redis `ZADD key INCR score member` command.
  2075. // Deprecated: Use
  2076. // client.ZAddArgsIncr(ctx, ZAddArgs{
  2077. // Members: []Z,
  2078. // })
  2079. // remove in v9.
  2080. func (c cmdable) ZIncr(ctx context.Context, key string, member *Z) *FloatCmd {
  2081. return c.ZAddArgsIncr(ctx, key, ZAddArgs{
  2082. Members: []Z{*member},
  2083. })
  2084. }
  2085. // ZIncrNX Redis `ZADD key NX INCR score member` command.
  2086. // Deprecated: Use
  2087. // client.ZAddArgsIncr(ctx, ZAddArgs{
  2088. // NX: true,
  2089. // Members: []Z,
  2090. // })
  2091. // remove in v9.
  2092. func (c cmdable) ZIncrNX(ctx context.Context, key string, member *Z) *FloatCmd {
  2093. return c.ZAddArgsIncr(ctx, key, ZAddArgs{
  2094. NX: true,
  2095. Members: []Z{*member},
  2096. })
  2097. }
  2098. // ZIncrXX Redis `ZADD key XX INCR score member` command.
  2099. // Deprecated: Use
  2100. // client.ZAddArgsIncr(ctx, ZAddArgs{
  2101. // XX: true,
  2102. // Members: []Z,
  2103. // })
  2104. // remove in v9.
  2105. func (c cmdable) ZIncrXX(ctx context.Context, key string, member *Z) *FloatCmd {
  2106. return c.ZAddArgsIncr(ctx, key, ZAddArgs{
  2107. XX: true,
  2108. Members: []Z{*member},
  2109. })
  2110. }
  2111. func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
  2112. cmd := NewIntCmd(ctx, "zcard", key)
  2113. _ = c(ctx, cmd)
  2114. return cmd
  2115. }
  2116. func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
  2117. cmd := NewIntCmd(ctx, "zcount", key, min, max)
  2118. _ = c(ctx, cmd)
  2119. return cmd
  2120. }
  2121. func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
  2122. cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
  2123. _ = c(ctx, cmd)
  2124. return cmd
  2125. }
  2126. func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
  2127. cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
  2128. _ = c(ctx, cmd)
  2129. return cmd
  2130. }
  2131. func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
  2132. args := make([]interface{}, 0, 3+store.len())
  2133. args = append(args, "zinterstore", destination, len(store.Keys))
  2134. args = store.appendArgs(args)
  2135. cmd := NewIntCmd(ctx, args...)
  2136. cmd.SetFirstKeyPos(3)
  2137. _ = c(ctx, cmd)
  2138. return cmd
  2139. }
  2140. func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd {
  2141. args := make([]interface{}, 0, 2+store.len())
  2142. args = append(args, "zinter", len(store.Keys))
  2143. args = store.appendArgs(args)
  2144. cmd := NewStringSliceCmd(ctx, args...)
  2145. cmd.SetFirstKeyPos(2)
  2146. _ = c(ctx, cmd)
  2147. return cmd
  2148. }
  2149. func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd {
  2150. args := make([]interface{}, 0, 3+store.len())
  2151. args = append(args, "zinter", len(store.Keys))
  2152. args = store.appendArgs(args)
  2153. args = append(args, "withscores")
  2154. cmd := NewZSliceCmd(ctx, args...)
  2155. cmd.SetFirstKeyPos(2)
  2156. _ = c(ctx, cmd)
  2157. return cmd
  2158. }
  2159. func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
  2160. args := make([]interface{}, 2+len(members))
  2161. args[0] = "zmscore"
  2162. args[1] = key
  2163. for i, member := range members {
  2164. args[2+i] = member
  2165. }
  2166. cmd := NewFloatSliceCmd(ctx, args...)
  2167. _ = c(ctx, cmd)
  2168. return cmd
  2169. }
  2170. func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
  2171. args := []interface{}{
  2172. "zpopmax",
  2173. key,
  2174. }
  2175. switch len(count) {
  2176. case 0:
  2177. break
  2178. case 1:
  2179. args = append(args, count[0])
  2180. default:
  2181. panic("too many arguments")
  2182. }
  2183. cmd := NewZSliceCmd(ctx, args...)
  2184. _ = c(ctx, cmd)
  2185. return cmd
  2186. }
  2187. func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
  2188. args := []interface{}{
  2189. "zpopmin",
  2190. key,
  2191. }
  2192. switch len(count) {
  2193. case 0:
  2194. break
  2195. case 1:
  2196. args = append(args, count[0])
  2197. default:
  2198. panic("too many arguments")
  2199. }
  2200. cmd := NewZSliceCmd(ctx, args...)
  2201. _ = c(ctx, cmd)
  2202. return cmd
  2203. }
  2204. // ZRangeArgs is all the options of the ZRange command.
  2205. // In version> 6.2.0, you can replace the(cmd):
  2206. // ZREVRANGE,
  2207. // ZRANGEBYSCORE,
  2208. // ZREVRANGEBYSCORE,
  2209. // ZRANGEBYLEX,
  2210. // ZREVRANGEBYLEX.
  2211. // Please pay attention to your redis-server version.
  2212. //
  2213. // Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher.
  2214. type ZRangeArgs struct {
  2215. Key string
  2216. // When the ByScore option is provided, the open interval(exclusive) can be set.
  2217. // By default, the score intervals specified by <Start> and <Stop> are closed (inclusive).
  2218. // It is similar to the deprecated(6.2.0+) ZRangeByScore command.
  2219. // For example:
  2220. // ZRangeArgs{
  2221. // Key: "example-key",
  2222. // Start: "(3",
  2223. // Stop: 8,
  2224. // ByScore: true,
  2225. // }
  2226. // cmd: "ZRange example-key (3 8 ByScore" (3 < score <= 8).
  2227. //
  2228. // For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command.
  2229. // You can set the <Start> and <Stop> options as follows:
  2230. // ZRangeArgs{
  2231. // Key: "example-key",
  2232. // Start: "[abc",
  2233. // Stop: "(def",
  2234. // ByLex: true,
  2235. // }
  2236. // cmd: "ZRange example-key [abc (def ByLex"
  2237. //
  2238. // For normal cases (ByScore==false && ByLex==false), <Start> and <Stop> should be set to the index range (int).
  2239. // You can read the documentation for more information: https://redis.io/commands/zrange
  2240. Start interface{}
  2241. Stop interface{}
  2242. // The ByScore and ByLex options are mutually exclusive.
  2243. ByScore bool
  2244. ByLex bool
  2245. Rev bool
  2246. // limit offset count.
  2247. Offset int64
  2248. Count int64
  2249. }
  2250. func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} {
  2251. // For Rev+ByScore/ByLex, we need to adjust the position of <Start> and <Stop>.
  2252. if z.Rev && (z.ByScore || z.ByLex) {
  2253. args = append(args, z.Key, z.Stop, z.Start)
  2254. } else {
  2255. args = append(args, z.Key, z.Start, z.Stop)
  2256. }
  2257. if z.ByScore {
  2258. args = append(args, "byscore")
  2259. } else if z.ByLex {
  2260. args = append(args, "bylex")
  2261. }
  2262. if z.Rev {
  2263. args = append(args, "rev")
  2264. }
  2265. if z.Offset != 0 || z.Count != 0 {
  2266. args = append(args, "limit", z.Offset, z.Count)
  2267. }
  2268. return args
  2269. }
  2270. func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd {
  2271. args := make([]interface{}, 0, 9)
  2272. args = append(args, "zrange")
  2273. args = z.appendArgs(args)
  2274. cmd := NewStringSliceCmd(ctx, args...)
  2275. _ = c(ctx, cmd)
  2276. return cmd
  2277. }
  2278. func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd {
  2279. args := make([]interface{}, 0, 10)
  2280. args = append(args, "zrange")
  2281. args = z.appendArgs(args)
  2282. args = append(args, "withscores")
  2283. cmd := NewZSliceCmd(ctx, args...)
  2284. _ = c(ctx, cmd)
  2285. return cmd
  2286. }
  2287. func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
  2288. return c.ZRangeArgs(ctx, ZRangeArgs{
  2289. Key: key,
  2290. Start: start,
  2291. Stop: stop,
  2292. })
  2293. }
  2294. func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
  2295. return c.ZRangeArgsWithScores(ctx, ZRangeArgs{
  2296. Key: key,
  2297. Start: start,
  2298. Stop: stop,
  2299. })
  2300. }
  2301. type ZRangeBy struct {
  2302. Min, Max string
  2303. Offset, Count int64
  2304. }
  2305. func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
  2306. args := []interface{}{zcmd, key, opt.Min, opt.Max}
  2307. if withScores {
  2308. args = append(args, "withscores")
  2309. }
  2310. if opt.Offset != 0 || opt.Count != 0 {
  2311. args = append(
  2312. args,
  2313. "limit",
  2314. opt.Offset,
  2315. opt.Count,
  2316. )
  2317. }
  2318. cmd := NewStringSliceCmd(ctx, args...)
  2319. _ = c(ctx, cmd)
  2320. return cmd
  2321. }
  2322. func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
  2323. return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
  2324. }
  2325. func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
  2326. return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
  2327. }
  2328. func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
  2329. args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
  2330. if opt.Offset != 0 || opt.Count != 0 {
  2331. args = append(
  2332. args,
  2333. "limit",
  2334. opt.Offset,
  2335. opt.Count,
  2336. )
  2337. }
  2338. cmd := NewZSliceCmd(ctx, args...)
  2339. _ = c(ctx, cmd)
  2340. return cmd
  2341. }
  2342. func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd {
  2343. args := make([]interface{}, 0, 10)
  2344. args = append(args, "zrangestore", dst)
  2345. args = z.appendArgs(args)
  2346. cmd := NewIntCmd(ctx, args...)
  2347. _ = c(ctx, cmd)
  2348. return cmd
  2349. }
  2350. func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
  2351. cmd := NewIntCmd(ctx, "zrank", key, member)
  2352. _ = c(ctx, cmd)
  2353. return cmd
  2354. }
  2355. func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
  2356. args := make([]interface{}, 2, 2+len(members))
  2357. args[0] = "zrem"
  2358. args[1] = key
  2359. args = appendArgs(args, members)
  2360. cmd := NewIntCmd(ctx, args...)
  2361. _ = c(ctx, cmd)
  2362. return cmd
  2363. }
  2364. func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
  2365. cmd := NewIntCmd(
  2366. ctx,
  2367. "zremrangebyrank",
  2368. key,
  2369. start,
  2370. stop,
  2371. )
  2372. _ = c(ctx, cmd)
  2373. return cmd
  2374. }
  2375. func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
  2376. cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
  2377. _ = c(ctx, cmd)
  2378. return cmd
  2379. }
  2380. func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
  2381. cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
  2382. _ = c(ctx, cmd)
  2383. return cmd
  2384. }
  2385. func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
  2386. cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
  2387. _ = c(ctx, cmd)
  2388. return cmd
  2389. }
  2390. func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
  2391. cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
  2392. _ = c(ctx, cmd)
  2393. return cmd
  2394. }
  2395. func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
  2396. args := []interface{}{zcmd, key, opt.Max, opt.Min}
  2397. if opt.Offset != 0 || opt.Count != 0 {
  2398. args = append(
  2399. args,
  2400. "limit",
  2401. opt.Offset,
  2402. opt.Count,
  2403. )
  2404. }
  2405. cmd := NewStringSliceCmd(ctx, args...)
  2406. _ = c(ctx, cmd)
  2407. return cmd
  2408. }
  2409. func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
  2410. return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
  2411. }
  2412. func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
  2413. return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
  2414. }
  2415. func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
  2416. args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
  2417. if opt.Offset != 0 || opt.Count != 0 {
  2418. args = append(
  2419. args,
  2420. "limit",
  2421. opt.Offset,
  2422. opt.Count,
  2423. )
  2424. }
  2425. cmd := NewZSliceCmd(ctx, args...)
  2426. _ = c(ctx, cmd)
  2427. return cmd
  2428. }
  2429. func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
  2430. cmd := NewIntCmd(ctx, "zrevrank", key, member)
  2431. _ = c(ctx, cmd)
  2432. return cmd
  2433. }
  2434. func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
  2435. cmd := NewFloatCmd(ctx, "zscore", key, member)
  2436. _ = c(ctx, cmd)
  2437. return cmd
  2438. }
  2439. func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd {
  2440. args := make([]interface{}, 0, 2+store.len())
  2441. args = append(args, "zunion", len(store.Keys))
  2442. args = store.appendArgs(args)
  2443. cmd := NewStringSliceCmd(ctx, args...)
  2444. cmd.SetFirstKeyPos(2)
  2445. _ = c(ctx, cmd)
  2446. return cmd
  2447. }
  2448. func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd {
  2449. args := make([]interface{}, 0, 3+store.len())
  2450. args = append(args, "zunion", len(store.Keys))
  2451. args = store.appendArgs(args)
  2452. args = append(args, "withscores")
  2453. cmd := NewZSliceCmd(ctx, args...)
  2454. cmd.SetFirstKeyPos(2)
  2455. _ = c(ctx, cmd)
  2456. return cmd
  2457. }
  2458. func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
  2459. args := make([]interface{}, 0, 3+store.len())
  2460. args = append(args, "zunionstore", dest, len(store.Keys))
  2461. args = store.appendArgs(args)
  2462. cmd := NewIntCmd(ctx, args...)
  2463. cmd.SetFirstKeyPos(3)
  2464. _ = c(ctx, cmd)
  2465. return cmd
  2466. }
  2467. // ZRandMember redis-server version >= 6.2.0.
  2468. func (c cmdable) ZRandMember(ctx context.Context, key string, count int, withScores bool) *StringSliceCmd {
  2469. args := make([]interface{}, 0, 4)
  2470. // Although count=0 is meaningless, redis accepts count=0.
  2471. args = append(args, "zrandmember", key, count)
  2472. if withScores {
  2473. args = append(args, "withscores")
  2474. }
  2475. cmd := NewStringSliceCmd(ctx, args...)
  2476. _ = c(ctx, cmd)
  2477. return cmd
  2478. }
  2479. // ZDiff redis-server version >= 6.2.0.
  2480. func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd {
  2481. args := make([]interface{}, 2+len(keys))
  2482. args[0] = "zdiff"
  2483. args[1] = len(keys)
  2484. for i, key := range keys {
  2485. args[i+2] = key
  2486. }
  2487. cmd := NewStringSliceCmd(ctx, args...)
  2488. cmd.SetFirstKeyPos(2)
  2489. _ = c(ctx, cmd)
  2490. return cmd
  2491. }
  2492. // ZDiffWithScores redis-server version >= 6.2.0.
  2493. func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd {
  2494. args := make([]interface{}, 3+len(keys))
  2495. args[0] = "zdiff"
  2496. args[1] = len(keys)
  2497. for i, key := range keys {
  2498. args[i+2] = key
  2499. }
  2500. args[len(keys)+2] = "withscores"
  2501. cmd := NewZSliceCmd(ctx, args...)
  2502. cmd.SetFirstKeyPos(2)
  2503. _ = c(ctx, cmd)
  2504. return cmd
  2505. }
  2506. // ZDiffStore redis-server version >=6.2.0.
  2507. func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
  2508. args := make([]interface{}, 0, 3+len(keys))
  2509. args = append(args, "zdiffstore", destination, len(keys))
  2510. for _, key := range keys {
  2511. args = append(args, key)
  2512. }
  2513. cmd := NewIntCmd(ctx, args...)
  2514. _ = c(ctx, cmd)
  2515. return cmd
  2516. }
  2517. //------------------------------------------------------------------------------
  2518. func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd {
  2519. args := make([]interface{}, 2, 2+len(els))
  2520. args[0] = "pfadd"
  2521. args[1] = key
  2522. args = appendArgs(args, els)
  2523. cmd := NewIntCmd(ctx, args...)
  2524. _ = c(ctx, cmd)
  2525. return cmd
  2526. }
  2527. func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
  2528. args := make([]interface{}, 1+len(keys))
  2529. args[0] = "pfcount"
  2530. for i, key := range keys {
  2531. args[1+i] = key
  2532. }
  2533. cmd := NewIntCmd(ctx, args...)
  2534. _ = c(ctx, cmd)
  2535. return cmd
  2536. }
  2537. func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd {
  2538. args := make([]interface{}, 2+len(keys))
  2539. args[0] = "pfmerge"
  2540. args[1] = dest
  2541. for i, key := range keys {
  2542. args[2+i] = key
  2543. }
  2544. cmd := NewStatusCmd(ctx, args...)
  2545. _ = c(ctx, cmd)
  2546. return cmd
  2547. }
  2548. //------------------------------------------------------------------------------
  2549. func (c cmdable) BgRewriteAOF(ctx context.Context) *StatusCmd {
  2550. cmd := NewStatusCmd(ctx, "bgrewriteaof")
  2551. _ = c(ctx, cmd)
  2552. return cmd
  2553. }
  2554. func (c cmdable) BgSave(ctx context.Context) *StatusCmd {
  2555. cmd := NewStatusCmd(ctx, "bgsave")
  2556. _ = c(ctx, cmd)
  2557. return cmd
  2558. }
  2559. func (c cmdable) ClientKill(ctx context.Context, ipPort string) *StatusCmd {
  2560. cmd := NewStatusCmd(ctx, "client", "kill", ipPort)
  2561. _ = c(ctx, cmd)
  2562. return cmd
  2563. }
  2564. // ClientKillByFilter is new style syntax, while the ClientKill is old
  2565. //
  2566. // CLIENT KILL <option> [value] ... <option> [value]
  2567. func (c cmdable) ClientKillByFilter(ctx context.Context, keys ...string) *IntCmd {
  2568. args := make([]interface{}, 2+len(keys))
  2569. args[0] = "client"
  2570. args[1] = "kill"
  2571. for i, key := range keys {
  2572. args[2+i] = key
  2573. }
  2574. cmd := NewIntCmd(ctx, args...)
  2575. _ = c(ctx, cmd)
  2576. return cmd
  2577. }
  2578. func (c cmdable) ClientList(ctx context.Context) *StringCmd {
  2579. cmd := NewStringCmd(ctx, "client", "list")
  2580. _ = c(ctx, cmd)
  2581. return cmd
  2582. }
  2583. func (c cmdable) ClientPause(ctx context.Context, dur time.Duration) *BoolCmd {
  2584. cmd := NewBoolCmd(ctx, "client", "pause", formatMs(ctx, dur))
  2585. _ = c(ctx, cmd)
  2586. return cmd
  2587. }
  2588. func (c cmdable) ClientID(ctx context.Context) *IntCmd {
  2589. cmd := NewIntCmd(ctx, "client", "id")
  2590. _ = c(ctx, cmd)
  2591. return cmd
  2592. }
  2593. func (c cmdable) ClientUnblock(ctx context.Context, id int64) *IntCmd {
  2594. cmd := NewIntCmd(ctx, "client", "unblock", id)
  2595. _ = c(ctx, cmd)
  2596. return cmd
  2597. }
  2598. func (c cmdable) ClientUnblockWithError(ctx context.Context, id int64) *IntCmd {
  2599. cmd := NewIntCmd(ctx, "client", "unblock", id, "error")
  2600. _ = c(ctx, cmd)
  2601. return cmd
  2602. }
  2603. func (c cmdable) ConfigGet(ctx context.Context, parameter string) *SliceCmd {
  2604. cmd := NewSliceCmd(ctx, "config", "get", parameter)
  2605. _ = c(ctx, cmd)
  2606. return cmd
  2607. }
  2608. func (c cmdable) ConfigResetStat(ctx context.Context) *StatusCmd {
  2609. cmd := NewStatusCmd(ctx, "config", "resetstat")
  2610. _ = c(ctx, cmd)
  2611. return cmd
  2612. }
  2613. func (c cmdable) ConfigSet(ctx context.Context, parameter, value string) *StatusCmd {
  2614. cmd := NewStatusCmd(ctx, "config", "set", parameter, value)
  2615. _ = c(ctx, cmd)
  2616. return cmd
  2617. }
  2618. func (c cmdable) ConfigRewrite(ctx context.Context) *StatusCmd {
  2619. cmd := NewStatusCmd(ctx, "config", "rewrite")
  2620. _ = c(ctx, cmd)
  2621. return cmd
  2622. }
  2623. func (c cmdable) DBSize(ctx context.Context) *IntCmd {
  2624. cmd := NewIntCmd(ctx, "dbsize")
  2625. _ = c(ctx, cmd)
  2626. return cmd
  2627. }
  2628. func (c cmdable) FlushAll(ctx context.Context) *StatusCmd {
  2629. cmd := NewStatusCmd(ctx, "flushall")
  2630. _ = c(ctx, cmd)
  2631. return cmd
  2632. }
  2633. func (c cmdable) FlushAllAsync(ctx context.Context) *StatusCmd {
  2634. cmd := NewStatusCmd(ctx, "flushall", "async")
  2635. _ = c(ctx, cmd)
  2636. return cmd
  2637. }
  2638. func (c cmdable) FlushDB(ctx context.Context) *StatusCmd {
  2639. cmd := NewStatusCmd(ctx, "flushdb")
  2640. _ = c(ctx, cmd)
  2641. return cmd
  2642. }
  2643. func (c cmdable) FlushDBAsync(ctx context.Context) *StatusCmd {
  2644. cmd := NewStatusCmd(ctx, "flushdb", "async")
  2645. _ = c(ctx, cmd)
  2646. return cmd
  2647. }
  2648. func (c cmdable) Info(ctx context.Context, section ...string) *StringCmd {
  2649. args := []interface{}{"info"}
  2650. if len(section) > 0 {
  2651. args = append(args, section[0])
  2652. }
  2653. cmd := NewStringCmd(ctx, args...)
  2654. _ = c(ctx, cmd)
  2655. return cmd
  2656. }
  2657. func (c cmdable) LastSave(ctx context.Context) *IntCmd {
  2658. cmd := NewIntCmd(ctx, "lastsave")
  2659. _ = c(ctx, cmd)
  2660. return cmd
  2661. }
  2662. func (c cmdable) Save(ctx context.Context) *StatusCmd {
  2663. cmd := NewStatusCmd(ctx, "save")
  2664. _ = c(ctx, cmd)
  2665. return cmd
  2666. }
  2667. func (c cmdable) shutdown(ctx context.Context, modifier string) *StatusCmd {
  2668. var args []interface{}
  2669. if modifier == "" {
  2670. args = []interface{}{"shutdown"}
  2671. } else {
  2672. args = []interface{}{"shutdown", modifier}
  2673. }
  2674. cmd := NewStatusCmd(ctx, args...)
  2675. _ = c(ctx, cmd)
  2676. if err := cmd.Err(); err != nil {
  2677. if err == io.EOF {
  2678. // Server quit as expected.
  2679. cmd.err = nil
  2680. }
  2681. } else {
  2682. // Server did not quit. String reply contains the reason.
  2683. cmd.err = errors.New(cmd.val)
  2684. cmd.val = ""
  2685. }
  2686. return cmd
  2687. }
  2688. func (c cmdable) Shutdown(ctx context.Context) *StatusCmd {
  2689. return c.shutdown(ctx, "")
  2690. }
  2691. func (c cmdable) ShutdownSave(ctx context.Context) *StatusCmd {
  2692. return c.shutdown(ctx, "save")
  2693. }
  2694. func (c cmdable) ShutdownNoSave(ctx context.Context) *StatusCmd {
  2695. return c.shutdown(ctx, "nosave")
  2696. }
  2697. func (c cmdable) SlaveOf(ctx context.Context, host, port string) *StatusCmd {
  2698. cmd := NewStatusCmd(ctx, "slaveof", host, port)
  2699. _ = c(ctx, cmd)
  2700. return cmd
  2701. }
  2702. func (c cmdable) SlowLogGet(ctx context.Context, num int64) *SlowLogCmd {
  2703. cmd := NewSlowLogCmd(context.Background(), "slowlog", "get", num)
  2704. _ = c(ctx, cmd)
  2705. return cmd
  2706. }
  2707. func (c cmdable) Sync(_ context.Context) {
  2708. panic("not implemented")
  2709. }
  2710. func (c cmdable) Time(ctx context.Context) *TimeCmd {
  2711. cmd := NewTimeCmd(ctx, "time")
  2712. _ = c(ctx, cmd)
  2713. return cmd
  2714. }
  2715. func (c cmdable) DebugObject(ctx context.Context, key string) *StringCmd {
  2716. cmd := NewStringCmd(ctx, "debug", "object", key)
  2717. _ = c(ctx, cmd)
  2718. return cmd
  2719. }
  2720. func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
  2721. cmd := NewStatusCmd(ctx, "readonly")
  2722. _ = c(ctx, cmd)
  2723. return cmd
  2724. }
  2725. func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
  2726. cmd := NewStatusCmd(ctx, "readwrite")
  2727. _ = c(ctx, cmd)
  2728. return cmd
  2729. }
  2730. func (c cmdable) MemoryUsage(ctx context.Context, key string, samples ...int) *IntCmd {
  2731. args := []interface{}{"memory", "usage", key}
  2732. if len(samples) > 0 {
  2733. if len(samples) != 1 {
  2734. panic("MemoryUsage expects single sample count")
  2735. }
  2736. args = append(args, "SAMPLES", samples[0])
  2737. }
  2738. cmd := NewIntCmd(ctx, args...)
  2739. cmd.SetFirstKeyPos(2)
  2740. _ = c(ctx, cmd)
  2741. return cmd
  2742. }
  2743. //------------------------------------------------------------------------------
  2744. func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
  2745. cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
  2746. cmdArgs[0] = "eval"
  2747. cmdArgs[1] = script
  2748. cmdArgs[2] = len(keys)
  2749. for i, key := range keys {
  2750. cmdArgs[3+i] = key
  2751. }
  2752. cmdArgs = appendArgs(cmdArgs, args)
  2753. cmd := NewCmd(ctx, cmdArgs...)
  2754. cmd.SetFirstKeyPos(3)
  2755. _ = c(ctx, cmd)
  2756. return cmd
  2757. }
  2758. func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
  2759. cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
  2760. cmdArgs[0] = "evalsha"
  2761. cmdArgs[1] = sha1
  2762. cmdArgs[2] = len(keys)
  2763. for i, key := range keys {
  2764. cmdArgs[3+i] = key
  2765. }
  2766. cmdArgs = appendArgs(cmdArgs, args)
  2767. cmd := NewCmd(ctx, cmdArgs...)
  2768. cmd.SetFirstKeyPos(3)
  2769. _ = c(ctx, cmd)
  2770. return cmd
  2771. }
  2772. func (c cmdable) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
  2773. args := make([]interface{}, 2+len(hashes))
  2774. args[0] = "script"
  2775. args[1] = "exists"
  2776. for i, hash := range hashes {
  2777. args[2+i] = hash
  2778. }
  2779. cmd := NewBoolSliceCmd(ctx, args...)
  2780. _ = c(ctx, cmd)
  2781. return cmd
  2782. }
  2783. func (c cmdable) ScriptFlush(ctx context.Context) *StatusCmd {
  2784. cmd := NewStatusCmd(ctx, "script", "flush")
  2785. _ = c(ctx, cmd)
  2786. return cmd
  2787. }
  2788. func (c cmdable) ScriptKill(ctx context.Context) *StatusCmd {
  2789. cmd := NewStatusCmd(ctx, "script", "kill")
  2790. _ = c(ctx, cmd)
  2791. return cmd
  2792. }
  2793. func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
  2794. cmd := NewStringCmd(ctx, "script", "load", script)
  2795. _ = c(ctx, cmd)
  2796. return cmd
  2797. }
  2798. //------------------------------------------------------------------------------
  2799. // Publish posts the message to the channel.
  2800. func (c cmdable) Publish(ctx context.Context, channel string, message interface{}) *IntCmd {
  2801. cmd := NewIntCmd(ctx, "publish", channel, message)
  2802. _ = c(ctx, cmd)
  2803. return cmd
  2804. }
  2805. func (c cmdable) PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd {
  2806. args := []interface{}{"pubsub", "channels"}
  2807. if pattern != "*" {
  2808. args = append(args, pattern)
  2809. }
  2810. cmd := NewStringSliceCmd(ctx, args...)
  2811. _ = c(ctx, cmd)
  2812. return cmd
  2813. }
  2814. func (c cmdable) PubSubNumSub(ctx context.Context, channels ...string) *StringIntMapCmd {
  2815. args := make([]interface{}, 2+len(channels))
  2816. args[0] = "pubsub"
  2817. args[1] = "numsub"
  2818. for i, channel := range channels {
  2819. args[2+i] = channel
  2820. }
  2821. cmd := NewStringIntMapCmd(ctx, args...)
  2822. _ = c(ctx, cmd)
  2823. return cmd
  2824. }
  2825. func (c cmdable) PubSubNumPat(ctx context.Context) *IntCmd {
  2826. cmd := NewIntCmd(ctx, "pubsub", "numpat")
  2827. _ = c(ctx, cmd)
  2828. return cmd
  2829. }
  2830. //------------------------------------------------------------------------------
  2831. func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
  2832. cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
  2833. _ = c(ctx, cmd)
  2834. return cmd
  2835. }
  2836. func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
  2837. cmd := NewStringCmd(ctx, "cluster", "nodes")
  2838. _ = c(ctx, cmd)
  2839. return cmd
  2840. }
  2841. func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
  2842. cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
  2843. _ = c(ctx, cmd)
  2844. return cmd
  2845. }
  2846. func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
  2847. cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
  2848. _ = c(ctx, cmd)
  2849. return cmd
  2850. }
  2851. func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
  2852. cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
  2853. _ = c(ctx, cmd)
  2854. return cmd
  2855. }
  2856. func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
  2857. cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
  2858. _ = c(ctx, cmd)
  2859. return cmd
  2860. }
  2861. func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
  2862. cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
  2863. _ = c(ctx, cmd)
  2864. return cmd
  2865. }
  2866. func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
  2867. cmd := NewStringCmd(ctx, "cluster", "info")
  2868. _ = c(ctx, cmd)
  2869. return cmd
  2870. }
  2871. func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
  2872. cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
  2873. _ = c(ctx, cmd)
  2874. return cmd
  2875. }
  2876. func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
  2877. cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
  2878. _ = c(ctx, cmd)
  2879. return cmd
  2880. }
  2881. func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
  2882. cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
  2883. _ = c(ctx, cmd)
  2884. return cmd
  2885. }
  2886. func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
  2887. cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
  2888. _ = c(ctx, cmd)
  2889. return cmd
  2890. }
  2891. func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
  2892. args := make([]interface{}, 2+len(slots))
  2893. args[0] = "cluster"
  2894. args[1] = "delslots"
  2895. for i, slot := range slots {
  2896. args[2+i] = slot
  2897. }
  2898. cmd := NewStatusCmd(ctx, args...)
  2899. _ = c(ctx, cmd)
  2900. return cmd
  2901. }
  2902. func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
  2903. size := max - min + 1
  2904. slots := make([]int, size)
  2905. for i := 0; i < size; i++ {
  2906. slots[i] = min + i
  2907. }
  2908. return c.ClusterDelSlots(ctx, slots...)
  2909. }
  2910. func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
  2911. cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
  2912. _ = c(ctx, cmd)
  2913. return cmd
  2914. }
  2915. func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
  2916. cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
  2917. _ = c(ctx, cmd)
  2918. return cmd
  2919. }
  2920. func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
  2921. cmd := NewStatusCmd(ctx, "cluster", "failover")
  2922. _ = c(ctx, cmd)
  2923. return cmd
  2924. }
  2925. func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
  2926. args := make([]interface{}, 2+len(slots))
  2927. args[0] = "cluster"
  2928. args[1] = "addslots"
  2929. for i, num := range slots {
  2930. args[2+i] = num
  2931. }
  2932. cmd := NewStatusCmd(ctx, args...)
  2933. _ = c(ctx, cmd)
  2934. return cmd
  2935. }
  2936. func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
  2937. size := max - min + 1
  2938. slots := make([]int, size)
  2939. for i := 0; i < size; i++ {
  2940. slots[i] = min + i
  2941. }
  2942. return c.ClusterAddSlots(ctx, slots...)
  2943. }
  2944. //------------------------------------------------------------------------------
  2945. func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd {
  2946. args := make([]interface{}, 2+3*len(geoLocation))
  2947. args[0] = "geoadd"
  2948. args[1] = key
  2949. for i, eachLoc := range geoLocation {
  2950. args[2+3*i] = eachLoc.Longitude
  2951. args[2+3*i+1] = eachLoc.Latitude
  2952. args[2+3*i+2] = eachLoc.Name
  2953. }
  2954. cmd := NewIntCmd(ctx, args...)
  2955. _ = c(ctx, cmd)
  2956. return cmd
  2957. }
  2958. // GeoRadius is a read-only GEORADIUS_RO command.
  2959. func (c cmdable) GeoRadius(
  2960. ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
  2961. ) *GeoLocationCmd {
  2962. cmd := NewGeoLocationCmd(ctx, query, "georadius_ro", key, longitude, latitude)
  2963. if query.Store != "" || query.StoreDist != "" {
  2964. cmd.SetErr(errors.New("GeoRadius does not support Store or StoreDist"))
  2965. return cmd
  2966. }
  2967. _ = c(ctx, cmd)
  2968. return cmd
  2969. }
  2970. // GeoRadiusStore is a writing GEORADIUS command.
  2971. func (c cmdable) GeoRadiusStore(
  2972. ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
  2973. ) *IntCmd {
  2974. args := geoLocationArgs(query, "georadius", key, longitude, latitude)
  2975. cmd := NewIntCmd(ctx, args...)
  2976. if query.Store == "" && query.StoreDist == "" {
  2977. cmd.SetErr(errors.New("GeoRadiusStore requires Store or StoreDist"))
  2978. return cmd
  2979. }
  2980. _ = c(ctx, cmd)
  2981. return cmd
  2982. }
  2983. // GeoRadiusByMember is a read-only GEORADIUSBYMEMBER_RO command.
  2984. func (c cmdable) GeoRadiusByMember(
  2985. ctx context.Context, key, member string, query *GeoRadiusQuery,
  2986. ) *GeoLocationCmd {
  2987. cmd := NewGeoLocationCmd(ctx, query, "georadiusbymember_ro", key, member)
  2988. if query.Store != "" || query.StoreDist != "" {
  2989. cmd.SetErr(errors.New("GeoRadiusByMember does not support Store or StoreDist"))
  2990. return cmd
  2991. }
  2992. _ = c(ctx, cmd)
  2993. return cmd
  2994. }
  2995. // GeoRadiusByMemberStore is a writing GEORADIUSBYMEMBER command.
  2996. func (c cmdable) GeoRadiusByMemberStore(
  2997. ctx context.Context, key, member string, query *GeoRadiusQuery,
  2998. ) *IntCmd {
  2999. args := geoLocationArgs(query, "georadiusbymember", key, member)
  3000. cmd := NewIntCmd(ctx, args...)
  3001. if query.Store == "" && query.StoreDist == "" {
  3002. cmd.SetErr(errors.New("GeoRadiusByMemberStore requires Store or StoreDist"))
  3003. return cmd
  3004. }
  3005. _ = c(ctx, cmd)
  3006. return cmd
  3007. }
  3008. func (c cmdable) GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd {
  3009. args := make([]interface{}, 0, 13)
  3010. args = append(args, "geosearch", key)
  3011. args = geoSearchArgs(q, args)
  3012. cmd := NewStringSliceCmd(ctx, args...)
  3013. _ = c(ctx, cmd)
  3014. return cmd
  3015. }
  3016. func (c cmdable) GeoSearchLocation(
  3017. ctx context.Context, key string, q *GeoSearchLocationQuery,
  3018. ) *GeoSearchLocationCmd {
  3019. args := make([]interface{}, 0, 16)
  3020. args = append(args, "geosearch", key)
  3021. args = geoSearchLocationArgs(q, args)
  3022. cmd := NewGeoSearchLocationCmd(ctx, q, args...)
  3023. _ = c(ctx, cmd)
  3024. return cmd
  3025. }
  3026. func (c cmdable) GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd {
  3027. args := make([]interface{}, 0, 15)
  3028. args = append(args, "geosearchstore", store, key)
  3029. args = geoSearchArgs(&q.GeoSearchQuery, args)
  3030. if q.StoreDist {
  3031. args = append(args, "storedist")
  3032. }
  3033. cmd := NewIntCmd(ctx, args...)
  3034. _ = c(ctx, cmd)
  3035. return cmd
  3036. }
  3037. func (c cmdable) GeoDist(
  3038. ctx context.Context, key string, member1, member2, unit string,
  3039. ) *FloatCmd {
  3040. if unit == "" {
  3041. unit = "km"
  3042. }
  3043. cmd := NewFloatCmd(ctx, "geodist", key, member1, member2, unit)
  3044. _ = c(ctx, cmd)
  3045. return cmd
  3046. }
  3047. func (c cmdable) GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd {
  3048. args := make([]interface{}, 2+len(members))
  3049. args[0] = "geohash"
  3050. args[1] = key
  3051. for i, member := range members {
  3052. args[2+i] = member
  3053. }
  3054. cmd := NewStringSliceCmd(ctx, args...)
  3055. _ = c(ctx, cmd)
  3056. return cmd
  3057. }
  3058. func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd {
  3059. args := make([]interface{}, 2+len(members))
  3060. args[0] = "geopos"
  3061. args[1] = key
  3062. for i, member := range members {
  3063. args[2+i] = member
  3064. }
  3065. cmd := NewGeoPosCmd(ctx, args...)
  3066. _ = c(ctx, cmd)
  3067. return cmd
  3068. }