/
command_list.go
389 lines (363 loc) · 14.5 KB
/
command_list.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
package redis
import (
"context"
"time"
"github.com/redis/go-redis/v9"
)
// BLPop 是列表的阻塞式(blocking)弹出原语。
// 它是 LPop 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BLPop 命令阻塞,直到等待超时或发现可弹出元素为止。
// 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。
func (r *Client) BLPop(ctx context.Context, timeout time.Duration, keys ...any) (val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.BLPop(getCtx(ctx), timeout, r.ks(keys...)...).Result()
return err
}, acceptable)
return
}
func (r *Client) BLMPop(ctx context.Context, timeout time.Duration, direction string, count int64, keys ...any) (key string, val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
key, val, err = conn.BLMPop(getCtx(ctx), timeout, direction, count, r.ks(keys...)...).Result()
return err
}, acceptable)
return
}
// BRPop 是列表的阻塞式(blocking)弹出原语。
// 它是 RPOP 命令的阻塞版本,当给定列表内没有任何元素可供弹出的时候,连接将被 BRPOP 命令阻塞,直到等待超时或发现可弹出元素为止。
// 当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的尾部元素。
// 关于阻塞操作的更多信息,请查看 BLPOP 命令, BRPOP 除了弹出元素的位置和 BLPOP 不同之外,其他表现一致。
func (r *Client) BRPop(ctx context.Context, timeout time.Duration, keys ...any) (val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.BRPop(getCtx(ctx), timeout, r.ks(keys...)...).Result()
return err
}, acceptable)
return
}
// BRPopLPush 是 RPOPLPUSH 的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH 的表现和 RPOPLPUSH 一样。
// 当列表 source 为空时, BRPOPLPUSH 命令将阻塞连接,直到等待超时,或有另一个客户端对 source 执行 LPUSH 或 RPUSH 命令为止。
func (r *Client) BRPopLPush(ctx context.Context, source, destination any, timeout time.Duration) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.BRPopLPush(getCtx(ctx), r.k(source), r.k(destination), timeout).Result()
return err
}, acceptable)
return
}
// LIndex 返回列表 key 中,下标为 index 的元素。
// 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
// 如果 key 不是列表类型,返回一个错误。
func (r *Client) LIndex(ctx context.Context, key any, index int64) (val string, err error) {
// return getRedis(r).LIndex(getCtx(ctx), r.k(key), index)
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LIndex(getCtx(ctx), r.k(key), index).Result()
return err
}, acceptable)
return
}
// LInsert 将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
// 当 pivot 不存在于列表 key 时,不执行任何操作。
// 当 key 不存在时, key 被视为空列表,不执行任何操作。
// 如果 key 不是列表类型,返回一个错误。
func (r *Client) LInsert(ctx context.Context, key any, op string, pivot, value any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LInsert(getCtx(ctx), r.k(key), op, pivot, value).Result()
return err
}, acceptable)
return
}
// LInsertBefore 同 LInsert
func (r *Client) LInsertBefore(ctx context.Context, key any, pivot, value any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LInsertBefore(getCtx(ctx), r.k(key), pivot, value).Result()
return err
}, acceptable)
return
}
// LInsertAfter 同 LInsert
func (r *Client) LInsertAfter(ctx context.Context, key any, pivot, value any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LInsertAfter(getCtx(ctx), r.k(key), pivot, value).Result()
return err
}, acceptable)
return
}
// LLen 返回列表 key 的长度。
// 如果 key 不存在,则 key 被解释为一个空列表,返回 0 .
// 如果 key 不是列表类型,返回一个错误。
func (r *Client) LLen(ctx context.Context, key any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LLen(getCtx(ctx), r.k(key)).Result()
return err
}, acceptable)
return
}
// LMPop Pops one or more elements from the first non-empty list key from the list of provided key names.
// direction: left or right, count: > 0
// example: client.LMPop(ctx, "left", 3, "key1", "key2")
func (r *Client) LMPop(ctx context.Context, direction string, count int64, keys ...any) (key string, val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
key, val, err = conn.LMPop(getCtx(ctx), direction, count, r.ks(keys...)...).Result()
return err
}, acceptable)
return
}
// LPop 移除并返回列表 key 的头元素。
func (r *Client) LPop(ctx context.Context, key any) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LPop(getCtx(ctx), r.k(key)).Result()
return err
}, acceptable)
return
}
// LPopCount 移除并返回列表 key 的头元素。
func (r *Client) LPopCount(ctx context.Context, key any, count int) (val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LPopCount(getCtx(ctx), r.k(key), count).Result()
return err
}, acceptable)
return
}
func (r *Client) LPos(ctx context.Context, key any, value string, args redis.LPosArgs) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LPos(getCtx(ctx), r.k(key), value, args).Result()
return err
}, acceptable)
return
}
func (r *Client) LPosCount(ctx context.Context, key any, value string, count int64, args redis.LPosArgs) (val []int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LPosCount(getCtx(ctx), r.k(key), value, count, args).Result()
return err
}, acceptable)
return
}
// LPush 将一个或多个值 value 插入到列表 key 的表头
// 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头
// 如果 key 不存在,一个空列表会被创建并执行 LPush 操作。
// 当 key 存在但不是列表类型时,返回一个错误。
func (r *Client) LPush(ctx context.Context, key any, values ...any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LPush(getCtx(ctx), r.k(key), values...).Result()
return err
}, acceptable)
return
}
// LPushX 将值 value 插入到列表 key 的表头,当且仅当 key 存在并且是一个列表。
// 和 LPUSH 命令相反,当 key 不存在时, LPUSHX 命令什么也不做。
func (r *Client) LPushX(ctx context.Context, key any, value any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LPushX(getCtx(ctx), r.k(key), value).Result()
return err
}, acceptable)
return
}
// LRange 返回列表 key 中指定区间内的元素,区间以偏移量 start 和 stop 指定。
// 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
func (r *Client) LRange(ctx context.Context, key any, start, stop int64) (val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LRange(getCtx(ctx), r.k(key), start, stop).Result()
return err
}, acceptable)
return
}
// LRem 根据参数 count 的值,移除列表中与参数 value 相等的元素。
func (r *Client) LRem(ctx context.Context, key any, count int64, value any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LRem(getCtx(ctx), r.k(key), count, value).Result()
return err
}, acceptable)
return
}
// LSet 将列表 key 下标为 index 的元素的值设置为 value 。
// 当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。
// 关于列表下标的更多信息,请参考 LINDEX 命令。
func (r *Client) LSet(ctx context.Context, key any, index int64, value any) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LSet(getCtx(ctx), r.k(key), index, value).Result()
return err
}, acceptable)
return
}
// LTrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
// 举个例子,执行命令 LTRIM list 0 2 ,表示只保留列表 list 的前三个元素,其余元素全部删除。
// 下标(index)参数 start 和 stop 都以 0 为底,也就是说,以 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。
// 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。
// 当 key 不是列表类型时,返回一个错误。
func (r *Client) LTrim(ctx context.Context, key any, start, stop int64) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LTrim(getCtx(ctx), r.k(key), start, stop).Result()
return err
}, acceptable)
return
}
// RPop 移除并返回列表 key 的头元素。
func (r *Client) RPop(ctx context.Context, key any) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.RPop(getCtx(ctx), r.k(key)).Result()
return err
}, acceptable)
return
}
// RPopCount 移除并返回列表 key 的头元素。
func (r *Client) RPopCount(ctx context.Context, key any, count int) (val []string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.RPopCount(getCtx(ctx), r.k(key), count).Result()
return err
}, acceptable)
return
}
// RPopLPush 命令 RPOPLPUSH 在一个原子时间内,执行以下两个动作:
// 将列表 source 中的最后一个元素(尾元素)弹出,并返回给客户端。
// 将 source 弹出的元素插入到列表 destination ,作为 destination 列表的的头元素。
// 举个例子,你有两个列表 source 和 destination , source 列表有元素 a, b, c , destination 列表有元素 x, y, z ,执行 RPOPLPUSH source destination 之后, source 列表包含元素 a, b , destination 列表包含元素 c, x, y, z ,并且元素 c 会被返回给客户端。
// 如果 source 不存在,值 nil 被返回,并且不执行其他动作。
// 如果 source 和 destination 相同,则列表中的表尾元素被移动到表头,并返回该元素,可以把这种特殊情况视作列表的旋转(rotation)操作。
func (r *Client) RPopLPush(ctx context.Context, source, destination any) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.RPopLPush(getCtx(ctx), r.k(source), r.k(destination)).Result()
return err
}, acceptable)
return
}
// RPush 将一个或多个值 value 插入到列表 key 的表尾(最右边)。
// 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表尾:比如对一个空列表 mylist 执行 RPUSH mylist a b c ,得出的结果列表为 a b c ,等同于执行命令 RPUSH mylist a 、 RPUSH mylist b 、 RPUSH mylist c 。
// 如果 key 不存在,一个空列表会被创建并执行 RPUSH 操作。
// 当 key 存在但不是列表类型时,返回一个错误。
func (r *Client) RPush(ctx context.Context, key any, values ...any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.RPush(getCtx(ctx), r.k(key), values...).Result()
return err
}, acceptable)
return
}
// RPushX 将值 value 插入到列表 key 的表尾,当且仅当 key 存在并且是一个列表。
// 和 RPUSH 命令相反,当 key 不存在时, RPUSHX 命令什么也不做。
func (r *Client) RPushX(ctx context.Context, key any, value any) (val int64, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.RPushX(getCtx(ctx), r.k(key), value).Result()
return err
}, acceptable)
return
}
func (r *Client) LMove(ctx context.Context, source, destination, srcpos, destpos any) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.LMove(getCtx(ctx), r.k(source), r.k(destination), r.k(srcpos), r.k(destpos)).Result()
return err
}, acceptable)
return
}
func (r *Client) BLMove(ctx context.Context, source, destination, srcpos, destpos any, ts time.Duration) (val string, err error) {
err = r.brk.DoWithAcceptable(func() error {
conn, err := getRedis(r)
if err != nil {
return err
}
val, err = conn.BLMove(getCtx(ctx), r.k(source), r.k(destination), r.k(srcpos), r.k(destpos), ts).Result()
return err
}, acceptable)
return
}