Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

620 wiersze
22 KiB

  1. package redis
  2. import (
  3. "context"
  4. "time"
  5. "github.com/redis/go-redis/v9/internal/hashtag"
  6. )
  7. type HashCmdable interface {
  8. HDel(ctx context.Context, key string, fields ...string) *IntCmd
  9. HExists(ctx context.Context, key, field string) *BoolCmd
  10. HGet(ctx context.Context, key, field string) *StringCmd
  11. HGetAll(ctx context.Context, key string) *MapStringStringCmd
  12. HGetDel(ctx context.Context, key string, fields ...string) *StringSliceCmd
  13. HGetEX(ctx context.Context, key string, fields ...string) *StringSliceCmd
  14. HGetEXWithArgs(ctx context.Context, key string, options *HGetEXOptions, fields ...string) *StringSliceCmd
  15. HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
  16. HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
  17. HKeys(ctx context.Context, key string) *StringSliceCmd
  18. HLen(ctx context.Context, key string) *IntCmd
  19. HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
  20. HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
  21. HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
  22. HSetEX(ctx context.Context, key string, fieldsAndValues ...string) *IntCmd
  23. HSetEXWithArgs(ctx context.Context, key string, options *HSetEXOptions, fieldsAndValues ...string) *IntCmd
  24. HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
  25. HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
  26. HScanNoValues(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
  27. HVals(ctx context.Context, key string) *StringSliceCmd
  28. HRandField(ctx context.Context, key string, count int) *StringSliceCmd
  29. HRandFieldWithValues(ctx context.Context, key string, count int) *KeyValueSliceCmd
  30. HStrLen(ctx context.Context, key, field string) *IntCmd
  31. HExpire(ctx context.Context, key string, expiration time.Duration, fields ...string) *IntSliceCmd
  32. HExpireWithArgs(ctx context.Context, key string, expiration time.Duration, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
  33. HPExpire(ctx context.Context, key string, expiration time.Duration, fields ...string) *IntSliceCmd
  34. HPExpireWithArgs(ctx context.Context, key string, expiration time.Duration, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
  35. HExpireAt(ctx context.Context, key string, tm time.Time, fields ...string) *IntSliceCmd
  36. HExpireAtWithArgs(ctx context.Context, key string, tm time.Time, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
  37. HPExpireAt(ctx context.Context, key string, tm time.Time, fields ...string) *IntSliceCmd
  38. HPExpireAtWithArgs(ctx context.Context, key string, tm time.Time, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd
  39. HPersist(ctx context.Context, key string, fields ...string) *IntSliceCmd
  40. HExpireTime(ctx context.Context, key string, fields ...string) *IntSliceCmd
  41. HPExpireTime(ctx context.Context, key string, fields ...string) *IntSliceCmd
  42. HTTL(ctx context.Context, key string, fields ...string) *IntSliceCmd
  43. HPTTL(ctx context.Context, key string, fields ...string) *IntSliceCmd
  44. }
  45. func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
  46. args := make([]interface{}, 2+len(fields))
  47. args[0] = "hdel"
  48. args[1] = key
  49. for i, field := range fields {
  50. args[2+i] = field
  51. }
  52. cmd := NewIntCmd(ctx, args...)
  53. _ = c(ctx, cmd)
  54. return cmd
  55. }
  56. func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
  57. cmd := NewBoolCmd(ctx, "hexists", key, field)
  58. _ = c(ctx, cmd)
  59. return cmd
  60. }
  61. func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
  62. cmd := NewStringCmd(ctx, "hget", key, field)
  63. _ = c(ctx, cmd)
  64. return cmd
  65. }
  66. func (c cmdable) HGetAll(ctx context.Context, key string) *MapStringStringCmd {
  67. cmd := NewMapStringStringCmd(ctx, "hgetall", key)
  68. _ = c(ctx, cmd)
  69. return cmd
  70. }
  71. func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
  72. cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
  73. _ = c(ctx, cmd)
  74. return cmd
  75. }
  76. func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
  77. cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
  78. _ = c(ctx, cmd)
  79. return cmd
  80. }
  81. func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
  82. cmd := NewStringSliceCmd(ctx, "hkeys", key)
  83. _ = c(ctx, cmd)
  84. return cmd
  85. }
  86. func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
  87. cmd := NewIntCmd(ctx, "hlen", key)
  88. _ = c(ctx, cmd)
  89. return cmd
  90. }
  91. // HMGet returns the values for the specified fields in the hash stored at key.
  92. // It returns an interface{} to distinguish between empty string and nil value.
  93. func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
  94. args := make([]interface{}, 2+len(fields))
  95. args[0] = "hmget"
  96. args[1] = key
  97. for i, field := range fields {
  98. args[2+i] = field
  99. }
  100. cmd := NewSliceCmd(ctx, args...)
  101. _ = c(ctx, cmd)
  102. return cmd
  103. }
  104. // HSet accepts values in following formats:
  105. //
  106. // - HSet(ctx, "myhash", "key1", "value1", "key2", "value2")
  107. //
  108. // - HSet(ctx, "myhash", []string{"key1", "value1", "key2", "value2"})
  109. //
  110. // - HSet(ctx, "myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
  111. //
  112. // Playing struct With "redis" tag.
  113. // type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
  114. //
  115. // - HSet(ctx, "myhash", MyHash{"value1", "value2"}) Warn: redis-server >= 4.0
  116. //
  117. // For struct, can be a structure pointer type, we only parse the field whose tag is redis.
  118. // if you don't want the field to be read, you can use the `redis:"-"` flag to ignore it,
  119. // or you don't need to set the redis tag.
  120. // For the type of structure field, we only support simple data types:
  121. // string, int/uint(8,16,32,64), float(32,64), time.Time(to RFC3339Nano), time.Duration(to Nanoseconds ),
  122. // if you are other more complex or custom data types, please implement the encoding.BinaryMarshaler interface.
  123. //
  124. // Note that in older versions of Redis server(redis-server < 4.0), HSet only supports a single key-value pair.
  125. // redis-docs: https://redis.io/commands/hset (Starting with Redis version 4.0.0: Accepts multiple field and value arguments.)
  126. // If you are using a Struct type and the number of fields is greater than one,
  127. // you will receive an error similar to "ERR wrong number of arguments", you can use HMSet as a substitute.
  128. func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
  129. args := make([]interface{}, 2, 2+len(values))
  130. args[0] = "hset"
  131. args[1] = key
  132. args = appendArgs(args, values)
  133. cmd := NewIntCmd(ctx, args...)
  134. _ = c(ctx, cmd)
  135. return cmd
  136. }
  137. // HMSet is a deprecated version of HSet left for compatibility with Redis 3.
  138. func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
  139. args := make([]interface{}, 2, 2+len(values))
  140. args[0] = "hmset"
  141. args[1] = key
  142. args = appendArgs(args, values)
  143. cmd := NewBoolCmd(ctx, args...)
  144. _ = c(ctx, cmd)
  145. return cmd
  146. }
  147. func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
  148. cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
  149. _ = c(ctx, cmd)
  150. return cmd
  151. }
  152. func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
  153. cmd := NewStringSliceCmd(ctx, "hvals", key)
  154. _ = c(ctx, cmd)
  155. return cmd
  156. }
  157. // HRandField redis-server version >= 6.2.0.
  158. func (c cmdable) HRandField(ctx context.Context, key string, count int) *StringSliceCmd {
  159. cmd := NewStringSliceCmd(ctx, "hrandfield", key, count)
  160. _ = c(ctx, cmd)
  161. return cmd
  162. }
  163. // HRandFieldWithValues redis-server version >= 6.2.0.
  164. func (c cmdable) HRandFieldWithValues(ctx context.Context, key string, count int) *KeyValueSliceCmd {
  165. cmd := NewKeyValueSliceCmd(ctx, "hrandfield", key, count, "withvalues")
  166. _ = c(ctx, cmd)
  167. return cmd
  168. }
  169. func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
  170. args := []interface{}{"hscan", key, cursor}
  171. if match != "" {
  172. args = append(args, "match", match)
  173. }
  174. if count > 0 {
  175. args = append(args, "count", count)
  176. }
  177. cmd := NewScanCmd(ctx, c, args...)
  178. if hashtag.Present(match) {
  179. cmd.SetFirstKeyPos(4)
  180. }
  181. _ = c(ctx, cmd)
  182. return cmd
  183. }
  184. func (c cmdable) HStrLen(ctx context.Context, key, field string) *IntCmd {
  185. cmd := NewIntCmd(ctx, "hstrlen", key, field)
  186. _ = c(ctx, cmd)
  187. return cmd
  188. }
  189. func (c cmdable) HScanNoValues(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
  190. args := []interface{}{"hscan", key, cursor}
  191. if match != "" {
  192. args = append(args, "match", match)
  193. }
  194. if count > 0 {
  195. args = append(args, "count", count)
  196. }
  197. args = append(args, "novalues")
  198. cmd := NewScanCmd(ctx, c, args...)
  199. if hashtag.Present(match) {
  200. cmd.SetFirstKeyPos(4)
  201. }
  202. _ = c(ctx, cmd)
  203. return cmd
  204. }
  205. type HExpireArgs struct {
  206. NX bool
  207. XX bool
  208. GT bool
  209. LT bool
  210. }
  211. // HExpire - Sets the expiration time for specified fields in a hash in seconds.
  212. // The command constructs an argument list starting with "HEXPIRE", followed by the key, duration, any conditional flags, and the specified fields.
  213. // Available since Redis 7.4 CE.
  214. // For more information refer to [HEXPIRE Documentation].
  215. //
  216. // [HEXPIRE Documentation]: https://redis.io/commands/hexpire/
  217. func (c cmdable) HExpire(ctx context.Context, key string, expiration time.Duration, fields ...string) *IntSliceCmd {
  218. args := []interface{}{"HEXPIRE", key, formatSec(ctx, expiration), "FIELDS", len(fields)}
  219. for _, field := range fields {
  220. args = append(args, field)
  221. }
  222. cmd := NewIntSliceCmd(ctx, args...)
  223. _ = c(ctx, cmd)
  224. return cmd
  225. }
  226. // HExpireWithArgs - Sets the expiration time for specified fields in a hash in seconds.
  227. // It requires a key, an expiration duration, a struct with boolean flags for conditional expiration settings (NX, XX, GT, LT), and a list of fields.
  228. // The command constructs an argument list starting with "HEXPIRE", followed by the key, duration, any conditional flags, and the specified fields.
  229. // Available since Redis 7.4 CE.
  230. // For more information refer to [HEXPIRE Documentation].
  231. //
  232. // [HEXPIRE Documentation]: https://redis.io/commands/hexpire/
  233. func (c cmdable) HExpireWithArgs(ctx context.Context, key string, expiration time.Duration, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd {
  234. args := []interface{}{"HEXPIRE", key, formatSec(ctx, expiration)}
  235. // only if one argument is true, we can add it to the args
  236. // if more than one argument is true, it will cause an error
  237. if expirationArgs.NX {
  238. args = append(args, "NX")
  239. } else if expirationArgs.XX {
  240. args = append(args, "XX")
  241. } else if expirationArgs.GT {
  242. args = append(args, "GT")
  243. } else if expirationArgs.LT {
  244. args = append(args, "LT")
  245. }
  246. args = append(args, "FIELDS", len(fields))
  247. for _, field := range fields {
  248. args = append(args, field)
  249. }
  250. cmd := NewIntSliceCmd(ctx, args...)
  251. _ = c(ctx, cmd)
  252. return cmd
  253. }
  254. // HPExpire - Sets the expiration time for specified fields in a hash in milliseconds.
  255. // Similar to HExpire, it accepts a key, an expiration duration in milliseconds, a struct with expiration condition flags, and a list of fields.
  256. // The command modifies the standard time.Duration to milliseconds for the Redis command.
  257. // Available since Redis 7.4 CE.
  258. // For more information refer to [HPEXPIRE Documentation].
  259. //
  260. // [HPEXPIRE Documentation]: https://redis.io/commands/hpexpire/
  261. func (c cmdable) HPExpire(ctx context.Context, key string, expiration time.Duration, fields ...string) *IntSliceCmd {
  262. args := []interface{}{"HPEXPIRE", key, formatMs(ctx, expiration), "FIELDS", len(fields)}
  263. for _, field := range fields {
  264. args = append(args, field)
  265. }
  266. cmd := NewIntSliceCmd(ctx, args...)
  267. _ = c(ctx, cmd)
  268. return cmd
  269. }
  270. // HPExpireWithArgs - Sets the expiration time for specified fields in a hash in milliseconds.
  271. // It requires a key, an expiration duration, a struct with boolean flags for conditional expiration settings (NX, XX, GT, LT), and a list of fields.
  272. // The command constructs an argument list starting with "HPEXPIRE", followed by the key, duration, any conditional flags, and the specified fields.
  273. // Available since Redis 7.4 CE.
  274. // For more information refer to [HPEXPIRE Documentation].
  275. //
  276. // [HPEXPIRE Documentation]: https://redis.io/commands/hpexpire/
  277. func (c cmdable) HPExpireWithArgs(ctx context.Context, key string, expiration time.Duration, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd {
  278. args := []interface{}{"HPEXPIRE", key, formatMs(ctx, expiration)}
  279. // only if one argument is true, we can add it to the args
  280. // if more than one argument is true, it will cause an error
  281. if expirationArgs.NX {
  282. args = append(args, "NX")
  283. } else if expirationArgs.XX {
  284. args = append(args, "XX")
  285. } else if expirationArgs.GT {
  286. args = append(args, "GT")
  287. } else if expirationArgs.LT {
  288. args = append(args, "LT")
  289. }
  290. args = append(args, "FIELDS", len(fields))
  291. for _, field := range fields {
  292. args = append(args, field)
  293. }
  294. cmd := NewIntSliceCmd(ctx, args...)
  295. _ = c(ctx, cmd)
  296. return cmd
  297. }
  298. // HExpireAt - Sets the expiration time for specified fields in a hash to a UNIX timestamp in seconds.
  299. // Takes a key, a UNIX timestamp, a struct of conditional flags, and a list of fields.
  300. // The command sets absolute expiration times based on the UNIX timestamp provided.
  301. // Available since Redis 7.4 CE.
  302. // For more information refer to [HExpireAt Documentation].
  303. //
  304. // [HExpireAt Documentation]: https://redis.io/commands/hexpireat/
  305. func (c cmdable) HExpireAt(ctx context.Context, key string, tm time.Time, fields ...string) *IntSliceCmd {
  306. args := []interface{}{"HEXPIREAT", key, tm.Unix(), "FIELDS", len(fields)}
  307. for _, field := range fields {
  308. args = append(args, field)
  309. }
  310. cmd := NewIntSliceCmd(ctx, args...)
  311. _ = c(ctx, cmd)
  312. return cmd
  313. }
  314. func (c cmdable) HExpireAtWithArgs(ctx context.Context, key string, tm time.Time, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd {
  315. args := []interface{}{"HEXPIREAT", key, tm.Unix()}
  316. // only if one argument is true, we can add it to the args
  317. // if more than one argument is true, it will cause an error
  318. if expirationArgs.NX {
  319. args = append(args, "NX")
  320. } else if expirationArgs.XX {
  321. args = append(args, "XX")
  322. } else if expirationArgs.GT {
  323. args = append(args, "GT")
  324. } else if expirationArgs.LT {
  325. args = append(args, "LT")
  326. }
  327. args = append(args, "FIELDS", len(fields))
  328. for _, field := range fields {
  329. args = append(args, field)
  330. }
  331. cmd := NewIntSliceCmd(ctx, args...)
  332. _ = c(ctx, cmd)
  333. return cmd
  334. }
  335. // HPExpireAt - Sets the expiration time for specified fields in a hash to a UNIX timestamp in milliseconds.
  336. // Similar to HExpireAt but for timestamps in milliseconds. It accepts the same parameters and adjusts the UNIX time to milliseconds.
  337. // Available since Redis 7.4 CE.
  338. // For more information refer to [HExpireAt Documentation].
  339. //
  340. // [HExpireAt Documentation]: https://redis.io/commands/hexpireat/
  341. func (c cmdable) HPExpireAt(ctx context.Context, key string, tm time.Time, fields ...string) *IntSliceCmd {
  342. args := []interface{}{"HPEXPIREAT", key, tm.UnixNano() / int64(time.Millisecond), "FIELDS", len(fields)}
  343. for _, field := range fields {
  344. args = append(args, field)
  345. }
  346. cmd := NewIntSliceCmd(ctx, args...)
  347. _ = c(ctx, cmd)
  348. return cmd
  349. }
  350. func (c cmdable) HPExpireAtWithArgs(ctx context.Context, key string, tm time.Time, expirationArgs HExpireArgs, fields ...string) *IntSliceCmd {
  351. args := []interface{}{"HPEXPIREAT", key, tm.UnixNano() / int64(time.Millisecond)}
  352. // only if one argument is true, we can add it to the args
  353. // if more than one argument is true, it will cause an error
  354. if expirationArgs.NX {
  355. args = append(args, "NX")
  356. } else if expirationArgs.XX {
  357. args = append(args, "XX")
  358. } else if expirationArgs.GT {
  359. args = append(args, "GT")
  360. } else if expirationArgs.LT {
  361. args = append(args, "LT")
  362. }
  363. args = append(args, "FIELDS", len(fields))
  364. for _, field := range fields {
  365. args = append(args, field)
  366. }
  367. cmd := NewIntSliceCmd(ctx, args...)
  368. _ = c(ctx, cmd)
  369. return cmd
  370. }
  371. // HPersist - Removes the expiration time from specified fields in a hash.
  372. // Accepts a key and the fields themselves.
  373. // This command ensures that each field specified will have its expiration removed if present.
  374. // Available since Redis 7.4 CE.
  375. // For more information refer to [HPersist Documentation].
  376. //
  377. // [HPersist Documentation]: https://redis.io/commands/hpersist/
  378. func (c cmdable) HPersist(ctx context.Context, key string, fields ...string) *IntSliceCmd {
  379. args := []interface{}{"HPERSIST", key, "FIELDS", len(fields)}
  380. for _, field := range fields {
  381. args = append(args, field)
  382. }
  383. cmd := NewIntSliceCmd(ctx, args...)
  384. _ = c(ctx, cmd)
  385. return cmd
  386. }
  387. // HExpireTime - Retrieves the expiration time for specified fields in a hash as a UNIX timestamp in seconds.
  388. // Requires a key and the fields themselves to fetch their expiration timestamps.
  389. // This command returns the expiration times for each field or error/status codes for each field as specified.
  390. // Available since Redis 7.4 CE.
  391. // For more information refer to [HExpireTime Documentation].
  392. //
  393. // [HExpireTime Documentation]: https://redis.io/commands/hexpiretime/
  394. // For more information - https://redis.io/commands/hexpiretime/
  395. func (c cmdable) HExpireTime(ctx context.Context, key string, fields ...string) *IntSliceCmd {
  396. args := []interface{}{"HEXPIRETIME", key, "FIELDS", len(fields)}
  397. for _, field := range fields {
  398. args = append(args, field)
  399. }
  400. cmd := NewIntSliceCmd(ctx, args...)
  401. _ = c(ctx, cmd)
  402. return cmd
  403. }
  404. // HPExpireTime - Retrieves the expiration time for specified fields in a hash as a UNIX timestamp in milliseconds.
  405. // Similar to HExpireTime, adjusted for timestamps in milliseconds. It requires the same parameters.
  406. // Provides the expiration timestamp for each field in milliseconds.
  407. // Available since Redis 7.4 CE.
  408. // For more information refer to [HExpireTime Documentation].
  409. //
  410. // [HExpireTime Documentation]: https://redis.io/commands/hexpiretime/
  411. // For more information - https://redis.io/commands/hexpiretime/
  412. func (c cmdable) HPExpireTime(ctx context.Context, key string, fields ...string) *IntSliceCmd {
  413. args := []interface{}{"HPEXPIRETIME", key, "FIELDS", len(fields)}
  414. for _, field := range fields {
  415. args = append(args, field)
  416. }
  417. cmd := NewIntSliceCmd(ctx, args...)
  418. _ = c(ctx, cmd)
  419. return cmd
  420. }
  421. // HTTL - Retrieves the remaining time to live for specified fields in a hash in seconds.
  422. // Requires a key and the fields themselves. It returns the TTL for each specified field.
  423. // This command fetches the TTL in seconds for each field or returns error/status codes as appropriate.
  424. // Available since Redis 7.4 CE.
  425. // For more information refer to [HTTL Documentation].
  426. //
  427. // [HTTL Documentation]: https://redis.io/commands/httl/
  428. func (c cmdable) HTTL(ctx context.Context, key string, fields ...string) *IntSliceCmd {
  429. args := []interface{}{"HTTL", key, "FIELDS", len(fields)}
  430. for _, field := range fields {
  431. args = append(args, field)
  432. }
  433. cmd := NewIntSliceCmd(ctx, args...)
  434. _ = c(ctx, cmd)
  435. return cmd
  436. }
  437. // HPTTL - Retrieves the remaining time to live for specified fields in a hash in milliseconds.
  438. // Similar to HTTL, but returns the TTL in milliseconds. It requires a key and the specified fields.
  439. // This command provides the TTL in milliseconds for each field or returns error/status codes as needed.
  440. // Available since Redis 7.4 CE.
  441. // For more information refer to [HPTTL Documentation].
  442. //
  443. // [HPTTL Documentation]: https://redis.io/commands/hpttl/
  444. // For more information - https://redis.io/commands/hpttl/
  445. func (c cmdable) HPTTL(ctx context.Context, key string, fields ...string) *IntSliceCmd {
  446. args := []interface{}{"HPTTL", key, "FIELDS", len(fields)}
  447. for _, field := range fields {
  448. args = append(args, field)
  449. }
  450. cmd := NewIntSliceCmd(ctx, args...)
  451. _ = c(ctx, cmd)
  452. return cmd
  453. }
  454. func (c cmdable) HGetDel(ctx context.Context, key string, fields ...string) *StringSliceCmd {
  455. args := []interface{}{"HGETDEL", key, "FIELDS", len(fields)}
  456. for _, field := range fields {
  457. args = append(args, field)
  458. }
  459. cmd := NewStringSliceCmd(ctx, args...)
  460. _ = c(ctx, cmd)
  461. return cmd
  462. }
  463. func (c cmdable) HGetEX(ctx context.Context, key string, fields ...string) *StringSliceCmd {
  464. args := []interface{}{"HGETEX", key, "FIELDS", len(fields)}
  465. for _, field := range fields {
  466. args = append(args, field)
  467. }
  468. cmd := NewStringSliceCmd(ctx, args...)
  469. _ = c(ctx, cmd)
  470. return cmd
  471. }
  472. // HGetEXExpirationType represents an expiration option for the HGETEX command.
  473. type HGetEXExpirationType string
  474. const (
  475. HGetEXExpirationEX HGetEXExpirationType = "EX"
  476. HGetEXExpirationPX HGetEXExpirationType = "PX"
  477. HGetEXExpirationEXAT HGetEXExpirationType = "EXAT"
  478. HGetEXExpirationPXAT HGetEXExpirationType = "PXAT"
  479. HGetEXExpirationPERSIST HGetEXExpirationType = "PERSIST"
  480. )
  481. type HGetEXOptions struct {
  482. ExpirationType HGetEXExpirationType
  483. ExpirationVal int64
  484. }
  485. func (c cmdable) HGetEXWithArgs(ctx context.Context, key string, options *HGetEXOptions, fields ...string) *StringSliceCmd {
  486. args := []interface{}{"HGETEX", key}
  487. if options.ExpirationType != "" {
  488. args = append(args, string(options.ExpirationType))
  489. if options.ExpirationType != HGetEXExpirationPERSIST {
  490. args = append(args, options.ExpirationVal)
  491. }
  492. }
  493. args = append(args, "FIELDS", len(fields))
  494. for _, field := range fields {
  495. args = append(args, field)
  496. }
  497. cmd := NewStringSliceCmd(ctx, args...)
  498. _ = c(ctx, cmd)
  499. return cmd
  500. }
  501. type HSetEXCondition string
  502. const (
  503. HSetEXFNX HSetEXCondition = "FNX" // Only set the fields if none of them already exist.
  504. HSetEXFXX HSetEXCondition = "FXX" // Only set the fields if all already exist.
  505. )
  506. type HSetEXExpirationType string
  507. const (
  508. HSetEXExpirationEX HSetEXExpirationType = "EX"
  509. HSetEXExpirationPX HSetEXExpirationType = "PX"
  510. HSetEXExpirationEXAT HSetEXExpirationType = "EXAT"
  511. HSetEXExpirationPXAT HSetEXExpirationType = "PXAT"
  512. HSetEXExpirationKEEPTTL HSetEXExpirationType = "KEEPTTL"
  513. )
  514. type HSetEXOptions struct {
  515. Condition HSetEXCondition
  516. ExpirationType HSetEXExpirationType
  517. ExpirationVal int64
  518. }
  519. func (c cmdable) HSetEX(ctx context.Context, key string, fieldsAndValues ...string) *IntCmd {
  520. args := []interface{}{"HSETEX", key, "FIELDS", len(fieldsAndValues) / 2}
  521. for _, field := range fieldsAndValues {
  522. args = append(args, field)
  523. }
  524. cmd := NewIntCmd(ctx, args...)
  525. _ = c(ctx, cmd)
  526. return cmd
  527. }
  528. func (c cmdable) HSetEXWithArgs(ctx context.Context, key string, options *HSetEXOptions, fieldsAndValues ...string) *IntCmd {
  529. args := []interface{}{"HSETEX", key}
  530. if options.Condition != "" {
  531. args = append(args, string(options.Condition))
  532. }
  533. if options.ExpirationType != "" {
  534. args = append(args, string(options.ExpirationType))
  535. if options.ExpirationType != HSetEXExpirationKEEPTTL {
  536. args = append(args, options.ExpirationVal)
  537. }
  538. }
  539. args = append(args, "FIELDS", len(fieldsAndValues)/2)
  540. for _, field := range fieldsAndValues {
  541. args = append(args, field)
  542. }
  543. cmd := NewIntCmd(ctx, args...)
  544. _ = c(ctx, cmd)
  545. return cmd
  546. }