build(deps): bump github.com/redis/go-redis/v9 from 9.1.0 to 9.2.1 (#7107)
Bumps https://github.com/redis/go-redis from 9.1.0 to 9.2.1. - Release notes: https://github.com/redis/go-redis/releases/tag/v9.2.1 - Changelog: https://github.com/redis/go-redis/compare/v9.1.0...v9.2.1
This commit is contained in:
parent
c84201c09a
commit
50ec4786e4
2
go.mod
2
go.mod
|
|
@ -23,7 +23,7 @@ require (
|
|||
github.com/miekg/pkcs11 v1.1.1
|
||||
github.com/prometheus/client_golang v1.15.1
|
||||
github.com/prometheus/client_model v0.4.0
|
||||
github.com/redis/go-redis/v9 v9.1.0
|
||||
github.com/redis/go-redis/v9 v9.2.1
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399
|
||||
github.com/weppos/publicsuffix-go v0.30.1-0.20230620154423-38c92ad2d5c6
|
||||
github.com/zmap/zcrypto v0.0.0-20230310154051-c8b263fd8300
|
||||
|
|
|
|||
12
go.sum
12
go.sum
|
|
@ -91,10 +91,10 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
|||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bsm/ginkgo/v2 v2.9.5 h1:rtVBYPs3+TC5iLUVOis1B9tjLTup7Cj5IfzosKtvTJ0=
|
||||
github.com/bsm/ginkgo/v2 v2.9.5/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.26.0 h1:LhQm+AFcgV2M0WyKroMASzAzCAJVpAxQXv4SaI9a69Y=
|
||||
github.com/bsm/gomega v1.26.0/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||
|
|
@ -329,8 +329,8 @@ github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7z
|
|||
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
|
||||
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/redis/go-redis/v9 v9.1.0 h1:137FnGdk+EQdCbye1FW+qOEcY5S+SpY9T0NiuqvtfMY=
|
||||
github.com/redis/go-redis/v9 v9.1.0/go.mod h1:urWj3He21Dj5k4TK1y59xH8Uj6ATueP8AH1cY3lZl4c=
|
||||
github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg=
|
||||
github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
|
|
|||
|
|
@ -2,3 +2,5 @@
|
|||
testdata/*
|
||||
.idea/
|
||||
.DS_Store
|
||||
*.tar.gz
|
||||
*.dic
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
# Contributing
|
||||
|
||||
## Introduction
|
||||
|
||||
We appreciate your interest in considering contributing to go-redis.
|
||||
Community contributions mean a lot to us.
|
||||
|
||||
## Contributions we need
|
||||
|
||||
You may already know how you'd like to contribute, whether it's a fix for a bug you
|
||||
encountered, or a new feature your team wants to use.
|
||||
|
||||
If you don't know where to start, consider improving
|
||||
documentation, bug triaging, and writing tutorials are all examples of
|
||||
helpful contributions that mean less work for you.
|
||||
|
||||
## Your First Contribution
|
||||
|
||||
Unsure where to begin contributing? You can start by looking through
|
||||
[help-wanted
|
||||
issues](https://github.com/redis/go-redis/issues?q=is%3Aopen+is%3Aissue+label%3ahelp-wanted).
|
||||
|
||||
Never contributed to open source before? Here are a couple of friendly
|
||||
tutorials:
|
||||
|
||||
- <http://makeapullrequest.com/>
|
||||
- <http://www.firsttimersonly.com/>
|
||||
|
||||
## Getting Started
|
||||
|
||||
Here's how to get started with your code contribution:
|
||||
|
||||
1. Create your own fork of go-redis
|
||||
2. Do the changes in your fork
|
||||
3. If you need a development environment, run `make test`. Note: this clones and builds the latest release of [redis](https://redis.io). You also need a redis-stack-server docker, in order to run the capabilities tests. This can be started by running:
|
||||
```docker run -p 6379:6379 -it redis/redis-stack-server:edge```
|
||||
4. While developing, make sure the tests pass by running `make tests`
|
||||
5. If you like the change and think the project could use it, send a
|
||||
pull request
|
||||
|
||||
To see what else is part of the automation, run `invoke -l`
|
||||
|
||||
## Testing
|
||||
|
||||
Call `make test` to run all tests, including linters.
|
||||
|
||||
Continuous Integration uses these same wrappers to run all of these
|
||||
tests against multiple versions of python. Feel free to test your
|
||||
changes against all the go versions supported, as declared by the
|
||||
[build.yml](./.github/workflows/build.yml) file.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
If you get any errors when running `make test`, make sure
|
||||
that you are using supported versions of Docker and go.
|
||||
|
||||
## How to Report a Bug
|
||||
|
||||
### Security Vulnerabilities
|
||||
|
||||
**NOTE**: If you find a security vulnerability, do NOT open an issue.
|
||||
Email [Redis Open Source (<oss@redis.com>)](mailto:oss@redis.com) instead.
|
||||
|
||||
In order to determine whether you are dealing with a security issue, ask
|
||||
yourself these two questions:
|
||||
|
||||
- Can I access something that's not mine, or something I shouldn't
|
||||
have access to?
|
||||
- Can I disable something for other people?
|
||||
|
||||
If the answer to either of those two questions are *yes*, then you're
|
||||
probably dealing with a security issue. Note that even if you answer
|
||||
*no* to both questions, you may still be dealing with a security
|
||||
issue, so if you're unsure, just email [us](mailto:oss@redis.com).
|
||||
|
||||
### Everything Else
|
||||
|
||||
When filing an issue, make sure to answer these five questions:
|
||||
|
||||
1. What version of go-redis are you using?
|
||||
2. What version of redis are you using?
|
||||
3. What did you do?
|
||||
4. What did you expect to see?
|
||||
5. What did you see instead?
|
||||
|
||||
## Suggest a feature or enhancement
|
||||
|
||||
If you'd like to contribute a new feature, make sure you check our
|
||||
issue list to see if someone has already proposed it. Work may already
|
||||
be underway on the feature you want or we may have rejected a
|
||||
feature like it already.
|
||||
|
||||
If you don't see anything, open a new issue that describes the feature
|
||||
you would like and how it should work.
|
||||
|
||||
## Code review process
|
||||
|
||||
The core team regularly looks at pull requests. We will provide
|
||||
feedback as soon as possible. After receiving our feedback, please respond
|
||||
within two weeks. After that time, we may close your PR if it isn't
|
||||
showing any activity.
|
||||
|
|
@ -19,17 +19,20 @@ testdeps: testdata/redis/src/redis-server
|
|||
bench: testdeps
|
||||
go test ./... -test.run=NONE -test.bench=. -test.benchmem
|
||||
|
||||
.PHONY: all test testdeps bench
|
||||
.PHONY: all test testdeps bench fmt
|
||||
|
||||
build:
|
||||
go build .
|
||||
|
||||
testdata/redis:
|
||||
mkdir -p $@
|
||||
wget -qO- https://download.redis.io/releases/redis-7.2-rc3.tar.gz | tar xvz --strip-components=1 -C $@
|
||||
wget -qO- https://download.redis.io/releases/redis-7.2.1.tar.gz | tar xvz --strip-components=1 -C $@
|
||||
|
||||
testdata/redis/src/redis-server: testdata/redis
|
||||
cd $< && make all
|
||||
|
||||
fmt:
|
||||
gofmt -w -s ./
|
||||
gofumpt -w ./
|
||||
goimports -w -local github.com/redis/go-redis ./
|
||||
|
||||
go_mod_tidy:
|
||||
|
|
|
|||
|
|
@ -69,8 +69,9 @@ go get github.com/redis/go-redis/v9
|
|||
```go
|
||||
import (
|
||||
"context"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"fmt"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
|
|
@ -125,8 +126,9 @@ go-redis also supports connecting via the [redis uri specification](https://gith
|
|||
```go
|
||||
import (
|
||||
"context"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"fmt"
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
|
|
@ -140,6 +142,10 @@ func ExampleClient() {
|
|||
rdb := redis.NewClient(opts)
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [out contributing guidelines](CONTRIBUTING.md) to help us improve this library!
|
||||
|
||||
## Look and feel
|
||||
|
||||
Some corner cases:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type ACLCmdable interface {
|
||||
ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd
|
||||
ACLLog(ctx context.Context, count int64) *ACLLogCmd
|
||||
ACLLogReset(ctx context.Context) *StatusCmd
|
||||
}
|
||||
|
||||
func (c cmdable) ACLDryRun(ctx context.Context, username string, command ...interface{}) *StringCmd {
|
||||
args := make([]interface{}, 0, 3+len(command))
|
||||
args = append(args, "acl", "dryrun", username)
|
||||
args = append(args, command...)
|
||||
cmd := NewStringCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ACLLog(ctx context.Context, count int64) *ACLLogCmd {
|
||||
args := make([]interface{}, 0, 3)
|
||||
args = append(args, "acl", "log")
|
||||
if count > 0 {
|
||||
args = append(args, count)
|
||||
}
|
||||
cmd := NewACLLogCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ACLLogReset(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "acl", "log", "reset")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type BitMapCmdable interface {
|
||||
GetBit(ctx context.Context, key string, offset int64) *IntCmd
|
||||
SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd
|
||||
BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd
|
||||
BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd
|
||||
BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd
|
||||
BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd
|
||||
BitOpNot(ctx context.Context, destKey string, key string) *IntCmd
|
||||
BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd
|
||||
BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd
|
||||
BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd
|
||||
}
|
||||
|
||||
func (c cmdable) GetBit(ctx context.Context, key string, offset int64) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "getbit", key, offset)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SetBit(ctx context.Context, key string, offset int64, value int) *IntCmd {
|
||||
cmd := NewIntCmd(
|
||||
ctx,
|
||||
"setbit",
|
||||
key,
|
||||
offset,
|
||||
value,
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type BitCount struct {
|
||||
Start, End int64
|
||||
}
|
||||
|
||||
func (c cmdable) BitCount(ctx context.Context, key string, bitCount *BitCount) *IntCmd {
|
||||
args := []interface{}{"bitcount", key}
|
||||
if bitCount != nil {
|
||||
args = append(
|
||||
args,
|
||||
bitCount.Start,
|
||||
bitCount.End,
|
||||
)
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) bitOp(ctx context.Context, op, destKey string, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 3+len(keys))
|
||||
args[0] = "bitop"
|
||||
args[1] = op
|
||||
args[2] = destKey
|
||||
for i, key := range keys {
|
||||
args[3+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) BitOpAnd(ctx context.Context, destKey string, keys ...string) *IntCmd {
|
||||
return c.bitOp(ctx, "and", destKey, keys...)
|
||||
}
|
||||
|
||||
func (c cmdable) BitOpOr(ctx context.Context, destKey string, keys ...string) *IntCmd {
|
||||
return c.bitOp(ctx, "or", destKey, keys...)
|
||||
}
|
||||
|
||||
func (c cmdable) BitOpXor(ctx context.Context, destKey string, keys ...string) *IntCmd {
|
||||
return c.bitOp(ctx, "xor", destKey, keys...)
|
||||
}
|
||||
|
||||
func (c cmdable) BitOpNot(ctx context.Context, destKey string, key string) *IntCmd {
|
||||
return c.bitOp(ctx, "not", destKey, key)
|
||||
}
|
||||
|
||||
// BitPos is an API before Redis version 7.0, cmd: bitpos key bit start end
|
||||
// if you need the `byte | bit` parameter, please use `BitPosSpan`.
|
||||
func (c cmdable) BitPos(ctx context.Context, key string, bit int64, pos ...int64) *IntCmd {
|
||||
args := make([]interface{}, 3+len(pos))
|
||||
args[0] = "bitpos"
|
||||
args[1] = key
|
||||
args[2] = bit
|
||||
switch len(pos) {
|
||||
case 0:
|
||||
case 1:
|
||||
args[3] = pos[0]
|
||||
case 2:
|
||||
args[3] = pos[0]
|
||||
args[4] = pos[1]
|
||||
default:
|
||||
panic("too many arguments")
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// BitPosSpan supports the `byte | bit` parameters in redis version 7.0,
|
||||
// the bitpos command defaults to using byte type for the `start-end` range,
|
||||
// which means it counts in bytes from start to end. you can set the value
|
||||
// of "span" to determine the type of `start-end`.
|
||||
// span = "bit", cmd: bitpos key bit start end bit
|
||||
// span = "byte", cmd: bitpos key bit start end byte
|
||||
func (c cmdable) BitPosSpan(ctx context.Context, key string, bit int8, start, end int64, span string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "bitpos", key, bit, start, end, span)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// BitField accepts multiple values:
|
||||
// - BitField("set", "i1", "offset1", "value1","cmd2", "type2", "offset2", "value2")
|
||||
// - BitField([]string{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"})
|
||||
// - BitField([]interface{}{"cmd1", "type1", "offset1", "value1","cmd2", "type2", "offset2", "value2"})
|
||||
func (c cmdable) BitField(ctx context.Context, key string, values ...interface{}) *IntSliceCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "bitfield"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewIntSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -1,109 +1,192 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
import "context"
|
||||
|
||||
func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "dbsize")
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
var size int64
|
||||
err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error {
|
||||
n, err := master.DBSize(ctx).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.AddInt64(&size, n)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
} else {
|
||||
cmd.val = size
|
||||
}
|
||||
return nil
|
||||
})
|
||||
type ClusterCmdable interface {
|
||||
ClusterMyShardID(ctx context.Context) *StringCmd
|
||||
ClusterSlots(ctx context.Context) *ClusterSlotsCmd
|
||||
ClusterShards(ctx context.Context) *ClusterShardsCmd
|
||||
ClusterLinks(ctx context.Context) *ClusterLinksCmd
|
||||
ClusterNodes(ctx context.Context) *StringCmd
|
||||
ClusterMeet(ctx context.Context, host, port string) *StatusCmd
|
||||
ClusterForget(ctx context.Context, nodeID string) *StatusCmd
|
||||
ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd
|
||||
ClusterResetSoft(ctx context.Context) *StatusCmd
|
||||
ClusterResetHard(ctx context.Context) *StatusCmd
|
||||
ClusterInfo(ctx context.Context) *StringCmd
|
||||
ClusterKeySlot(ctx context.Context, key string) *IntCmd
|
||||
ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd
|
||||
ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd
|
||||
ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd
|
||||
ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd
|
||||
ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd
|
||||
ClusterSaveConfig(ctx context.Context) *StatusCmd
|
||||
ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd
|
||||
ClusterFailover(ctx context.Context) *StatusCmd
|
||||
ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd
|
||||
ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd
|
||||
ReadOnly(ctx context.Context) *StatusCmd
|
||||
ReadWrite(ctx context.Context) *StatusCmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterMyShardID(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "cluster", "myshardid")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ClusterClient) ScriptLoad(ctx context.Context, script string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "script", "load", script)
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
var mu sync.Mutex
|
||||
err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
|
||||
val, err := shard.ScriptLoad(ctx, script).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
if cmd.Val() == "" {
|
||||
cmd.val = val
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
func (c cmdable) ClusterSlots(ctx context.Context) *ClusterSlotsCmd {
|
||||
cmd := NewClusterSlotsCmd(ctx, "cluster", "slots")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ClusterClient) ScriptFlush(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "script", "flush")
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
|
||||
return shard.ScriptFlush(ctx).Err()
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
func (c cmdable) ClusterShards(ctx context.Context) *ClusterShardsCmd {
|
||||
cmd := NewClusterShardsCmd(ctx, "cluster", "shards")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ClusterClient) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
|
||||
args := make([]interface{}, 2+len(hashes))
|
||||
args[0] = "script"
|
||||
args[1] = "exists"
|
||||
for i, hash := range hashes {
|
||||
args[2+i] = hash
|
||||
func (c cmdable) ClusterLinks(ctx context.Context) *ClusterLinksCmd {
|
||||
cmd := NewClusterLinksCmd(ctx, "cluster", "links")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterNodes(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "cluster", "nodes")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterMeet(ctx context.Context, host, port string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "meet", host, port)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterForget(ctx context.Context, nodeID string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "forget", nodeID)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterReplicate(ctx context.Context, nodeID string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "replicate", nodeID)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterResetSoft(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "reset", "soft")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterResetHard(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "reset", "hard")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterInfo(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "cluster", "info")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterKeySlot(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "cluster", "keyslot", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterGetKeysInSlot(ctx context.Context, slot int, count int) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "cluster", "getkeysinslot", slot, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterCountFailureReports(ctx context.Context, nodeID string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "cluster", "count-failure-reports", nodeID)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterCountKeysInSlot(ctx context.Context, slot int) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "cluster", "countkeysinslot", slot)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterDelSlots(ctx context.Context, slots ...int) *StatusCmd {
|
||||
args := make([]interface{}, 2+len(slots))
|
||||
args[0] = "cluster"
|
||||
args[1] = "delslots"
|
||||
for i, slot := range slots {
|
||||
args[2+i] = slot
|
||||
}
|
||||
cmd := NewBoolSliceCmd(ctx, args...)
|
||||
|
||||
result := make([]bool, len(hashes))
|
||||
for i := range result {
|
||||
result[i] = true
|
||||
}
|
||||
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
var mu sync.Mutex
|
||||
err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
|
||||
val, err := shard.ScriptExists(ctx, hashes...).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
for i, v := range val {
|
||||
result[i] = result[i] && v
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
} else {
|
||||
cmd.val = result
|
||||
}
|
||||
return nil
|
||||
})
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterDelSlotsRange(ctx context.Context, min, max int) *StatusCmd {
|
||||
size := max - min + 1
|
||||
slots := make([]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
slots[i] = min + i
|
||||
}
|
||||
return c.ClusterDelSlots(ctx, slots...)
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterSaveConfig(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "saveconfig")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterSlaves(ctx context.Context, nodeID string) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "cluster", "slaves", nodeID)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterFailover(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "cluster", "failover")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterAddSlots(ctx context.Context, slots ...int) *StatusCmd {
|
||||
args := make([]interface{}, 2+len(slots))
|
||||
args[0] = "cluster"
|
||||
args[1] = "addslots"
|
||||
for i, num := range slots {
|
||||
args[2+i] = num
|
||||
}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ClusterAddSlotsRange(ctx context.Context, min, max int) *StatusCmd {
|
||||
size := max - min + 1
|
||||
slots := make([]int, size)
|
||||
for i := 0; i < size; i++ {
|
||||
slots[i] = min + i
|
||||
}
|
||||
return c.ClusterAddSlots(ctx, slots...)
|
||||
}
|
||||
|
||||
func (c cmdable) ReadOnly(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "readonly")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ReadWrite(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "readwrite")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1351,6 +1351,65 @@ func (cmd *MapStringIntCmd) readReply(rd *proto.Reader) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
type MapStringSliceInterfaceCmd struct {
|
||||
baseCmd
|
||||
val map[string][]interface{}
|
||||
}
|
||||
|
||||
func NewMapStringSliceInterfaceCmd(ctx context.Context, args ...interface{}) *MapStringSliceInterfaceCmd {
|
||||
return &MapStringSliceInterfaceCmd{
|
||||
baseCmd: baseCmd{
|
||||
ctx: ctx,
|
||||
args: args,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *MapStringSliceInterfaceCmd) String() string {
|
||||
return cmdString(cmd, cmd.val)
|
||||
}
|
||||
|
||||
func (cmd *MapStringSliceInterfaceCmd) SetVal(val map[string][]interface{}) {
|
||||
cmd.val = val
|
||||
}
|
||||
|
||||
func (cmd *MapStringSliceInterfaceCmd) Result() (map[string][]interface{}, error) {
|
||||
return cmd.val, cmd.err
|
||||
}
|
||||
|
||||
func (cmd *MapStringSliceInterfaceCmd) Val() map[string][]interface{} {
|
||||
return cmd.val
|
||||
}
|
||||
|
||||
func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
|
||||
n, err := rd.ReadMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val = make(map[string][]interface{}, n)
|
||||
for i := 0; i < n; i++ {
|
||||
k, err := rd.ReadString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nn, err := rd.ReadArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val[k] = make([]interface{}, nn)
|
||||
for j := 0; j < nn; j++ {
|
||||
value, err := rd.ReadReply()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val[k][j] = value
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
type StringStructMapCmd struct {
|
||||
|
|
@ -4265,7 +4324,6 @@ func (cmd *FunctionStatsCmd) readDuration(rd *proto.Reader) (time.Duration, erro
|
|||
}
|
||||
|
||||
func (cmd *FunctionStatsCmd) readCommand(rd *proto.Reader) ([]string, error) {
|
||||
|
||||
n, err := rd.ReadArrayLen()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -4282,6 +4340,7 @@ func (cmd *FunctionStatsCmd) readCommand(rd *proto.Reader) ([]string, error) {
|
|||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
func (cmd *FunctionStatsCmd) readRunningScripts(rd *proto.Reader) ([]RunningScript, bool, error) {
|
||||
n, err := rd.ReadArrayLen()
|
||||
if err != nil {
|
||||
|
|
@ -5233,3 +5292,9 @@ func (cmd *ACLLogCmd) readReply(rd *proto.Reader) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LibraryInfo holds the library info.
|
||||
type LibraryInfo struct {
|
||||
LibName *string
|
||||
LibVer *string
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
type gearsCmdable interface {
|
||||
type GearsCmdable interface {
|
||||
TFunctionLoad(ctx context.Context, lib string) *StatusCmd
|
||||
TFunctionLoadArgs(ctx context.Context, lib string, options *TFunctionLoadOptions) *StatusCmd
|
||||
TFunctionDelete(ctx context.Context, libName string) *StatusCmd
|
||||
|
|
@ -17,6 +17,7 @@ type gearsCmdable interface {
|
|||
TFCallASYNC(ctx context.Context, libName string, funcName string, numKeys int) *Cmd
|
||||
TFCallASYNCArgs(ctx context.Context, libName string, funcName string, numKeys int, options *TFCallOptions) *Cmd
|
||||
}
|
||||
|
||||
type TFunctionLoadOptions struct {
|
||||
Replace bool
|
||||
Config string
|
||||
|
|
@ -88,7 +89,6 @@ func (c cmdable) TFunctionListArgs(ctx context.Context, options *TFunctionListOp
|
|||
}
|
||||
if options.Library != "" {
|
||||
args = append(args, "LIBRARY", options.Library)
|
||||
|
||||
}
|
||||
}
|
||||
cmd := NewMapStringInterfaceSliceCmd(ctx, args...)
|
||||
|
|
@ -110,17 +110,11 @@ func (c cmdable) TFCallArgs(ctx context.Context, libName string, funcName string
|
|||
lf := libName + "." + funcName
|
||||
args := []interface{}{"TFCALL", lf, numKeys}
|
||||
if options != nil {
|
||||
if options.Keys != nil {
|
||||
for _, key := range options.Keys {
|
||||
|
||||
args = append(args, key)
|
||||
}
|
||||
for _, key := range options.Keys {
|
||||
args = append(args, key)
|
||||
}
|
||||
if options.Arguments != nil {
|
||||
for _, key := range options.Arguments {
|
||||
|
||||
args = append(args, key)
|
||||
}
|
||||
for _, key := range options.Arguments {
|
||||
args = append(args, key)
|
||||
}
|
||||
}
|
||||
cmd := NewCmd(ctx, args...)
|
||||
|
|
@ -142,17 +136,11 @@ func (c cmdable) TFCallASYNCArgs(ctx context.Context, libName string, funcName s
|
|||
lf := fmt.Sprintf("%s.%s", libName, funcName)
|
||||
args := []interface{}{"TFCALLASYNC", lf, numKeys}
|
||||
if options != nil {
|
||||
if options.Keys != nil {
|
||||
for _, key := range options.Keys {
|
||||
|
||||
args = append(args, key)
|
||||
}
|
||||
for _, key := range options.Keys {
|
||||
args = append(args, key)
|
||||
}
|
||||
if options.Arguments != nil {
|
||||
for _, key := range options.Arguments {
|
||||
|
||||
args = append(args, key)
|
||||
}
|
||||
for _, key := range options.Arguments {
|
||||
args = append(args, key)
|
||||
}
|
||||
}
|
||||
cmd := NewCmd(ctx, args...)
|
||||
|
|
@ -0,0 +1,377 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type GenericCmdable interface {
|
||||
Del(ctx context.Context, keys ...string) *IntCmd
|
||||
Dump(ctx context.Context, key string) *StringCmd
|
||||
Exists(ctx context.Context, keys ...string) *IntCmd
|
||||
Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
|
||||
ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
|
||||
ExpireTime(ctx context.Context, key string) *DurationCmd
|
||||
ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
|
||||
ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd
|
||||
ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
|
||||
ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd
|
||||
Keys(ctx context.Context, pattern string) *StringSliceCmd
|
||||
Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd
|
||||
Move(ctx context.Context, key string, db int) *BoolCmd
|
||||
ObjectRefCount(ctx context.Context, key string) *IntCmd
|
||||
ObjectEncoding(ctx context.Context, key string) *StringCmd
|
||||
ObjectIdleTime(ctx context.Context, key string) *DurationCmd
|
||||
Persist(ctx context.Context, key string) *BoolCmd
|
||||
PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd
|
||||
PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd
|
||||
PExpireTime(ctx context.Context, key string) *DurationCmd
|
||||
PTTL(ctx context.Context, key string) *DurationCmd
|
||||
RandomKey(ctx context.Context) *StringCmd
|
||||
Rename(ctx context.Context, key, newkey string) *StatusCmd
|
||||
RenameNX(ctx context.Context, key, newkey string) *BoolCmd
|
||||
Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
|
||||
RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd
|
||||
Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd
|
||||
SortRO(ctx context.Context, key string, sort *Sort) *StringSliceCmd
|
||||
SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd
|
||||
SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd
|
||||
Touch(ctx context.Context, keys ...string) *IntCmd
|
||||
TTL(ctx context.Context, key string) *DurationCmd
|
||||
Type(ctx context.Context, key string) *StatusCmd
|
||||
Copy(ctx context.Context, sourceKey string, destKey string, db int, replace bool) *IntCmd
|
||||
|
||||
Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd
|
||||
ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd
|
||||
}
|
||||
|
||||
func (c cmdable) Del(ctx context.Context, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "del"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Unlink(ctx context.Context, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "unlink"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Dump(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "dump", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Exists(ctx context.Context, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "exists"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Expire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
|
||||
return c.expire(ctx, key, expiration, "")
|
||||
}
|
||||
|
||||
func (c cmdable) ExpireNX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
|
||||
return c.expire(ctx, key, expiration, "NX")
|
||||
}
|
||||
|
||||
func (c cmdable) ExpireXX(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
|
||||
return c.expire(ctx, key, expiration, "XX")
|
||||
}
|
||||
|
||||
func (c cmdable) ExpireGT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
|
||||
return c.expire(ctx, key, expiration, "GT")
|
||||
}
|
||||
|
||||
func (c cmdable) ExpireLT(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
|
||||
return c.expire(ctx, key, expiration, "LT")
|
||||
}
|
||||
|
||||
func (c cmdable) expire(
|
||||
ctx context.Context, key string, expiration time.Duration, mode string,
|
||||
) *BoolCmd {
|
||||
args := make([]interface{}, 3, 4)
|
||||
args[0] = "expire"
|
||||
args[1] = key
|
||||
args[2] = formatSec(ctx, expiration)
|
||||
if mode != "" {
|
||||
args = append(args, mode)
|
||||
}
|
||||
|
||||
cmd := NewBoolCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "expireat", key, tm.Unix())
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ExpireTime(ctx context.Context, key string) *DurationCmd {
|
||||
cmd := NewDurationCmd(ctx, time.Second, "expiretime", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Keys(ctx context.Context, pattern string) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "keys", pattern)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Migrate(ctx context.Context, host, port, key string, db int, timeout time.Duration) *StatusCmd {
|
||||
cmd := NewStatusCmd(
|
||||
ctx,
|
||||
"migrate",
|
||||
host,
|
||||
port,
|
||||
key,
|
||||
db,
|
||||
formatMs(ctx, timeout),
|
||||
)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Move(ctx context.Context, key string, db int) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "move", key, db)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ObjectRefCount(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "object", "refcount", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ObjectEncoding(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "object", "encoding", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ObjectIdleTime(ctx context.Context, key string) *DurationCmd {
|
||||
cmd := NewDurationCmd(ctx, time.Second, "object", "idletime", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Persist(ctx context.Context, key string) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "persist", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PExpire(ctx context.Context, key string, expiration time.Duration) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "pexpire", key, formatMs(ctx, expiration))
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PExpireAt(ctx context.Context, key string, tm time.Time) *BoolCmd {
|
||||
cmd := NewBoolCmd(
|
||||
ctx,
|
||||
"pexpireat",
|
||||
key,
|
||||
tm.UnixNano()/int64(time.Millisecond),
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PExpireTime(ctx context.Context, key string) *DurationCmd {
|
||||
cmd := NewDurationCmd(ctx, time.Millisecond, "pexpiretime", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PTTL(ctx context.Context, key string) *DurationCmd {
|
||||
cmd := NewDurationCmd(ctx, time.Millisecond, "pttl", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RandomKey(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "randomkey")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Rename(ctx context.Context, key, newkey string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "rename", key, newkey)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RenameNX(ctx context.Context, key, newkey string) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "renamenx", key, newkey)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Restore(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
|
||||
cmd := NewStatusCmd(
|
||||
ctx,
|
||||
"restore",
|
||||
key,
|
||||
formatMs(ctx, ttl),
|
||||
value,
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RestoreReplace(ctx context.Context, key string, ttl time.Duration, value string) *StatusCmd {
|
||||
cmd := NewStatusCmd(
|
||||
ctx,
|
||||
"restore",
|
||||
key,
|
||||
formatMs(ctx, ttl),
|
||||
value,
|
||||
"replace",
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type Sort struct {
|
||||
By string
|
||||
Offset, Count int64
|
||||
Get []string
|
||||
Order string
|
||||
Alpha bool
|
||||
}
|
||||
|
||||
func (sort *Sort) args(command, key string) []interface{} {
|
||||
args := []interface{}{command, key}
|
||||
|
||||
if sort.By != "" {
|
||||
args = append(args, "by", sort.By)
|
||||
}
|
||||
if sort.Offset != 0 || sort.Count != 0 {
|
||||
args = append(args, "limit", sort.Offset, sort.Count)
|
||||
}
|
||||
for _, get := range sort.Get {
|
||||
args = append(args, "get", get)
|
||||
}
|
||||
if sort.Order != "" {
|
||||
args = append(args, sort.Order)
|
||||
}
|
||||
if sort.Alpha {
|
||||
args = append(args, "alpha")
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func (c cmdable) SortRO(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, sort.args("sort_ro", key)...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Sort(ctx context.Context, key string, sort *Sort) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, sort.args("sort", key)...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SortStore(ctx context.Context, key, store string, sort *Sort) *IntCmd {
|
||||
args := sort.args("sort", key)
|
||||
if store != "" {
|
||||
args = append(args, "store", store)
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SortInterfaces(ctx context.Context, key string, sort *Sort) *SliceCmd {
|
||||
cmd := NewSliceCmd(ctx, sort.args("sort", key)...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Touch(ctx context.Context, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, len(keys)+1)
|
||||
args[0] = "touch"
|
||||
for i, key := range keys {
|
||||
args[i+1] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) TTL(ctx context.Context, key string) *DurationCmd {
|
||||
cmd := NewDurationCmd(ctx, time.Second, "ttl", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Type(ctx context.Context, key string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "type", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Copy(ctx context.Context, sourceKey, destKey string, db int, replace bool) *IntCmd {
|
||||
args := []interface{}{"copy", sourceKey, destKey, "DB", db}
|
||||
if replace {
|
||||
args = append(args, "REPLACE")
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (c cmdable) Scan(ctx context.Context, cursor uint64, match string, count int64) *ScanCmd {
|
||||
args := []interface{}{"scan", cursor}
|
||||
if match != "" {
|
||||
args = append(args, "match", match)
|
||||
}
|
||||
if count > 0 {
|
||||
args = append(args, "count", count)
|
||||
}
|
||||
cmd := NewScanCmd(ctx, c, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ScanType(ctx context.Context, cursor uint64, match string, count int64, keyType string) *ScanCmd {
|
||||
args := []interface{}{"scan", cursor}
|
||||
if match != "" {
|
||||
args = append(args, "match", match)
|
||||
}
|
||||
if count > 0 {
|
||||
args = append(args, "count", count)
|
||||
}
|
||||
if keyType != "" {
|
||||
args = append(args, "type", keyType)
|
||||
}
|
||||
cmd := NewScanCmd(ctx, c, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type GeoCmdable interface {
|
||||
GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd
|
||||
GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd
|
||||
GeoRadius(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *GeoLocationCmd
|
||||
GeoRadiusStore(ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery) *IntCmd
|
||||
GeoRadiusByMember(ctx context.Context, key, member string, query *GeoRadiusQuery) *GeoLocationCmd
|
||||
GeoRadiusByMemberStore(ctx context.Context, key, member string, query *GeoRadiusQuery) *IntCmd
|
||||
GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd
|
||||
GeoSearchLocation(ctx context.Context, key string, q *GeoSearchLocationQuery) *GeoSearchLocationCmd
|
||||
GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd
|
||||
GeoDist(ctx context.Context, key string, member1, member2, unit string) *FloatCmd
|
||||
GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoAdd(ctx context.Context, key string, geoLocation ...*GeoLocation) *IntCmd {
|
||||
args := make([]interface{}, 2+3*len(geoLocation))
|
||||
args[0] = "geoadd"
|
||||
args[1] = key
|
||||
for i, eachLoc := range geoLocation {
|
||||
args[2+3*i] = eachLoc.Longitude
|
||||
args[2+3*i+1] = eachLoc.Latitude
|
||||
args[2+3*i+2] = eachLoc.Name
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GeoRadius is a read-only GEORADIUS_RO command.
|
||||
func (c cmdable) GeoRadius(
|
||||
ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
|
||||
) *GeoLocationCmd {
|
||||
cmd := NewGeoLocationCmd(ctx, query, "georadius_ro", key, longitude, latitude)
|
||||
if query.Store != "" || query.StoreDist != "" {
|
||||
cmd.SetErr(errors.New("GeoRadius does not support Store or StoreDist"))
|
||||
return cmd
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GeoRadiusStore is a writing GEORADIUS command.
|
||||
func (c cmdable) GeoRadiusStore(
|
||||
ctx context.Context, key string, longitude, latitude float64, query *GeoRadiusQuery,
|
||||
) *IntCmd {
|
||||
args := geoLocationArgs(query, "georadius", key, longitude, latitude)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
if query.Store == "" && query.StoreDist == "" {
|
||||
cmd.SetErr(errors.New("GeoRadiusStore requires Store or StoreDist"))
|
||||
return cmd
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GeoRadiusByMember is a read-only GEORADIUSBYMEMBER_RO command.
|
||||
func (c cmdable) GeoRadiusByMember(
|
||||
ctx context.Context, key, member string, query *GeoRadiusQuery,
|
||||
) *GeoLocationCmd {
|
||||
cmd := NewGeoLocationCmd(ctx, query, "georadiusbymember_ro", key, member)
|
||||
if query.Store != "" || query.StoreDist != "" {
|
||||
cmd.SetErr(errors.New("GeoRadiusByMember does not support Store or StoreDist"))
|
||||
return cmd
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GeoRadiusByMemberStore is a writing GEORADIUSBYMEMBER command.
|
||||
func (c cmdable) GeoRadiusByMemberStore(
|
||||
ctx context.Context, key, member string, query *GeoRadiusQuery,
|
||||
) *IntCmd {
|
||||
args := geoLocationArgs(query, "georadiusbymember", key, member)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
if query.Store == "" && query.StoreDist == "" {
|
||||
cmd.SetErr(errors.New("GeoRadiusByMemberStore requires Store or StoreDist"))
|
||||
return cmd
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoSearch(ctx context.Context, key string, q *GeoSearchQuery) *StringSliceCmd {
|
||||
args := make([]interface{}, 0, 13)
|
||||
args = append(args, "geosearch", key)
|
||||
args = geoSearchArgs(q, args)
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoSearchLocation(
|
||||
ctx context.Context, key string, q *GeoSearchLocationQuery,
|
||||
) *GeoSearchLocationCmd {
|
||||
args := make([]interface{}, 0, 16)
|
||||
args = append(args, "geosearch", key)
|
||||
args = geoSearchLocationArgs(q, args)
|
||||
cmd := NewGeoSearchLocationCmd(ctx, q, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoSearchStore(ctx context.Context, key, store string, q *GeoSearchStoreQuery) *IntCmd {
|
||||
args := make([]interface{}, 0, 15)
|
||||
args = append(args, "geosearchstore", store, key)
|
||||
args = geoSearchArgs(&q.GeoSearchQuery, args)
|
||||
if q.StoreDist {
|
||||
args = append(args, "storedist")
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoDist(
|
||||
ctx context.Context, key string, member1, member2, unit string,
|
||||
) *FloatCmd {
|
||||
if unit == "" {
|
||||
unit = "km"
|
||||
}
|
||||
cmd := NewFloatCmd(ctx, "geodist", key, member1, member2, unit)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoHash(ctx context.Context, key string, members ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 2+len(members))
|
||||
args[0] = "geohash"
|
||||
args[1] = key
|
||||
for i, member := range members {
|
||||
args[2+i] = member
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GeoPos(ctx context.Context, key string, members ...string) *GeoPosCmd {
|
||||
args := make([]interface{}, 2+len(members))
|
||||
args[0] = "geopos"
|
||||
args[1] = key
|
||||
for i, member := range members {
|
||||
args[2+i] = member
|
||||
}
|
||||
cmd := NewGeoPosCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type HashCmdable interface {
|
||||
HDel(ctx context.Context, key string, fields ...string) *IntCmd
|
||||
HExists(ctx context.Context, key, field string) *BoolCmd
|
||||
HGet(ctx context.Context, key, field string) *StringCmd
|
||||
HGetAll(ctx context.Context, key string) *MapStringStringCmd
|
||||
HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd
|
||||
HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd
|
||||
HKeys(ctx context.Context, key string) *StringSliceCmd
|
||||
HLen(ctx context.Context, key string) *IntCmd
|
||||
HMGet(ctx context.Context, key string, fields ...string) *SliceCmd
|
||||
HSet(ctx context.Context, key string, values ...interface{}) *IntCmd
|
||||
HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd
|
||||
HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd
|
||||
HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
|
||||
HVals(ctx context.Context, key string) *StringSliceCmd
|
||||
HRandField(ctx context.Context, key string, count int) *StringSliceCmd
|
||||
HRandFieldWithValues(ctx context.Context, key string, count int) *KeyValueSliceCmd
|
||||
}
|
||||
|
||||
func (c cmdable) HDel(ctx context.Context, key string, fields ...string) *IntCmd {
|
||||
args := make([]interface{}, 2+len(fields))
|
||||
args[0] = "hdel"
|
||||
args[1] = key
|
||||
for i, field := range fields {
|
||||
args[2+i] = field
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HExists(ctx context.Context, key, field string) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "hexists", key, field)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HGet(ctx context.Context, key, field string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "hget", key, field)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HGetAll(ctx context.Context, key string) *MapStringStringCmd {
|
||||
cmd := NewMapStringStringCmd(ctx, "hgetall", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HIncrBy(ctx context.Context, key, field string, incr int64) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "hincrby", key, field, incr)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HIncrByFloat(ctx context.Context, key, field string, incr float64) *FloatCmd {
|
||||
cmd := NewFloatCmd(ctx, "hincrbyfloat", key, field, incr)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HKeys(ctx context.Context, key string) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "hkeys", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HLen(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "hlen", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// HMGet returns the values for the specified fields in the hash stored at key.
|
||||
// It returns an interface{} to distinguish between empty string and nil value.
|
||||
func (c cmdable) HMGet(ctx context.Context, key string, fields ...string) *SliceCmd {
|
||||
args := make([]interface{}, 2+len(fields))
|
||||
args[0] = "hmget"
|
||||
args[1] = key
|
||||
for i, field := range fields {
|
||||
args[2+i] = field
|
||||
}
|
||||
cmd := NewSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// HSet accepts values in following formats:
|
||||
//
|
||||
// - HSet("myhash", "key1", "value1", "key2", "value2")
|
||||
//
|
||||
// - HSet("myhash", []string{"key1", "value1", "key2", "value2"})
|
||||
//
|
||||
// - HSet("myhash", map[string]interface{}{"key1": "value1", "key2": "value2"})
|
||||
//
|
||||
// Playing struct With "redis" tag.
|
||||
// type MyHash struct { Key1 string `redis:"key1"`; Key2 int `redis:"key2"` }
|
||||
//
|
||||
// - HSet("myhash", MyHash{"value1", "value2"}) Warn: redis-server >= 4.0
|
||||
//
|
||||
// For struct, can be a structure pointer type, we only parse the field whose tag is redis.
|
||||
// if you don't want the field to be read, you can use the `redis:"-"` flag to ignore it,
|
||||
// or you don't need to set the redis tag.
|
||||
// For the type of structure field, we only support simple data types:
|
||||
// string, int/uint(8,16,32,64), float(32,64), time.Time(to RFC3339Nano), time.Duration(to Nanoseconds ),
|
||||
// if you are other more complex or custom data types, please implement the encoding.BinaryMarshaler interface.
|
||||
//
|
||||
// Note that in older versions of Redis server(redis-server < 4.0), HSet only supports a single key-value pair.
|
||||
// redis-docs: https://redis.io/commands/hset (Starting with Redis version 4.0.0: Accepts multiple field and value arguments.)
|
||||
// If you are using a Struct type and the number of fields is greater than one,
|
||||
// you will receive an error similar to "ERR wrong number of arguments", you can use HMSet as a substitute.
|
||||
func (c cmdable) HSet(ctx context.Context, key string, values ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "hset"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// HMSet is a deprecated version of HSet left for compatibility with Redis 3.
|
||||
func (c cmdable) HMSet(ctx context.Context, key string, values ...interface{}) *BoolCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "hmset"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewBoolCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HSetNX(ctx context.Context, key, field string, value interface{}) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "hsetnx", key, field, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HVals(ctx context.Context, key string) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "hvals", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// HRandField redis-server version >= 6.2.0.
|
||||
func (c cmdable) HRandField(ctx context.Context, key string, count int) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "hrandfield", key, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// HRandFieldWithValues redis-server version >= 6.2.0.
|
||||
func (c cmdable) HRandFieldWithValues(ctx context.Context, key string, count int) *KeyValueSliceCmd {
|
||||
cmd := NewKeyValueSliceCmd(ctx, "hrandfield", key, count, "withvalues")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) HScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
|
||||
args := []interface{}{"hscan", key, cursor}
|
||||
if match != "" {
|
||||
args = append(args, "match", match)
|
||||
}
|
||||
if count > 0 {
|
||||
args = append(args, "count", count)
|
||||
}
|
||||
cmd := NewScanCmd(ctx, c, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type HyperLogLogCmdable interface {
|
||||
PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd
|
||||
PFCount(ctx context.Context, keys ...string) *IntCmd
|
||||
PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd
|
||||
}
|
||||
|
||||
func (c cmdable) PFAdd(ctx context.Context, key string, els ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(els))
|
||||
args[0] = "pfadd"
|
||||
args[1] = key
|
||||
args = appendArgs(args, els)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PFCount(ctx context.Context, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "pfcount"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PFMerge(ctx context.Context, dest string, keys ...string) *StatusCmd {
|
||||
args := make([]interface{}, 2+len(keys))
|
||||
args[0] = "pfmerge"
|
||||
args[1] = dest
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
//go:build linux || darwin || dragonfly || freebsd || netbsd || openbsd || solaris || illumos
|
||||
// +build linux darwin dragonfly freebsd netbsd openbsd solaris illumos
|
||||
|
||||
package pool
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//go:build !linux && !darwin && !dragonfly && !freebsd && !netbsd && !openbsd && !solaris && !illumos
|
||||
// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos
|
||||
|
||||
package pool
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,10 @@ var (
|
|||
// ErrClosed performs any operation on the closed client will return this error.
|
||||
ErrClosed = errors.New("redis: client is closed")
|
||||
|
||||
// ErrPoolExhausted is returned from a pool connection method
|
||||
// when the maximum number of database connections in the pool has been reached.
|
||||
ErrPoolExhausted = errors.New("redis: connection pool exhausted")
|
||||
|
||||
// ErrPoolTimeout timed out waiting to get a connection from the connection pool.
|
||||
ErrPoolTimeout = errors.New("redis: connection pool timeout")
|
||||
)
|
||||
|
|
@ -61,6 +65,7 @@ type Options struct {
|
|||
PoolTimeout time.Duration
|
||||
MinIdleConns int
|
||||
MaxIdleConns int
|
||||
MaxActiveConns int
|
||||
ConnMaxIdleTime time.Duration
|
||||
ConnMaxLifetime time.Duration
|
||||
}
|
||||
|
|
@ -159,6 +164,14 @@ func (p *ConnPool) NewConn(ctx context.Context) (*Conn, error) {
|
|||
}
|
||||
|
||||
func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, error) {
|
||||
if p.closed() {
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
||||
if p.cfg.MaxActiveConns > 0 && p.poolSize >= p.cfg.MaxActiveConns {
|
||||
return nil, ErrPoolExhausted
|
||||
}
|
||||
|
||||
cn, err := p.dialConn(ctx, pooled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -167,12 +180,6 @@ func (p *ConnPool) newConn(ctx context.Context, pooled bool) (*Conn, error) {
|
|||
p.connsMu.Lock()
|
||||
defer p.connsMu.Unlock()
|
||||
|
||||
// It is not allowed to add new connections to the closed connection pool.
|
||||
if p.closed() {
|
||||
_ = cn.Close()
|
||||
return nil, ErrClosed
|
||||
}
|
||||
|
||||
p.conns = append(p.conns, cn)
|
||||
if pooled {
|
||||
// If pool is full remove the cn on next Put.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//go:build appengine
|
||||
// +build appengine
|
||||
|
||||
package util
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
//go:build !appengine
|
||||
// +build !appengine
|
||||
|
||||
package util
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,289 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ListCmdable interface {
|
||||
BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
|
||||
BLMPop(ctx context.Context, timeout time.Duration, direction string, count int64, keys ...string) *KeyValuesCmd
|
||||
BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd
|
||||
BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd
|
||||
LIndex(ctx context.Context, key string, index int64) *StringCmd
|
||||
LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd
|
||||
LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd
|
||||
LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd
|
||||
LLen(ctx context.Context, key string) *IntCmd
|
||||
LMPop(ctx context.Context, direction string, count int64, keys ...string) *KeyValuesCmd
|
||||
LPop(ctx context.Context, key string) *StringCmd
|
||||
LPopCount(ctx context.Context, key string, count int) *StringSliceCmd
|
||||
LPos(ctx context.Context, key string, value string, args LPosArgs) *IntCmd
|
||||
LPosCount(ctx context.Context, key string, value string, count int64, args LPosArgs) *IntSliceCmd
|
||||
LPush(ctx context.Context, key string, values ...interface{}) *IntCmd
|
||||
LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
|
||||
LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
|
||||
LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd
|
||||
LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd
|
||||
LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd
|
||||
RPop(ctx context.Context, key string) *StringCmd
|
||||
RPopCount(ctx context.Context, key string, count int) *StringSliceCmd
|
||||
RPopLPush(ctx context.Context, source, destination string) *StringCmd
|
||||
RPush(ctx context.Context, key string, values ...interface{}) *IntCmd
|
||||
RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd
|
||||
LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd
|
||||
BLMove(ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration) *StringCmd
|
||||
}
|
||||
|
||||
func (c cmdable) BLPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 1+len(keys)+1)
|
||||
args[0] = "blpop"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
args[len(args)-1] = formatSec(ctx, timeout)
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) BLMPop(ctx context.Context, timeout time.Duration, direction string, count int64, keys ...string) *KeyValuesCmd {
|
||||
args := make([]interface{}, 3+len(keys), 6+len(keys))
|
||||
args[0] = "blmpop"
|
||||
args[1] = formatSec(ctx, timeout)
|
||||
args[2] = len(keys)
|
||||
for i, key := range keys {
|
||||
args[3+i] = key
|
||||
}
|
||||
args = append(args, strings.ToLower(direction), "count", count)
|
||||
cmd := NewKeyValuesCmd(ctx, args...)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) BRPop(ctx context.Context, timeout time.Duration, keys ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 1+len(keys)+1)
|
||||
args[0] = "brpop"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
args[len(keys)+1] = formatSec(ctx, timeout)
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) BRPopLPush(ctx context.Context, source, destination string, timeout time.Duration) *StringCmd {
|
||||
cmd := NewStringCmd(
|
||||
ctx,
|
||||
"brpoplpush",
|
||||
source,
|
||||
destination,
|
||||
formatSec(ctx, timeout),
|
||||
)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LIndex(ctx context.Context, key string, index int64) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "lindex", key, index)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// 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 (c cmdable) LMPop(ctx context.Context, direction string, count int64, keys ...string) *KeyValuesCmd {
|
||||
args := make([]interface{}, 2+len(keys), 5+len(keys))
|
||||
args[0] = "lmpop"
|
||||
args[1] = len(keys)
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
}
|
||||
args = append(args, strings.ToLower(direction), "count", count)
|
||||
cmd := NewKeyValuesCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LInsert(ctx context.Context, key, op string, pivot, value interface{}) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "linsert", key, op, pivot, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LInsertBefore(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "linsert", key, "before", pivot, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LInsertAfter(ctx context.Context, key string, pivot, value interface{}) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "linsert", key, "after", pivot, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LLen(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "llen", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LPop(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "lpop", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "lpop", key, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type LPosArgs struct {
|
||||
Rank, MaxLen int64
|
||||
}
|
||||
|
||||
func (c cmdable) LPos(ctx context.Context, key string, value string, a LPosArgs) *IntCmd {
|
||||
args := []interface{}{"lpos", key, value}
|
||||
if a.Rank != 0 {
|
||||
args = append(args, "rank", a.Rank)
|
||||
}
|
||||
if a.MaxLen != 0 {
|
||||
args = append(args, "maxlen", a.MaxLen)
|
||||
}
|
||||
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LPosCount(ctx context.Context, key string, value string, count int64, a LPosArgs) *IntSliceCmd {
|
||||
args := []interface{}{"lpos", key, value, "count", count}
|
||||
if a.Rank != 0 {
|
||||
args = append(args, "rank", a.Rank)
|
||||
}
|
||||
if a.MaxLen != 0 {
|
||||
args = append(args, "maxlen", a.MaxLen)
|
||||
}
|
||||
cmd := NewIntSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "lpush"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "lpushx"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(
|
||||
ctx,
|
||||
"lrange",
|
||||
key,
|
||||
start,
|
||||
stop,
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LRem(ctx context.Context, key string, count int64, value interface{}) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "lrem", key, count, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LSet(ctx context.Context, key string, index int64, value interface{}) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "lset", key, index, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LTrim(ctx context.Context, key string, start, stop int64) *StatusCmd {
|
||||
cmd := NewStatusCmd(
|
||||
ctx,
|
||||
"ltrim",
|
||||
key,
|
||||
start,
|
||||
stop,
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RPop(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "rpop", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RPopCount(ctx context.Context, key string, count int) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "rpop", key, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RPopLPush(ctx context.Context, source, destination string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "rpoplpush", source, destination)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RPush(ctx context.Context, key string, values ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "rpush"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) RPushX(ctx context.Context, key string, values ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(values))
|
||||
args[0] = "rpushx"
|
||||
args[1] = key
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LMove(ctx context.Context, source, destination, srcpos, destpos string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "lmove", source, destination, srcpos, destpos)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) BLMove(
|
||||
ctx context.Context, source, destination, srcpos, destpos string, timeout time.Duration,
|
||||
) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "blmove", source, destination, srcpos, destpos, formatSec(ctx, timeout))
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -98,8 +98,10 @@ type Options struct {
|
|||
// Note that FIFO has slightly higher overhead compared to LIFO,
|
||||
// but it helps closing idle connections faster reducing the pool size.
|
||||
PoolFIFO bool
|
||||
// Maximum number of socket connections.
|
||||
// Base number of socket connections.
|
||||
// Default is 10 connections per every available CPU as reported by runtime.GOMAXPROCS.
|
||||
// If there is not enough connections in the pool, new connections will be allocated in excess of PoolSize,
|
||||
// you can limit it through MaxActiveConns
|
||||
PoolSize int
|
||||
// Amount of time client waits for connection if all connections
|
||||
// are busy before returning an error.
|
||||
|
|
@ -112,6 +114,9 @@ type Options struct {
|
|||
// Maximum number of idle connections.
|
||||
// Default is 0. the idle connections are not closed by default.
|
||||
MaxIdleConns int
|
||||
// Maximum number of connections allocated by the pool at a given time.
|
||||
// When zero, there is no limit on the number of connections in the pool.
|
||||
MaxActiveConns int
|
||||
// ConnMaxIdleTime is the maximum amount of time a connection may be idle.
|
||||
// Should be less than server's timeout.
|
||||
//
|
||||
|
|
@ -136,6 +141,9 @@ type Options struct {
|
|||
|
||||
// Enables read only queries on slave/follower nodes.
|
||||
readOnly bool
|
||||
|
||||
// // Disable set-lib on connect. Default is false.
|
||||
DisableIndentity bool
|
||||
}
|
||||
|
||||
func (opt *Options) init() {
|
||||
|
|
@ -499,6 +507,7 @@ func newConnPool(
|
|||
PoolTimeout: opt.PoolTimeout,
|
||||
MinIdleConns: opt.MinIdleConns,
|
||||
MaxIdleConns: opt.MaxIdleConns,
|
||||
MaxActiveConns: opt.MaxActiveConns,
|
||||
ConnMaxIdleTime: opt.ConnMaxIdleTime,
|
||||
ConnMaxLifetime: opt.ConnMaxLifetime,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -83,7 +83,8 @@ type ClusterOptions struct {
|
|||
ConnMaxIdleTime time.Duration
|
||||
ConnMaxLifetime time.Duration
|
||||
|
||||
TLSConfig *tls.Config
|
||||
TLSConfig *tls.Config
|
||||
DisableIndentity bool // Disable set-lib on connect. Default is false.
|
||||
}
|
||||
|
||||
func (opt *ClusterOptions) init() {
|
||||
|
|
@ -277,15 +278,15 @@ func (opt *ClusterOptions) clientOptions() *Options {
|
|||
ReadTimeout: opt.ReadTimeout,
|
||||
WriteTimeout: opt.WriteTimeout,
|
||||
|
||||
PoolFIFO: opt.PoolFIFO,
|
||||
PoolSize: opt.PoolSize,
|
||||
PoolTimeout: opt.PoolTimeout,
|
||||
MinIdleConns: opt.MinIdleConns,
|
||||
MaxIdleConns: opt.MaxIdleConns,
|
||||
ConnMaxIdleTime: opt.ConnMaxIdleTime,
|
||||
ConnMaxLifetime: opt.ConnMaxLifetime,
|
||||
|
||||
TLSConfig: opt.TLSConfig,
|
||||
PoolFIFO: opt.PoolFIFO,
|
||||
PoolSize: opt.PoolSize,
|
||||
PoolTimeout: opt.PoolTimeout,
|
||||
MinIdleConns: opt.MinIdleConns,
|
||||
MaxIdleConns: opt.MaxIdleConns,
|
||||
ConnMaxIdleTime: opt.ConnMaxIdleTime,
|
||||
ConnMaxLifetime: opt.ConnMaxLifetime,
|
||||
DisableIndentity: opt.DisableIndentity,
|
||||
TLSConfig: opt.TLSConfig,
|
||||
// If ClusterSlots is populated, then we probably have an artificial
|
||||
// cluster whose nodes are not in clustering mode (otherwise there isn't
|
||||
// much use for ClusterSlots config). This means we cannot execute the
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
func (c *ClusterClient) DBSize(ctx context.Context) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "dbsize")
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
var size int64
|
||||
err := c.ForEachMaster(ctx, func(ctx context.Context, master *Client) error {
|
||||
n, err := master.DBSize(ctx).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
atomic.AddInt64(&size, n)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
} else {
|
||||
cmd.val = size
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ClusterClient) ScriptLoad(ctx context.Context, script string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "script", "load", script)
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
var mu sync.Mutex
|
||||
err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
|
||||
val, err := shard.ScriptLoad(ctx, script).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
if cmd.Val() == "" {
|
||||
cmd.val = val
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ClusterClient) ScriptFlush(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "script", "flush")
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
|
||||
return shard.ScriptFlush(ctx).Err()
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *ClusterClient) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
|
||||
args := make([]interface{}, 2+len(hashes))
|
||||
args[0] = "script"
|
||||
args[1] = "exists"
|
||||
for i, hash := range hashes {
|
||||
args[2+i] = hash
|
||||
}
|
||||
cmd := NewBoolSliceCmd(ctx, args...)
|
||||
|
||||
result := make([]bool, len(hashes))
|
||||
for i := range result {
|
||||
result[i] = true
|
||||
}
|
||||
|
||||
_ = c.withProcessHook(ctx, cmd, func(ctx context.Context, _ Cmder) error {
|
||||
var mu sync.Mutex
|
||||
err := c.ForEachShard(ctx, func(ctx context.Context, shard *Client) error {
|
||||
val, err := shard.ScriptExists(ctx, hashes...).Result()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
for i, v := range val {
|
||||
result[i] = result[i] && v
|
||||
}
|
||||
mu.Unlock()
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
cmd.SetErr(err)
|
||||
} else {
|
||||
cmd.val = result
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "redis",
|
||||
"version": "9.1.0",
|
||||
"version": "9.2.1",
|
||||
"main": "index.js",
|
||||
"repository": "git@github.com:redis/go-redis.git",
|
||||
"author": "Vladimir Mihailenco <vladimir.webdev@gmail.com>",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import (
|
|||
"github.com/redis/go-redis/v9/internal/proto"
|
||||
)
|
||||
|
||||
type probabilisticCmdable interface {
|
||||
type ProbabilisticCmdable interface {
|
||||
BFAdd(ctx context.Context, key string, element interface{}) *BoolCmd
|
||||
BFCard(ctx context.Context, key string) *IntCmd
|
||||
BFExists(ctx context.Context, key string, element interface{}) *BoolCmd
|
||||
|
|
@ -24,7 +24,7 @@ type probabilisticCmdable interface {
|
|||
BFReserve(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd
|
||||
BFReserveExpansion(ctx context.Context, key string, errorRate float64, capacity, expansion int64) *StatusCmd
|
||||
BFReserveNonScaling(ctx context.Context, key string, errorRate float64, capacity int64) *StatusCmd
|
||||
BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd
|
||||
BFReserveWithArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd
|
||||
BFScanDump(ctx context.Context, key string, iterator int64) *ScanDumpCmd
|
||||
BFLoadChunk(ctx context.Context, key string, iterator int64, data interface{}) *StatusCmd
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ type probabilisticCmdable interface {
|
|||
CFInsertNX(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd
|
||||
CFMExists(ctx context.Context, key string, elements ...interface{}) *BoolSliceCmd
|
||||
CFReserve(ctx context.Context, key string, capacity int64) *StatusCmd
|
||||
CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd
|
||||
CFReserveWithArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd
|
||||
CFReserveExpansion(ctx context.Context, key string, capacity int64, expansion int64) *StatusCmd
|
||||
CFReserveBucketSize(ctx context.Context, key string, capacity int64, bucketsize int64) *StatusCmd
|
||||
CFReserveMaxIterations(ctx context.Context, key string, capacity int64, maxiterations int64) *StatusCmd
|
||||
|
|
@ -143,11 +143,11 @@ func (c cmdable) BFReserveNonScaling(ctx context.Context, key string, errorRate
|
|||
return cmd
|
||||
}
|
||||
|
||||
// BFReserveArgs creates an empty Bloom filter with a single sub-filter
|
||||
// BFReserveWithArgs creates an empty Bloom filter with a single sub-filter
|
||||
// for the initial specified capacity and with an upper bound error_rate.
|
||||
// This function also allows for specifying additional options such as expansion rate and non-scaling behavior.
|
||||
// For more information - https://redis.io/commands/bf.reserve/
|
||||
func (c cmdable) BFReserveArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd {
|
||||
func (c cmdable) BFReserveWithArgs(ctx context.Context, key string, options *BFReserveOptions) *StatusCmd {
|
||||
args := []interface{}{"BF.RESERVE", key}
|
||||
if options != nil {
|
||||
if options.Error != 0 {
|
||||
|
|
@ -310,6 +310,7 @@ func NewBFInfoCmd(ctx context.Context, args ...interface{}) *BFInfoCmd {
|
|||
func (cmd *BFInfoCmd) SetVal(val BFInfo) {
|
||||
cmd.val = val
|
||||
}
|
||||
|
||||
func (cmd *BFInfoCmd) String() string {
|
||||
return cmdString(cmd, cmd.val)
|
||||
}
|
||||
|
|
@ -493,10 +494,10 @@ func (c cmdable) CFReserveMaxIterations(ctx context.Context, key string, capacit
|
|||
return cmd
|
||||
}
|
||||
|
||||
// CFReserveArgs creates an empty Cuckoo filter with the specified options.
|
||||
// CFReserveWithArgs creates an empty Cuckoo filter with the specified options.
|
||||
// This function allows for specifying additional options such as bucket size and maximum number of iterations.
|
||||
// For more information - https://redis.io/commands/cf.reserve/
|
||||
func (c cmdable) CFReserveArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd {
|
||||
func (c cmdable) CFReserveWithArgs(ctx context.Context, key string, options *CFReserveOptions) *StatusCmd {
|
||||
args := []interface{}{"CF.RESERVE", key, options.Capacity}
|
||||
if options.BucketSize != 0 {
|
||||
args = append(args, "BUCKETSIZE", options.BucketSize)
|
||||
|
|
@ -679,7 +680,7 @@ func (c cmdable) CFInfo(ctx context.Context, key string) *CFInfoCmd {
|
|||
// For more information - https://redis.io/commands/cf.insert/
|
||||
func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *BoolSliceCmd {
|
||||
args := []interface{}{"CF.INSERT", key}
|
||||
args = c.getCfInsertArgs(args, options, elements...)
|
||||
args = c.getCfInsertWithArgs(args, options, elements...)
|
||||
|
||||
cmd := NewBoolSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
|
|
@ -693,14 +694,14 @@ func (c cmdable) CFInsert(ctx context.Context, key string, options *CFInsertOpti
|
|||
// For more information - https://redis.io/commands/cf.insertnx/
|
||||
func (c cmdable) CFInsertNX(ctx context.Context, key string, options *CFInsertOptions, elements ...interface{}) *IntSliceCmd {
|
||||
args := []interface{}{"CF.INSERTNX", key}
|
||||
args = c.getCfInsertArgs(args, options, elements...)
|
||||
args = c.getCfInsertWithArgs(args, options, elements...)
|
||||
|
||||
cmd := NewIntSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) getCfInsertArgs(args []interface{}, options *CFInsertOptions, elements ...interface{}) []interface{} {
|
||||
func (c cmdable) getCfInsertWithArgs(args []interface{}, options *CFInsertOptions, elements ...interface{}) []interface{} {
|
||||
if options != nil {
|
||||
if options.Capacity != 0 {
|
||||
args = append(args, "CAPACITY", options.Capacity)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type PubSubCmdable interface {
|
||||
Publish(ctx context.Context, channel string, message interface{}) *IntCmd
|
||||
SPublish(ctx context.Context, channel string, message interface{}) *IntCmd
|
||||
PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd
|
||||
PubSubNumSub(ctx context.Context, channels ...string) *MapStringIntCmd
|
||||
PubSubNumPat(ctx context.Context) *IntCmd
|
||||
PubSubShardChannels(ctx context.Context, pattern string) *StringSliceCmd
|
||||
PubSubShardNumSub(ctx context.Context, channels ...string) *MapStringIntCmd
|
||||
}
|
||||
|
||||
// Publish posts the message to the channel.
|
||||
func (c cmdable) Publish(ctx context.Context, channel string, message interface{}) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "publish", channel, message)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SPublish(ctx context.Context, channel string, message interface{}) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "spublish", channel, message)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PubSubChannels(ctx context.Context, pattern string) *StringSliceCmd {
|
||||
args := []interface{}{"pubsub", "channels"}
|
||||
if pattern != "*" {
|
||||
args = append(args, pattern)
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PubSubNumSub(ctx context.Context, channels ...string) *MapStringIntCmd {
|
||||
args := make([]interface{}, 2+len(channels))
|
||||
args[0] = "pubsub"
|
||||
args[1] = "numsub"
|
||||
for i, channel := range channels {
|
||||
args[2+i] = channel
|
||||
}
|
||||
cmd := NewMapStringIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PubSubShardChannels(ctx context.Context, pattern string) *StringSliceCmd {
|
||||
args := []interface{}{"pubsub", "shardchannels"}
|
||||
if pattern != "*" {
|
||||
args = append(args, pattern)
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PubSubShardNumSub(ctx context.Context, channels ...string) *MapStringIntCmd {
|
||||
args := make([]interface{}, 2+len(channels))
|
||||
args[0] = "pubsub"
|
||||
args[1] = "shardnumsub"
|
||||
for i, channel := range channels {
|
||||
args[2+i] = channel
|
||||
}
|
||||
cmd := NewMapStringIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) PubSubNumPat(ctx context.Context) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "pubsub", "numpat")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -299,7 +299,14 @@ func (c *baseClient) initConn(ctx context.Context, cn *pool.Conn) error {
|
|||
// difficult to rely on error strings to determine all results.
|
||||
return err
|
||||
}
|
||||
|
||||
if !c.opt.DisableIndentity {
|
||||
libName := ""
|
||||
libVer := Version()
|
||||
libInfo := LibraryInfo{LibName: &libName}
|
||||
conn.ClientSetInfo(ctx, libInfo)
|
||||
libInfo = LibraryInfo{LibVer: &libVer}
|
||||
conn.ClientSetInfo(ctx, libInfo)
|
||||
}
|
||||
_, err := conn.Pipelined(ctx, func(pipe Pipeliner) error {
|
||||
if !auth && password != "" {
|
||||
if username != "" {
|
||||
|
|
|
|||
|
|
@ -292,7 +292,6 @@ func (c *ringSharding) SetAddrs(addrs map[string]string) {
|
|||
func (c *ringSharding) newRingShards(
|
||||
addrs map[string]string, existing *ringShards,
|
||||
) (shards *ringShards, created, unused map[string]*ringShard) {
|
||||
|
||||
shards = &ringShards{m: make(map[string]*ringShard, len(addrs))}
|
||||
created = make(map[string]*ringShard) // indexed by addr
|
||||
unused = make(map[string]*ringShard) // indexed by addr
|
||||
|
|
|
|||
|
|
@ -0,0 +1,215 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type ScriptingFunctionsCmdable interface {
|
||||
Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
|
||||
EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
|
||||
EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
|
||||
EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
|
||||
ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
|
||||
ScriptFlush(ctx context.Context) *StatusCmd
|
||||
ScriptKill(ctx context.Context) *StatusCmd
|
||||
ScriptLoad(ctx context.Context, script string) *StringCmd
|
||||
|
||||
FunctionLoad(ctx context.Context, code string) *StringCmd
|
||||
FunctionLoadReplace(ctx context.Context, code string) *StringCmd
|
||||
FunctionDelete(ctx context.Context, libName string) *StringCmd
|
||||
FunctionFlush(ctx context.Context) *StringCmd
|
||||
FunctionKill(ctx context.Context) *StringCmd
|
||||
FunctionFlushAsync(ctx context.Context) *StringCmd
|
||||
FunctionList(ctx context.Context, q FunctionListQuery) *FunctionListCmd
|
||||
FunctionDump(ctx context.Context) *StringCmd
|
||||
FunctionRestore(ctx context.Context, libDump string) *StringCmd
|
||||
FunctionStats(ctx context.Context) *FunctionStatsCmd
|
||||
FCall(ctx context.Context, function string, keys []string, args ...interface{}) *Cmd
|
||||
FCallRo(ctx context.Context, function string, keys []string, args ...interface{}) *Cmd
|
||||
FCallRO(ctx context.Context, function string, keys []string, args ...interface{}) *Cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
|
||||
return c.eval(ctx, "eval", script, keys, args...)
|
||||
}
|
||||
|
||||
func (c cmdable) EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd {
|
||||
return c.eval(ctx, "eval_ro", script, keys, args...)
|
||||
}
|
||||
|
||||
func (c cmdable) EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
|
||||
return c.eval(ctx, "evalsha", sha1, keys, args...)
|
||||
}
|
||||
|
||||
func (c cmdable) EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd {
|
||||
return c.eval(ctx, "evalsha_ro", sha1, keys, args...)
|
||||
}
|
||||
|
||||
func (c cmdable) eval(ctx context.Context, name, payload string, keys []string, args ...interface{}) *Cmd {
|
||||
cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
|
||||
cmdArgs[0] = name
|
||||
cmdArgs[1] = payload
|
||||
cmdArgs[2] = len(keys)
|
||||
for i, key := range keys {
|
||||
cmdArgs[3+i] = key
|
||||
}
|
||||
cmdArgs = appendArgs(cmdArgs, args)
|
||||
cmd := NewCmd(ctx, cmdArgs...)
|
||||
|
||||
// it is possible that only args exist without a key.
|
||||
// rdb.eval(ctx, eval, script, nil, arg1, arg2)
|
||||
if len(keys) > 0 {
|
||||
cmd.SetFirstKeyPos(3)
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd {
|
||||
args := make([]interface{}, 2+len(hashes))
|
||||
args[0] = "script"
|
||||
args[1] = "exists"
|
||||
for i, hash := range hashes {
|
||||
args[2+i] = hash
|
||||
}
|
||||
cmd := NewBoolSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ScriptFlush(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "script", "flush")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ScriptKill(ctx context.Context) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "script", "kill")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ScriptLoad(ctx context.Context, script string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "script", "load", script)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------
|
||||
|
||||
// FunctionListQuery is used with FunctionList to query for Redis libraries
|
||||
//
|
||||
// LibraryNamePattern - Use an empty string to get all libraries.
|
||||
// - Use a glob-style pattern to match multiple libraries with a matching name
|
||||
// - Use a library's full name to match a single library
|
||||
// WithCode - If true, it will return the code of the library
|
||||
type FunctionListQuery struct {
|
||||
LibraryNamePattern string
|
||||
WithCode bool
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionLoad(ctx context.Context, code string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "load", code)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionLoadReplace(ctx context.Context, code string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "load", "replace", code)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionDelete(ctx context.Context, libName string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "delete", libName)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionFlush(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "flush")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionKill(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "kill")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionFlushAsync(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "flush", "async")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionList(ctx context.Context, q FunctionListQuery) *FunctionListCmd {
|
||||
args := make([]interface{}, 2, 5)
|
||||
args[0] = "function"
|
||||
args[1] = "list"
|
||||
if q.LibraryNamePattern != "" {
|
||||
args = append(args, "libraryname", q.LibraryNamePattern)
|
||||
}
|
||||
if q.WithCode {
|
||||
args = append(args, "withcode")
|
||||
}
|
||||
cmd := NewFunctionListCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionDump(ctx context.Context) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "dump")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionRestore(ctx context.Context, libDump string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "function", "restore", libDump)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FunctionStats(ctx context.Context) *FunctionStatsCmd {
|
||||
cmd := NewFunctionStatsCmd(ctx, "function", "stats")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) FCall(ctx context.Context, function string, keys []string, args ...interface{}) *Cmd {
|
||||
cmdArgs := fcallArgs("fcall", function, keys, args...)
|
||||
cmd := NewCmd(ctx, cmdArgs...)
|
||||
if len(keys) > 0 {
|
||||
cmd.SetFirstKeyPos(3)
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// FCallRo this function simply calls FCallRO,
|
||||
// Deprecated: to maintain convention FCallRO.
|
||||
func (c cmdable) FCallRo(ctx context.Context, function string, keys []string, args ...interface{}) *Cmd {
|
||||
return c.FCallRO(ctx, function, keys, args...)
|
||||
}
|
||||
|
||||
func (c cmdable) FCallRO(ctx context.Context, function string, keys []string, args ...interface{}) *Cmd {
|
||||
cmdArgs := fcallArgs("fcall_ro", function, keys, args...)
|
||||
cmd := NewCmd(ctx, cmdArgs...)
|
||||
if len(keys) > 0 {
|
||||
cmd.SetFirstKeyPos(3)
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func fcallArgs(command string, function string, keys []string, args ...interface{}) []interface{} {
|
||||
cmdArgs := make([]interface{}, 3+len(keys), 3+len(keys)+len(args))
|
||||
cmdArgs[0] = command
|
||||
cmdArgs[1] = function
|
||||
cmdArgs[2] = len(keys)
|
||||
for i, key := range keys {
|
||||
cmdArgs[3+i] = key
|
||||
}
|
||||
|
||||
cmdArgs = append(cmdArgs, args...)
|
||||
return cmdArgs
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
package redis
|
||||
|
||||
import "context"
|
||||
|
||||
type SetCmdable interface {
|
||||
SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd
|
||||
SCard(ctx context.Context, key string) *IntCmd
|
||||
SDiff(ctx context.Context, keys ...string) *StringSliceCmd
|
||||
SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
|
||||
SInter(ctx context.Context, keys ...string) *StringSliceCmd
|
||||
SInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd
|
||||
SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd
|
||||
SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd
|
||||
SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd
|
||||
SMembers(ctx context.Context, key string) *StringSliceCmd
|
||||
SMembersMap(ctx context.Context, key string) *StringStructMapCmd
|
||||
SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd
|
||||
SPop(ctx context.Context, key string) *StringCmd
|
||||
SPopN(ctx context.Context, key string, count int64) *StringSliceCmd
|
||||
SRandMember(ctx context.Context, key string) *StringCmd
|
||||
SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd
|
||||
SRem(ctx context.Context, key string, members ...interface{}) *IntCmd
|
||||
SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
|
||||
SUnion(ctx context.Context, keys ...string) *StringSliceCmd
|
||||
SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
func (c cmdable) SAdd(ctx context.Context, key string, members ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(members))
|
||||
args[0] = "sadd"
|
||||
args[1] = key
|
||||
args = appendArgs(args, members)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SCard(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "scard", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SDiff(ctx context.Context, keys ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "sdiff"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 2+len(keys))
|
||||
args[0] = "sdiffstore"
|
||||
args[1] = destination
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SInter(ctx context.Context, keys ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "sinter"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 4+len(keys))
|
||||
args[0] = "sintercard"
|
||||
numkeys := int64(0)
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
numkeys++
|
||||
}
|
||||
args[1] = numkeys
|
||||
args[2+numkeys] = "limit"
|
||||
args[3+numkeys] = limit
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SInterStore(ctx context.Context, destination string, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 2+len(keys))
|
||||
args[0] = "sinterstore"
|
||||
args[1] = destination
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SIsMember(ctx context.Context, key string, member interface{}) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "sismember", key, member)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SMIsMember Redis `SMISMEMBER key member [member ...]` command.
|
||||
func (c cmdable) SMIsMember(ctx context.Context, key string, members ...interface{}) *BoolSliceCmd {
|
||||
args := make([]interface{}, 2, 2+len(members))
|
||||
args[0] = "smismember"
|
||||
args[1] = key
|
||||
args = appendArgs(args, members)
|
||||
cmd := NewBoolSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SMembers Redis `SMEMBERS key` command output as a slice.
|
||||
func (c cmdable) SMembers(ctx context.Context, key string) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "smembers", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SMembersMap Redis `SMEMBERS key` command output as a map.
|
||||
func (c cmdable) SMembersMap(ctx context.Context, key string) *StringStructMapCmd {
|
||||
cmd := NewStringStructMapCmd(ctx, "smembers", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SMove(ctx context.Context, source, destination string, member interface{}) *BoolCmd {
|
||||
cmd := NewBoolCmd(ctx, "smove", source, destination, member)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SPop Redis `SPOP key` command.
|
||||
func (c cmdable) SPop(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "spop", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SPopN Redis `SPOP key count` command.
|
||||
func (c cmdable) SPopN(ctx context.Context, key string, count int64) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "spop", key, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SRandMember Redis `SRANDMEMBER key` command.
|
||||
func (c cmdable) SRandMember(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "srandmember", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SRandMemberN Redis `SRANDMEMBER key count` command.
|
||||
func (c cmdable) SRandMemberN(ctx context.Context, key string, count int64) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "srandmember", key, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(members))
|
||||
args[0] = "srem"
|
||||
args[1] = key
|
||||
args = appendArgs(args, members)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SUnion(ctx context.Context, keys ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "sunion"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SUnionStore(ctx context.Context, destination string, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 2+len(keys))
|
||||
args[0] = "sunionstore"
|
||||
args[1] = destination
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
|
||||
args := []interface{}{"sscan", key, cursor}
|
||||
if match != "" {
|
||||
args = append(args, "match", match)
|
||||
}
|
||||
if count > 0 {
|
||||
args = append(args, "count", count)
|
||||
}
|
||||
cmd := NewScanCmd(ctx, c, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,772 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type SortedSetCmdable interface {
|
||||
BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
|
||||
BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd
|
||||
BZMPop(ctx context.Context, timeout time.Duration, order string, count int64, keys ...string) *ZSliceWithKeyCmd
|
||||
ZAdd(ctx context.Context, key string, members ...Z) *IntCmd
|
||||
ZAddLT(ctx context.Context, key string, members ...Z) *IntCmd
|
||||
ZAddGT(ctx context.Context, key string, members ...Z) *IntCmd
|
||||
ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd
|
||||
ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd
|
||||
ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd
|
||||
ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd
|
||||
ZCard(ctx context.Context, key string) *IntCmd
|
||||
ZCount(ctx context.Context, key, min, max string) *IntCmd
|
||||
ZLexCount(ctx context.Context, key, min, max string) *IntCmd
|
||||
ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd
|
||||
ZInter(ctx context.Context, store *ZStore) *StringSliceCmd
|
||||
ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd
|
||||
ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd
|
||||
ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd
|
||||
ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd
|
||||
ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd
|
||||
ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd
|
||||
ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd
|
||||
ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
|
||||
ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
|
||||
ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
||||
ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
||||
ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
|
||||
ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd
|
||||
ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd
|
||||
ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd
|
||||
ZRank(ctx context.Context, key, member string) *IntCmd
|
||||
ZRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd
|
||||
ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd
|
||||
ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd
|
||||
ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd
|
||||
ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd
|
||||
ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd
|
||||
ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd
|
||||
ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
||||
ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd
|
||||
ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd
|
||||
ZRevRank(ctx context.Context, key, member string) *IntCmd
|
||||
ZRevRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd
|
||||
ZScore(ctx context.Context, key, member string) *FloatCmd
|
||||
ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd
|
||||
ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd
|
||||
ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd
|
||||
ZUnion(ctx context.Context, store ZStore) *StringSliceCmd
|
||||
ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd
|
||||
ZDiff(ctx context.Context, keys ...string) *StringSliceCmd
|
||||
ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd
|
||||
ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd
|
||||
ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd
|
||||
}
|
||||
|
||||
// BZPopMax Redis `BZPOPMAX key [key ...] timeout` command.
|
||||
func (c cmdable) BZPopMax(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
|
||||
args := make([]interface{}, 1+len(keys)+1)
|
||||
args[0] = "bzpopmax"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
args[len(args)-1] = formatSec(ctx, timeout)
|
||||
cmd := NewZWithKeyCmd(ctx, args...)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// BZPopMin Redis `BZPOPMIN key [key ...] timeout` command.
|
||||
func (c cmdable) BZPopMin(ctx context.Context, timeout time.Duration, keys ...string) *ZWithKeyCmd {
|
||||
args := make([]interface{}, 1+len(keys)+1)
|
||||
args[0] = "bzpopmin"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
args[len(args)-1] = formatSec(ctx, timeout)
|
||||
cmd := NewZWithKeyCmd(ctx, args...)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// BZMPop is the blocking variant of ZMPOP.
|
||||
// When any of the sorted sets contains elements, this command behaves exactly like ZMPOP.
|
||||
// When all sorted sets are empty, Redis will block the connection until another client adds members to one of the keys or until the timeout elapses.
|
||||
// A timeout of zero can be used to block indefinitely.
|
||||
// example: client.BZMPop(ctx, 0,"max", 1, "set")
|
||||
func (c cmdable) BZMPop(ctx context.Context, timeout time.Duration, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
|
||||
args := make([]interface{}, 3+len(keys), 6+len(keys))
|
||||
args[0] = "bzmpop"
|
||||
args[1] = formatSec(ctx, timeout)
|
||||
args[2] = len(keys)
|
||||
for i, key := range keys {
|
||||
args[3+i] = key
|
||||
}
|
||||
args = append(args, strings.ToLower(order), "count", count)
|
||||
cmd := NewZSliceWithKeyCmd(ctx, args...)
|
||||
cmd.setReadTimeout(timeout)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZAddArgs WARN: The GT, LT and NX options are mutually exclusive.
|
||||
type ZAddArgs struct {
|
||||
NX bool
|
||||
XX bool
|
||||
LT bool
|
||||
GT bool
|
||||
Ch bool
|
||||
Members []Z
|
||||
}
|
||||
|
||||
func (c cmdable) zAddArgs(key string, args ZAddArgs, incr bool) []interface{} {
|
||||
a := make([]interface{}, 0, 6+2*len(args.Members))
|
||||
a = append(a, "zadd", key)
|
||||
|
||||
// The GT, LT and NX options are mutually exclusive.
|
||||
if args.NX {
|
||||
a = append(a, "nx")
|
||||
} else {
|
||||
if args.XX {
|
||||
a = append(a, "xx")
|
||||
}
|
||||
if args.GT {
|
||||
a = append(a, "gt")
|
||||
} else if args.LT {
|
||||
a = append(a, "lt")
|
||||
}
|
||||
}
|
||||
if args.Ch {
|
||||
a = append(a, "ch")
|
||||
}
|
||||
if incr {
|
||||
a = append(a, "incr")
|
||||
}
|
||||
for _, m := range args.Members {
|
||||
a = append(a, m.Score)
|
||||
a = append(a, m.Member)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func (c cmdable) ZAddArgs(ctx context.Context, key string, args ZAddArgs) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, c.zAddArgs(key, args, false)...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZAddArgsIncr(ctx context.Context, key string, args ZAddArgs) *FloatCmd {
|
||||
cmd := NewFloatCmd(ctx, c.zAddArgs(key, args, true)...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZAdd Redis `ZADD key score member [score member ...]` command.
|
||||
func (c cmdable) ZAdd(ctx context.Context, key string, members ...Z) *IntCmd {
|
||||
return c.ZAddArgs(ctx, key, ZAddArgs{
|
||||
Members: members,
|
||||
})
|
||||
}
|
||||
|
||||
// ZAddLT Redis `ZADD key LT score member [score member ...]` command.
|
||||
func (c cmdable) ZAddLT(ctx context.Context, key string, members ...Z) *IntCmd {
|
||||
return c.ZAddArgs(ctx, key, ZAddArgs{
|
||||
LT: true,
|
||||
Members: members,
|
||||
})
|
||||
}
|
||||
|
||||
// ZAddGT Redis `ZADD key GT score member [score member ...]` command.
|
||||
func (c cmdable) ZAddGT(ctx context.Context, key string, members ...Z) *IntCmd {
|
||||
return c.ZAddArgs(ctx, key, ZAddArgs{
|
||||
GT: true,
|
||||
Members: members,
|
||||
})
|
||||
}
|
||||
|
||||
// ZAddNX Redis `ZADD key NX score member [score member ...]` command.
|
||||
func (c cmdable) ZAddNX(ctx context.Context, key string, members ...Z) *IntCmd {
|
||||
return c.ZAddArgs(ctx, key, ZAddArgs{
|
||||
NX: true,
|
||||
Members: members,
|
||||
})
|
||||
}
|
||||
|
||||
// ZAddXX Redis `ZADD key XX score member [score member ...]` command.
|
||||
func (c cmdable) ZAddXX(ctx context.Context, key string, members ...Z) *IntCmd {
|
||||
return c.ZAddArgs(ctx, key, ZAddArgs{
|
||||
XX: true,
|
||||
Members: members,
|
||||
})
|
||||
}
|
||||
|
||||
func (c cmdable) ZCard(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zcard", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZCount(ctx context.Context, key, min, max string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zcount", key, min, max)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZLexCount(ctx context.Context, key, min, max string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zlexcount", key, min, max)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZIncrBy(ctx context.Context, key string, increment float64, member string) *FloatCmd {
|
||||
cmd := NewFloatCmd(ctx, "zincrby", key, increment, member)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZInterStore(ctx context.Context, destination string, store *ZStore) *IntCmd {
|
||||
args := make([]interface{}, 0, 3+store.len())
|
||||
args = append(args, "zinterstore", destination, len(store.Keys))
|
||||
args = store.appendArgs(args)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(3)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZInter(ctx context.Context, store *ZStore) *StringSliceCmd {
|
||||
args := make([]interface{}, 0, 2+store.len())
|
||||
args = append(args, "zinter", len(store.Keys))
|
||||
args = store.appendArgs(args)
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(2)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZInterWithScores(ctx context.Context, store *ZStore) *ZSliceCmd {
|
||||
args := make([]interface{}, 0, 3+store.len())
|
||||
args = append(args, "zinter", len(store.Keys))
|
||||
args = store.appendArgs(args)
|
||||
args = append(args, "withscores")
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(2)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZInterCard(ctx context.Context, limit int64, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 4+len(keys))
|
||||
args[0] = "zintercard"
|
||||
numkeys := int64(0)
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
numkeys++
|
||||
}
|
||||
args[1] = numkeys
|
||||
args[2+numkeys] = "limit"
|
||||
args[3+numkeys] = limit
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZMPop Pops one or more elements with the highest or lowest score from the first non-empty sorted set key from the list of provided key names.
|
||||
// direction: "max" (highest score) or "min" (lowest score), count: > 0
|
||||
// example: client.ZMPop(ctx, "max", 5, "set1", "set2")
|
||||
func (c cmdable) ZMPop(ctx context.Context, order string, count int64, keys ...string) *ZSliceWithKeyCmd {
|
||||
args := make([]interface{}, 2+len(keys), 5+len(keys))
|
||||
args[0] = "zmpop"
|
||||
args[1] = len(keys)
|
||||
for i, key := range keys {
|
||||
args[2+i] = key
|
||||
}
|
||||
args = append(args, strings.ToLower(order), "count", count)
|
||||
cmd := NewZSliceWithKeyCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZMScore(ctx context.Context, key string, members ...string) *FloatSliceCmd {
|
||||
args := make([]interface{}, 2+len(members))
|
||||
args[0] = "zmscore"
|
||||
args[1] = key
|
||||
for i, member := range members {
|
||||
args[2+i] = member
|
||||
}
|
||||
cmd := NewFloatSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZPopMax(ctx context.Context, key string, count ...int64) *ZSliceCmd {
|
||||
args := []interface{}{
|
||||
"zpopmax",
|
||||
key,
|
||||
}
|
||||
|
||||
switch len(count) {
|
||||
case 0:
|
||||
break
|
||||
case 1:
|
||||
args = append(args, count[0])
|
||||
default:
|
||||
panic("too many arguments")
|
||||
}
|
||||
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZPopMin(ctx context.Context, key string, count ...int64) *ZSliceCmd {
|
||||
args := []interface{}{
|
||||
"zpopmin",
|
||||
key,
|
||||
}
|
||||
|
||||
switch len(count) {
|
||||
case 0:
|
||||
break
|
||||
case 1:
|
||||
args = append(args, count[0])
|
||||
default:
|
||||
panic("too many arguments")
|
||||
}
|
||||
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZRangeArgs is all the options of the ZRange command.
|
||||
// In version> 6.2.0, you can replace the(cmd):
|
||||
//
|
||||
// ZREVRANGE,
|
||||
// ZRANGEBYSCORE,
|
||||
// ZREVRANGEBYSCORE,
|
||||
// ZRANGEBYLEX,
|
||||
// ZREVRANGEBYLEX.
|
||||
//
|
||||
// Please pay attention to your redis-server version.
|
||||
//
|
||||
// Rev, ByScore, ByLex and Offset+Count options require redis-server 6.2.0 and higher.
|
||||
type ZRangeArgs struct {
|
||||
Key string
|
||||
|
||||
// When the ByScore option is provided, the open interval(exclusive) can be set.
|
||||
// By default, the score intervals specified by <Start> and <Stop> are closed (inclusive).
|
||||
// It is similar to the deprecated(6.2.0+) ZRangeByScore command.
|
||||
// For example:
|
||||
// ZRangeArgs{
|
||||
// Key: "example-key",
|
||||
// Start: "(3",
|
||||
// Stop: 8,
|
||||
// ByScore: true,
|
||||
// }
|
||||
// cmd: "ZRange example-key (3 8 ByScore" (3 < score <= 8).
|
||||
//
|
||||
// For the ByLex option, it is similar to the deprecated(6.2.0+) ZRangeByLex command.
|
||||
// You can set the <Start> and <Stop> options as follows:
|
||||
// ZRangeArgs{
|
||||
// Key: "example-key",
|
||||
// Start: "[abc",
|
||||
// Stop: "(def",
|
||||
// ByLex: true,
|
||||
// }
|
||||
// cmd: "ZRange example-key [abc (def ByLex"
|
||||
//
|
||||
// For normal cases (ByScore==false && ByLex==false), <Start> and <Stop> should be set to the index range (int).
|
||||
// You can read the documentation for more information: https://redis.io/commands/zrange
|
||||
Start interface{}
|
||||
Stop interface{}
|
||||
|
||||
// The ByScore and ByLex options are mutually exclusive.
|
||||
ByScore bool
|
||||
ByLex bool
|
||||
|
||||
Rev bool
|
||||
|
||||
// limit offset count.
|
||||
Offset int64
|
||||
Count int64
|
||||
}
|
||||
|
||||
func (z ZRangeArgs) appendArgs(args []interface{}) []interface{} {
|
||||
// For Rev+ByScore/ByLex, we need to adjust the position of <Start> and <Stop>.
|
||||
if z.Rev && (z.ByScore || z.ByLex) {
|
||||
args = append(args, z.Key, z.Stop, z.Start)
|
||||
} else {
|
||||
args = append(args, z.Key, z.Start, z.Stop)
|
||||
}
|
||||
|
||||
if z.ByScore {
|
||||
args = append(args, "byscore")
|
||||
} else if z.ByLex {
|
||||
args = append(args, "bylex")
|
||||
}
|
||||
if z.Rev {
|
||||
args = append(args, "rev")
|
||||
}
|
||||
if z.Offset != 0 || z.Count != 0 {
|
||||
args = append(args, "limit", z.Offset, z.Count)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeArgs(ctx context.Context, z ZRangeArgs) *StringSliceCmd {
|
||||
args := make([]interface{}, 0, 9)
|
||||
args = append(args, "zrange")
|
||||
args = z.appendArgs(args)
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeArgsWithScores(ctx context.Context, z ZRangeArgs) *ZSliceCmd {
|
||||
args := make([]interface{}, 0, 10)
|
||||
args = append(args, "zrange")
|
||||
args = z.appendArgs(args)
|
||||
args = append(args, "withscores")
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
|
||||
return c.ZRangeArgs(ctx, ZRangeArgs{
|
||||
Key: key,
|
||||
Start: start,
|
||||
Stop: stop,
|
||||
})
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
|
||||
return c.ZRangeArgsWithScores(ctx, ZRangeArgs{
|
||||
Key: key,
|
||||
Start: start,
|
||||
Stop: stop,
|
||||
})
|
||||
}
|
||||
|
||||
type ZRangeBy struct {
|
||||
Min, Max string
|
||||
Offset, Count int64
|
||||
}
|
||||
|
||||
func (c cmdable) zRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy, withScores bool) *StringSliceCmd {
|
||||
args := []interface{}{zcmd, key, opt.Min, opt.Max}
|
||||
if withScores {
|
||||
args = append(args, "withscores")
|
||||
}
|
||||
if opt.Offset != 0 || opt.Count != 0 {
|
||||
args = append(
|
||||
args,
|
||||
"limit",
|
||||
opt.Offset,
|
||||
opt.Count,
|
||||
)
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
||||
return c.zRangeBy(ctx, "zrangebyscore", key, opt, false)
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
||||
return c.zRangeBy(ctx, "zrangebylex", key, opt, false)
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
|
||||
args := []interface{}{"zrangebyscore", key, opt.Min, opt.Max, "withscores"}
|
||||
if opt.Offset != 0 || opt.Count != 0 {
|
||||
args = append(
|
||||
args,
|
||||
"limit",
|
||||
opt.Offset,
|
||||
opt.Count,
|
||||
)
|
||||
}
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRangeStore(ctx context.Context, dst string, z ZRangeArgs) *IntCmd {
|
||||
args := make([]interface{}, 0, 10)
|
||||
args = append(args, "zrangestore", dst)
|
||||
args = z.appendArgs(args)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRank(ctx context.Context, key, member string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zrank", key, member)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZRankWithScore according to the Redis documentation, if member does not exist
|
||||
// in the sorted set or key does not exist, it will return a redis.Nil error.
|
||||
func (c cmdable) ZRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd {
|
||||
cmd := NewRankWithScoreCmd(ctx, "zrank", key, member, "withscore")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRem(ctx context.Context, key string, members ...interface{}) *IntCmd {
|
||||
args := make([]interface{}, 2, 2+len(members))
|
||||
args[0] = "zrem"
|
||||
args[1] = key
|
||||
args = appendArgs(args, members)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRemRangeByRank(ctx context.Context, key string, start, stop int64) *IntCmd {
|
||||
cmd := NewIntCmd(
|
||||
ctx,
|
||||
"zremrangebyrank",
|
||||
key,
|
||||
start,
|
||||
stop,
|
||||
)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRemRangeByScore(ctx context.Context, key, min, max string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zremrangebyscore", key, min, max)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRemRangeByLex(ctx context.Context, key, min, max string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zremrangebylex", key, min, max)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRevRange(ctx context.Context, key string, start, stop int64) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "zrevrange", key, start, stop)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZRevRangeWithScores according to the Redis documentation, if member does not exist
|
||||
// in the sorted set or key does not exist, it will return a redis.Nil error.
|
||||
func (c cmdable) ZRevRangeWithScores(ctx context.Context, key string, start, stop int64) *ZSliceCmd {
|
||||
cmd := NewZSliceCmd(ctx, "zrevrange", key, start, stop, "withscores")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) zRevRangeBy(ctx context.Context, zcmd, key string, opt *ZRangeBy) *StringSliceCmd {
|
||||
args := []interface{}{zcmd, key, opt.Max, opt.Min}
|
||||
if opt.Offset != 0 || opt.Count != 0 {
|
||||
args = append(
|
||||
args,
|
||||
"limit",
|
||||
opt.Offset,
|
||||
opt.Count,
|
||||
)
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRevRangeByScore(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
||||
return c.zRevRangeBy(ctx, "zrevrangebyscore", key, opt)
|
||||
}
|
||||
|
||||
func (c cmdable) ZRevRangeByLex(ctx context.Context, key string, opt *ZRangeBy) *StringSliceCmd {
|
||||
return c.zRevRangeBy(ctx, "zrevrangebylex", key, opt)
|
||||
}
|
||||
|
||||
func (c cmdable) ZRevRangeByScoreWithScores(ctx context.Context, key string, opt *ZRangeBy) *ZSliceCmd {
|
||||
args := []interface{}{"zrevrangebyscore", key, opt.Max, opt.Min, "withscores"}
|
||||
if opt.Offset != 0 || opt.Count != 0 {
|
||||
args = append(
|
||||
args,
|
||||
"limit",
|
||||
opt.Offset,
|
||||
opt.Count,
|
||||
)
|
||||
}
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRevRank(ctx context.Context, key, member string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "zrevrank", key, member)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZRevRankWithScore(ctx context.Context, key, member string) *RankWithScoreCmd {
|
||||
cmd := NewRankWithScoreCmd(ctx, "zrevrank", key, member, "withscore")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZScore(ctx context.Context, key, member string) *FloatCmd {
|
||||
cmd := NewFloatCmd(ctx, "zscore", key, member)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZUnion(ctx context.Context, store ZStore) *StringSliceCmd {
|
||||
args := make([]interface{}, 0, 2+store.len())
|
||||
args = append(args, "zunion", len(store.Keys))
|
||||
args = store.appendArgs(args)
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(2)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZUnionWithScores(ctx context.Context, store ZStore) *ZSliceCmd {
|
||||
args := make([]interface{}, 0, 3+store.len())
|
||||
args = append(args, "zunion", len(store.Keys))
|
||||
args = store.appendArgs(args)
|
||||
args = append(args, "withscores")
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(2)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZUnionStore(ctx context.Context, dest string, store *ZStore) *IntCmd {
|
||||
args := make([]interface{}, 0, 3+store.len())
|
||||
args = append(args, "zunionstore", dest, len(store.Keys))
|
||||
args = store.appendArgs(args)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(3)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZRandMember redis-server version >= 6.2.0.
|
||||
func (c cmdable) ZRandMember(ctx context.Context, key string, count int) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd(ctx, "zrandmember", key, count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZRandMemberWithScores redis-server version >= 6.2.0.
|
||||
func (c cmdable) ZRandMemberWithScores(ctx context.Context, key string, count int) *ZSliceCmd {
|
||||
cmd := NewZSliceCmd(ctx, "zrandmember", key, count, "withscores")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZDiff redis-server version >= 6.2.0.
|
||||
func (c cmdable) ZDiff(ctx context.Context, keys ...string) *StringSliceCmd {
|
||||
args := make([]interface{}, 2+len(keys))
|
||||
args[0] = "zdiff"
|
||||
args[1] = len(keys)
|
||||
for i, key := range keys {
|
||||
args[i+2] = key
|
||||
}
|
||||
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(2)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZDiffWithScores redis-server version >= 6.2.0.
|
||||
func (c cmdable) ZDiffWithScores(ctx context.Context, keys ...string) *ZSliceCmd {
|
||||
args := make([]interface{}, 3+len(keys))
|
||||
args[0] = "zdiff"
|
||||
args[1] = len(keys)
|
||||
for i, key := range keys {
|
||||
args[i+2] = key
|
||||
}
|
||||
args[len(keys)+2] = "withscores"
|
||||
|
||||
cmd := NewZSliceCmd(ctx, args...)
|
||||
cmd.SetFirstKeyPos(2)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// ZDiffStore redis-server version >=6.2.0.
|
||||
func (c cmdable) ZDiffStore(ctx context.Context, destination string, keys ...string) *IntCmd {
|
||||
args := make([]interface{}, 0, 3+len(keys))
|
||||
args = append(args, "zdiffstore", destination, len(keys))
|
||||
for _, key := range keys {
|
||||
args = append(args, key)
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) ZScan(ctx context.Context, key string, cursor uint64, match string, count int64) *ScanCmd {
|
||||
args := []interface{}{"zscan", key, cursor}
|
||||
if match != "" {
|
||||
args = append(args, "match", match)
|
||||
}
|
||||
if count > 0 {
|
||||
args = append(args, "count", count)
|
||||
}
|
||||
cmd := NewScanCmd(ctx, c, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Z represents sorted set member.
|
||||
type Z struct {
|
||||
Score float64
|
||||
Member interface{}
|
||||
}
|
||||
|
||||
// ZWithKey represents sorted set member including the name of the key where it was popped.
|
||||
type ZWithKey struct {
|
||||
Z
|
||||
Key string
|
||||
}
|
||||
|
||||
// ZStore is used as an arg to ZInter/ZInterStore and ZUnion/ZUnionStore.
|
||||
type ZStore struct {
|
||||
Keys []string
|
||||
Weights []float64
|
||||
// Can be SUM, MIN or MAX.
|
||||
Aggregate string
|
||||
}
|
||||
|
||||
func (z ZStore) len() (n int) {
|
||||
n = len(z.Keys)
|
||||
if len(z.Weights) > 0 {
|
||||
n += 1 + len(z.Weights)
|
||||
}
|
||||
if z.Aggregate != "" {
|
||||
n += 2
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (z ZStore) appendArgs(args []interface{}) []interface{} {
|
||||
for _, key := range z.Keys {
|
||||
args = append(args, key)
|
||||
}
|
||||
if len(z.Weights) > 0 {
|
||||
args = append(args, "weights")
|
||||
for _, weights := range z.Weights {
|
||||
args = append(args, weights)
|
||||
}
|
||||
}
|
||||
if z.Aggregate != "" {
|
||||
args = append(args, "aggregate", z.Aggregate)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
|
@ -0,0 +1,438 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StreamCmdable interface {
|
||||
XAdd(ctx context.Context, a *XAddArgs) *StringCmd
|
||||
XDel(ctx context.Context, stream string, ids ...string) *IntCmd
|
||||
XLen(ctx context.Context, stream string) *IntCmd
|
||||
XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
|
||||
XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
|
||||
XRevRange(ctx context.Context, stream string, start, stop string) *XMessageSliceCmd
|
||||
XRevRangeN(ctx context.Context, stream string, start, stop string, count int64) *XMessageSliceCmd
|
||||
XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd
|
||||
XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd
|
||||
XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd
|
||||
XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd
|
||||
XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd
|
||||
XGroupDestroy(ctx context.Context, stream, group string) *IntCmd
|
||||
XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
|
||||
XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd
|
||||
XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd
|
||||
XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd
|
||||
XPending(ctx context.Context, stream, group string) *XPendingCmd
|
||||
XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd
|
||||
XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd
|
||||
XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd
|
||||
XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd
|
||||
XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd
|
||||
XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd
|
||||
XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd
|
||||
XTrimMinID(ctx context.Context, key string, minID string) *IntCmd
|
||||
XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd
|
||||
XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
|
||||
XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
|
||||
XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd
|
||||
XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd
|
||||
}
|
||||
|
||||
// XAddArgs accepts values in the following formats:
|
||||
// - XAddArgs.Values = []interface{}{"key1", "value1", "key2", "value2"}
|
||||
// - XAddArgs.Values = []string("key1", "value1", "key2", "value2")
|
||||
// - XAddArgs.Values = map[string]interface{}{"key1": "value1", "key2": "value2"}
|
||||
//
|
||||
// Note that map will not preserve the order of key-value pairs.
|
||||
// MaxLen/MaxLenApprox and MinID are in conflict, only one of them can be used.
|
||||
type XAddArgs struct {
|
||||
Stream string
|
||||
NoMkStream bool
|
||||
MaxLen int64 // MAXLEN N
|
||||
MinID string
|
||||
// Approx causes MaxLen and MinID to use "~" matcher (instead of "=").
|
||||
Approx bool
|
||||
Limit int64
|
||||
ID string
|
||||
Values interface{}
|
||||
}
|
||||
|
||||
func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
|
||||
args := make([]interface{}, 0, 11)
|
||||
args = append(args, "xadd", a.Stream)
|
||||
if a.NoMkStream {
|
||||
args = append(args, "nomkstream")
|
||||
}
|
||||
switch {
|
||||
case a.MaxLen > 0:
|
||||
if a.Approx {
|
||||
args = append(args, "maxlen", "~", a.MaxLen)
|
||||
} else {
|
||||
args = append(args, "maxlen", a.MaxLen)
|
||||
}
|
||||
case a.MinID != "":
|
||||
if a.Approx {
|
||||
args = append(args, "minid", "~", a.MinID)
|
||||
} else {
|
||||
args = append(args, "minid", a.MinID)
|
||||
}
|
||||
}
|
||||
if a.Limit > 0 {
|
||||
args = append(args, "limit", a.Limit)
|
||||
}
|
||||
if a.ID != "" {
|
||||
args = append(args, a.ID)
|
||||
} else {
|
||||
args = append(args, "*")
|
||||
}
|
||||
args = appendArg(args, a.Values)
|
||||
|
||||
cmd := NewStringCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
|
||||
args := []interface{}{"xdel", stream}
|
||||
for _, id := range ids {
|
||||
args = append(args, id)
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "xlen", stream)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
|
||||
cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
|
||||
cmd := NewXMessageSliceCmd(ctx, "xrange", stream, start, stop, "count", count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XRevRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd {
|
||||
cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XRevRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd {
|
||||
cmd := NewXMessageSliceCmd(ctx, "xrevrange", stream, start, stop, "count", count)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type XReadArgs struct {
|
||||
Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
|
||||
Count int64
|
||||
Block time.Duration
|
||||
}
|
||||
|
||||
func (c cmdable) XRead(ctx context.Context, a *XReadArgs) *XStreamSliceCmd {
|
||||
args := make([]interface{}, 0, 6+len(a.Streams))
|
||||
args = append(args, "xread")
|
||||
|
||||
keyPos := int8(1)
|
||||
if a.Count > 0 {
|
||||
args = append(args, "count")
|
||||
args = append(args, a.Count)
|
||||
keyPos += 2
|
||||
}
|
||||
if a.Block >= 0 {
|
||||
args = append(args, "block")
|
||||
args = append(args, int64(a.Block/time.Millisecond))
|
||||
keyPos += 2
|
||||
}
|
||||
args = append(args, "streams")
|
||||
keyPos++
|
||||
for _, s := range a.Streams {
|
||||
args = append(args, s)
|
||||
}
|
||||
|
||||
cmd := NewXStreamSliceCmd(ctx, args...)
|
||||
if a.Block >= 0 {
|
||||
cmd.setReadTimeout(a.Block)
|
||||
}
|
||||
cmd.SetFirstKeyPos(keyPos)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XReadStreams(ctx context.Context, streams ...string) *XStreamSliceCmd {
|
||||
return c.XRead(ctx, &XReadArgs{
|
||||
Streams: streams,
|
||||
Block: -1,
|
||||
})
|
||||
}
|
||||
|
||||
func (c cmdable) XGroupCreate(ctx context.Context, stream, group, start string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XGroupCreateMkStream(ctx context.Context, stream, group, start string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "xgroup", "create", stream, group, start, "mkstream")
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XGroupSetID(ctx context.Context, stream, group, start string) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "xgroup", "setid", stream, group, start)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XGroupDestroy(ctx context.Context, stream, group string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "xgroup", "destroy", stream, group)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XGroupCreateConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "xgroup", "createconsumer", stream, group, consumer)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XGroupDelConsumer(ctx context.Context, stream, group, consumer string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "xgroup", "delconsumer", stream, group, consumer)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type XReadGroupArgs struct {
|
||||
Group string
|
||||
Consumer string
|
||||
Streams []string // list of streams and ids, e.g. stream1 stream2 id1 id2
|
||||
Count int64
|
||||
Block time.Duration
|
||||
NoAck bool
|
||||
}
|
||||
|
||||
func (c cmdable) XReadGroup(ctx context.Context, a *XReadGroupArgs) *XStreamSliceCmd {
|
||||
args := make([]interface{}, 0, 10+len(a.Streams))
|
||||
args = append(args, "xreadgroup", "group", a.Group, a.Consumer)
|
||||
|
||||
keyPos := int8(4)
|
||||
if a.Count > 0 {
|
||||
args = append(args, "count", a.Count)
|
||||
keyPos += 2
|
||||
}
|
||||
if a.Block >= 0 {
|
||||
args = append(args, "block", int64(a.Block/time.Millisecond))
|
||||
keyPos += 2
|
||||
}
|
||||
if a.NoAck {
|
||||
args = append(args, "noack")
|
||||
keyPos++
|
||||
}
|
||||
args = append(args, "streams")
|
||||
keyPos++
|
||||
for _, s := range a.Streams {
|
||||
args = append(args, s)
|
||||
}
|
||||
|
||||
cmd := NewXStreamSliceCmd(ctx, args...)
|
||||
if a.Block >= 0 {
|
||||
cmd.setReadTimeout(a.Block)
|
||||
}
|
||||
cmd.SetFirstKeyPos(keyPos)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XAck(ctx context.Context, stream, group string, ids ...string) *IntCmd {
|
||||
args := []interface{}{"xack", stream, group}
|
||||
for _, id := range ids {
|
||||
args = append(args, id)
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XPending(ctx context.Context, stream, group string) *XPendingCmd {
|
||||
cmd := NewXPendingCmd(ctx, "xpending", stream, group)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type XPendingExtArgs struct {
|
||||
Stream string
|
||||
Group string
|
||||
Idle time.Duration
|
||||
Start string
|
||||
End string
|
||||
Count int64
|
||||
Consumer string
|
||||
}
|
||||
|
||||
func (c cmdable) XPendingExt(ctx context.Context, a *XPendingExtArgs) *XPendingExtCmd {
|
||||
args := make([]interface{}, 0, 9)
|
||||
args = append(args, "xpending", a.Stream, a.Group)
|
||||
if a.Idle != 0 {
|
||||
args = append(args, "idle", formatMs(ctx, a.Idle))
|
||||
}
|
||||
args = append(args, a.Start, a.End, a.Count)
|
||||
if a.Consumer != "" {
|
||||
args = append(args, a.Consumer)
|
||||
}
|
||||
cmd := NewXPendingExtCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type XAutoClaimArgs struct {
|
||||
Stream string
|
||||
Group string
|
||||
MinIdle time.Duration
|
||||
Start string
|
||||
Count int64
|
||||
Consumer string
|
||||
}
|
||||
|
||||
func (c cmdable) XAutoClaim(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimCmd {
|
||||
args := xAutoClaimArgs(ctx, a)
|
||||
cmd := NewXAutoClaimCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd {
|
||||
args := xAutoClaimArgs(ctx, a)
|
||||
args = append(args, "justid")
|
||||
cmd := NewXAutoClaimJustIDCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func xAutoClaimArgs(ctx context.Context, a *XAutoClaimArgs) []interface{} {
|
||||
args := make([]interface{}, 0, 8)
|
||||
args = append(args, "xautoclaim", a.Stream, a.Group, a.Consumer, formatMs(ctx, a.MinIdle), a.Start)
|
||||
if a.Count > 0 {
|
||||
args = append(args, "count", a.Count)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
type XClaimArgs struct {
|
||||
Stream string
|
||||
Group string
|
||||
Consumer string
|
||||
MinIdle time.Duration
|
||||
Messages []string
|
||||
}
|
||||
|
||||
func (c cmdable) XClaim(ctx context.Context, a *XClaimArgs) *XMessageSliceCmd {
|
||||
args := xClaimArgs(a)
|
||||
cmd := NewXMessageSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XClaimJustID(ctx context.Context, a *XClaimArgs) *StringSliceCmd {
|
||||
args := xClaimArgs(a)
|
||||
args = append(args, "justid")
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func xClaimArgs(a *XClaimArgs) []interface{} {
|
||||
args := make([]interface{}, 0, 5+len(a.Messages))
|
||||
args = append(args,
|
||||
"xclaim",
|
||||
a.Stream,
|
||||
a.Group, a.Consumer,
|
||||
int64(a.MinIdle/time.Millisecond))
|
||||
for _, id := range a.Messages {
|
||||
args = append(args, id)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default).
|
||||
// example:
|
||||
//
|
||||
// XTRIM key MAXLEN/MINID threshold LIMIT limit.
|
||||
// XTRIM key MAXLEN/MINID ~ threshold LIMIT limit.
|
||||
//
|
||||
// The redis-server version is lower than 6.2, please set limit to 0.
|
||||
func (c cmdable) xTrim(
|
||||
ctx context.Context, key, strategy string,
|
||||
approx bool, threshold interface{}, limit int64,
|
||||
) *IntCmd {
|
||||
args := make([]interface{}, 0, 7)
|
||||
args = append(args, "xtrim", key, strategy)
|
||||
if approx {
|
||||
args = append(args, "~")
|
||||
}
|
||||
args = append(args, threshold)
|
||||
if limit > 0 {
|
||||
args = append(args, "limit", limit)
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// XTrimMaxLen No `~` rules are used, `limit` cannot be used.
|
||||
// cmd: XTRIM key MAXLEN maxLen
|
||||
func (c cmdable) XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd {
|
||||
return c.xTrim(ctx, key, "maxlen", false, maxLen, 0)
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd {
|
||||
return c.xTrim(ctx, key, "maxlen", true, maxLen, limit)
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMinID(ctx context.Context, key string, minID string) *IntCmd {
|
||||
return c.xTrim(ctx, key, "minid", false, minID, 0)
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd {
|
||||
return c.xTrim(ctx, key, "minid", true, minID, limit)
|
||||
}
|
||||
|
||||
func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd {
|
||||
cmd := NewXInfoConsumersCmd(ctx, key, group)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd {
|
||||
cmd := NewXInfoGroupsCmd(ctx, key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XInfoStream(ctx context.Context, key string) *XInfoStreamCmd {
|
||||
cmd := NewXInfoStreamCmd(ctx, key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// XInfoStreamFull XINFO STREAM FULL [COUNT count]
|
||||
// redis-server >= 6.0.
|
||||
func (c cmdable) XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd {
|
||||
args := make([]interface{}, 0, 6)
|
||||
args = append(args, "xinfo", "stream", key, "full")
|
||||
if count > 0 {
|
||||
args = append(args, "count", count)
|
||||
}
|
||||
cmd := NewXInfoStreamFullCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,303 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StringCmdable interface {
|
||||
Append(ctx context.Context, key, value string) *IntCmd
|
||||
Decr(ctx context.Context, key string) *IntCmd
|
||||
DecrBy(ctx context.Context, key string, decrement int64) *IntCmd
|
||||
Get(ctx context.Context, key string) *StringCmd
|
||||
GetRange(ctx context.Context, key string, start, end int64) *StringCmd
|
||||
GetSet(ctx context.Context, key string, value interface{}) *StringCmd
|
||||
GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd
|
||||
GetDel(ctx context.Context, key string) *StringCmd
|
||||
Incr(ctx context.Context, key string) *IntCmd
|
||||
IncrBy(ctx context.Context, key string, value int64) *IntCmd
|
||||
IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd
|
||||
LCS(ctx context.Context, q *LCSQuery) *LCSCmd
|
||||
MGet(ctx context.Context, keys ...string) *SliceCmd
|
||||
MSet(ctx context.Context, values ...interface{}) *StatusCmd
|
||||
MSetNX(ctx context.Context, values ...interface{}) *BoolCmd
|
||||
Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
|
||||
SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd
|
||||
SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd
|
||||
SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
|
||||
SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd
|
||||
SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd
|
||||
StrLen(ctx context.Context, key string) *IntCmd
|
||||
}
|
||||
|
||||
func (c cmdable) Append(ctx context.Context, key, value string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "append", key, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Decr(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "decr", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) DecrBy(ctx context.Context, key string, decrement int64) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "decrby", key, decrement)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Get Redis `GET key` command. It returns redis.Nil error when key does not exist.
|
||||
func (c cmdable) Get(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "get", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GetRange(ctx context.Context, key string, start, end int64) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "getrange", key, start, end)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) GetSet(ctx context.Context, key string, value interface{}) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "getset", key, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetEx An expiration of zero removes the TTL associated with the key (i.e. GETEX key persist).
|
||||
// Requires Redis >= 6.2.0.
|
||||
func (c cmdable) GetEx(ctx context.Context, key string, expiration time.Duration) *StringCmd {
|
||||
args := make([]interface{}, 0, 4)
|
||||
args = append(args, "getex", key)
|
||||
if expiration > 0 {
|
||||
if usePrecise(expiration) {
|
||||
args = append(args, "px", formatMs(ctx, expiration))
|
||||
} else {
|
||||
args = append(args, "ex", formatSec(ctx, expiration))
|
||||
}
|
||||
} else if expiration == 0 {
|
||||
args = append(args, "persist")
|
||||
}
|
||||
|
||||
cmd := NewStringCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// GetDel redis-server version >= 6.2.0.
|
||||
func (c cmdable) GetDel(ctx context.Context, key string) *StringCmd {
|
||||
cmd := NewStringCmd(ctx, "getdel", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) Incr(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "incr", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) IncrBy(ctx context.Context, key string, value int64) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "incrby", key, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) IncrByFloat(ctx context.Context, key string, value float64) *FloatCmd {
|
||||
cmd := NewFloatCmd(ctx, "incrbyfloat", key, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) LCS(ctx context.Context, q *LCSQuery) *LCSCmd {
|
||||
cmd := NewLCSCmd(ctx, q)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) MGet(ctx context.Context, keys ...string) *SliceCmd {
|
||||
args := make([]interface{}, 1+len(keys))
|
||||
args[0] = "mget"
|
||||
for i, key := range keys {
|
||||
args[1+i] = key
|
||||
}
|
||||
cmd := NewSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// MSet is like Set but accepts multiple values:
|
||||
// - MSet("key1", "value1", "key2", "value2")
|
||||
// - MSet([]string{"key1", "value1", "key2", "value2"})
|
||||
// - MSet(map[string]interface{}{"key1": "value1", "key2": "value2"})
|
||||
// - MSet(struct), For struct types, see HSet description.
|
||||
func (c cmdable) MSet(ctx context.Context, values ...interface{}) *StatusCmd {
|
||||
args := make([]interface{}, 1, 1+len(values))
|
||||
args[0] = "mset"
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// MSetNX is like SetNX but accepts multiple values:
|
||||
// - MSetNX("key1", "value1", "key2", "value2")
|
||||
// - MSetNX([]string{"key1", "value1", "key2", "value2"})
|
||||
// - MSetNX(map[string]interface{}{"key1": "value1", "key2": "value2"})
|
||||
// - MSetNX(struct), For struct types, see HSet description.
|
||||
func (c cmdable) MSetNX(ctx context.Context, values ...interface{}) *BoolCmd {
|
||||
args := make([]interface{}, 1, 1+len(values))
|
||||
args[0] = "msetnx"
|
||||
args = appendArgs(args, values)
|
||||
cmd := NewBoolCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Set Redis `SET key value [expiration]` command.
|
||||
// Use expiration for `SETEx`-like behavior.
|
||||
//
|
||||
// Zero expiration means the key has no expiration time.
|
||||
// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
|
||||
// otherwise you will receive an error: (error) ERR syntax error.
|
||||
func (c cmdable) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
|
||||
args := make([]interface{}, 3, 5)
|
||||
args[0] = "set"
|
||||
args[1] = key
|
||||
args[2] = value
|
||||
if expiration > 0 {
|
||||
if usePrecise(expiration) {
|
||||
args = append(args, "px", formatMs(ctx, expiration))
|
||||
} else {
|
||||
args = append(args, "ex", formatSec(ctx, expiration))
|
||||
}
|
||||
} else if expiration == KeepTTL {
|
||||
args = append(args, "keepttl")
|
||||
}
|
||||
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetArgs provides arguments for the SetArgs function.
|
||||
type SetArgs struct {
|
||||
// Mode can be `NX` or `XX` or empty.
|
||||
Mode string
|
||||
|
||||
// Zero `TTL` or `Expiration` means that the key has no expiration time.
|
||||
TTL time.Duration
|
||||
ExpireAt time.Time
|
||||
|
||||
// When Get is true, the command returns the old value stored at key, or nil when key did not exist.
|
||||
Get bool
|
||||
|
||||
// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
|
||||
// otherwise you will receive an error: (error) ERR syntax error.
|
||||
KeepTTL bool
|
||||
}
|
||||
|
||||
// SetArgs supports all the options that the SET command supports.
|
||||
// It is the alternative to the Set function when you want
|
||||
// to have more control over the options.
|
||||
func (c cmdable) SetArgs(ctx context.Context, key string, value interface{}, a SetArgs) *StatusCmd {
|
||||
args := []interface{}{"set", key, value}
|
||||
|
||||
if a.KeepTTL {
|
||||
args = append(args, "keepttl")
|
||||
}
|
||||
|
||||
if !a.ExpireAt.IsZero() {
|
||||
args = append(args, "exat", a.ExpireAt.Unix())
|
||||
}
|
||||
if a.TTL > 0 {
|
||||
if usePrecise(a.TTL) {
|
||||
args = append(args, "px", formatMs(ctx, a.TTL))
|
||||
} else {
|
||||
args = append(args, "ex", formatSec(ctx, a.TTL))
|
||||
}
|
||||
}
|
||||
|
||||
if a.Mode != "" {
|
||||
args = append(args, a.Mode)
|
||||
}
|
||||
|
||||
if a.Get {
|
||||
args = append(args, "get")
|
||||
}
|
||||
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetEx Redis `SETEx key expiration value` command.
|
||||
func (c cmdable) SetEx(ctx context.Context, key string, value interface{}, expiration time.Duration) *StatusCmd {
|
||||
cmd := NewStatusCmd(ctx, "setex", key, formatSec(ctx, expiration), value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetNX Redis `SET key value [expiration] NX` command.
|
||||
//
|
||||
// Zero expiration means the key has no expiration time.
|
||||
// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
|
||||
// otherwise you will receive an error: (error) ERR syntax error.
|
||||
func (c cmdable) SetNX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
|
||||
var cmd *BoolCmd
|
||||
switch expiration {
|
||||
case 0:
|
||||
// Use old `SETNX` to support old Redis versions.
|
||||
cmd = NewBoolCmd(ctx, "setnx", key, value)
|
||||
case KeepTTL:
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "nx")
|
||||
default:
|
||||
if usePrecise(expiration) {
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "nx")
|
||||
} else {
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "nx")
|
||||
}
|
||||
}
|
||||
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// SetXX Redis `SET key value [expiration] XX` command.
|
||||
//
|
||||
// Zero expiration means the key has no expiration time.
|
||||
// KeepTTL is a Redis KEEPTTL option to keep existing TTL, it requires your redis-server version >= 6.0,
|
||||
// otherwise you will receive an error: (error) ERR syntax error.
|
||||
func (c cmdable) SetXX(ctx context.Context, key string, value interface{}, expiration time.Duration) *BoolCmd {
|
||||
var cmd *BoolCmd
|
||||
switch expiration {
|
||||
case 0:
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "xx")
|
||||
case KeepTTL:
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "keepttl", "xx")
|
||||
default:
|
||||
if usePrecise(expiration) {
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "px", formatMs(ctx, expiration), "xx")
|
||||
} else {
|
||||
cmd = NewBoolCmd(ctx, "set", key, value, "ex", formatSec(ctx, expiration), "xx")
|
||||
}
|
||||
}
|
||||
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) SetRange(ctx context.Context, key string, offset int64, value string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "setrange", key, offset, value)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) StrLen(ctx context.Context, key string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "strlen", key)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -0,0 +1,920 @@
|
|||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
"github.com/redis/go-redis/v9/internal/proto"
|
||||
)
|
||||
|
||||
type TimeseriesCmdable interface {
|
||||
TSAdd(ctx context.Context, key string, timestamp interface{}, value float64) *IntCmd
|
||||
TSAddWithArgs(ctx context.Context, key string, timestamp interface{}, value float64, options *TSOptions) *IntCmd
|
||||
TSCreate(ctx context.Context, key string) *StatusCmd
|
||||
TSCreateWithArgs(ctx context.Context, key string, options *TSOptions) *StatusCmd
|
||||
TSAlter(ctx context.Context, key string, options *TSAlterOptions) *StatusCmd
|
||||
TSCreateRule(ctx context.Context, sourceKey string, destKey string, aggregator Aggregator, bucketDuration int) *StatusCmd
|
||||
TSCreateRuleWithArgs(ctx context.Context, sourceKey string, destKey string, aggregator Aggregator, bucketDuration int, options *TSCreateRuleOptions) *StatusCmd
|
||||
TSIncrBy(ctx context.Context, Key string, timestamp float64) *IntCmd
|
||||
TSIncrByWithArgs(ctx context.Context, key string, timestamp float64, options *TSIncrDecrOptions) *IntCmd
|
||||
TSDecrBy(ctx context.Context, Key string, timestamp float64) *IntCmd
|
||||
TSDecrByWithArgs(ctx context.Context, key string, timestamp float64, options *TSIncrDecrOptions) *IntCmd
|
||||
TSDel(ctx context.Context, Key string, fromTimestamp int, toTimestamp int) *IntCmd
|
||||
TSDeleteRule(ctx context.Context, sourceKey string, destKey string) *StatusCmd
|
||||
TSGet(ctx context.Context, key string) *TSTimestampValueCmd
|
||||
TSGetWithArgs(ctx context.Context, key string, options *TSGetOptions) *TSTimestampValueCmd
|
||||
TSInfo(ctx context.Context, key string) *MapStringInterfaceCmd
|
||||
TSInfoWithArgs(ctx context.Context, key string, options *TSInfoOptions) *MapStringInterfaceCmd
|
||||
TSMAdd(ctx context.Context, ktvSlices [][]interface{}) *IntSliceCmd
|
||||
TSQueryIndex(ctx context.Context, filterExpr []string) *StringSliceCmd
|
||||
TSRevRange(ctx context.Context, key string, fromTimestamp int, toTimestamp int) *TSTimestampValueSliceCmd
|
||||
TSRevRangeWithArgs(ctx context.Context, key string, fromTimestamp int, toTimestamp int, options *TSRevRangeOptions) *TSTimestampValueSliceCmd
|
||||
TSRange(ctx context.Context, key string, fromTimestamp int, toTimestamp int) *TSTimestampValueSliceCmd
|
||||
TSRangeWithArgs(ctx context.Context, key string, fromTimestamp int, toTimestamp int, options *TSRangeOptions) *TSTimestampValueSliceCmd
|
||||
TSMRange(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string) *MapStringSliceInterfaceCmd
|
||||
TSMRangeWithArgs(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string, options *TSMRangeOptions) *MapStringSliceInterfaceCmd
|
||||
TSMRevRange(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string) *MapStringSliceInterfaceCmd
|
||||
TSMRevRangeWithArgs(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string, options *TSMRevRangeOptions) *MapStringSliceInterfaceCmd
|
||||
TSMGet(ctx context.Context, filters []string) *MapStringSliceInterfaceCmd
|
||||
TSMGetWithArgs(ctx context.Context, filters []string, options *TSMGetOptions) *MapStringSliceInterfaceCmd
|
||||
}
|
||||
|
||||
type TSOptions struct {
|
||||
Retention int
|
||||
ChunkSize int
|
||||
Encoding string
|
||||
DuplicatePolicy string
|
||||
Labels map[string]string
|
||||
}
|
||||
type TSIncrDecrOptions struct {
|
||||
Timestamp int64
|
||||
Retention int
|
||||
ChunkSize int
|
||||
Uncompressed bool
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
type TSAlterOptions struct {
|
||||
Retention int
|
||||
ChunkSize int
|
||||
DuplicatePolicy string
|
||||
Labels map[string]string
|
||||
}
|
||||
|
||||
type TSCreateRuleOptions struct {
|
||||
alignTimestamp int64
|
||||
}
|
||||
|
||||
type TSGetOptions struct {
|
||||
Latest bool
|
||||
}
|
||||
|
||||
type TSInfoOptions struct {
|
||||
Debug bool
|
||||
}
|
||||
type Aggregator int
|
||||
|
||||
const (
|
||||
Invalid = Aggregator(iota)
|
||||
Avg
|
||||
Sum
|
||||
Min
|
||||
Max
|
||||
Range
|
||||
Count
|
||||
First
|
||||
Last
|
||||
StdP
|
||||
StdS
|
||||
VarP
|
||||
VarS
|
||||
Twa
|
||||
)
|
||||
|
||||
func (a Aggregator) String() string {
|
||||
switch a {
|
||||
case Invalid:
|
||||
return ""
|
||||
case Avg:
|
||||
return "AVG"
|
||||
case Sum:
|
||||
return "SUM"
|
||||
case Min:
|
||||
return "MIN"
|
||||
case Max:
|
||||
return "MAX"
|
||||
case Range:
|
||||
return "RANGE"
|
||||
case Count:
|
||||
return "COUNT"
|
||||
case First:
|
||||
return "FIRST"
|
||||
case Last:
|
||||
return "LAST"
|
||||
case StdP:
|
||||
return "STD.P"
|
||||
case StdS:
|
||||
return "STD.S"
|
||||
case VarP:
|
||||
return "VAR.P"
|
||||
case VarS:
|
||||
return "VAR.S"
|
||||
case Twa:
|
||||
return "TWA"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
type TSRangeOptions struct {
|
||||
Latest bool
|
||||
FilterByTS []int
|
||||
FilterByValue []int
|
||||
Count int
|
||||
Align interface{}
|
||||
Aggregator Aggregator
|
||||
BucketDuration int
|
||||
BucketTimestamp interface{}
|
||||
Empty bool
|
||||
}
|
||||
|
||||
type TSRevRangeOptions struct {
|
||||
Latest bool
|
||||
FilterByTS []int
|
||||
FilterByValue []int
|
||||
Count int
|
||||
Align interface{}
|
||||
Aggregator Aggregator
|
||||
BucketDuration int
|
||||
BucketTimestamp interface{}
|
||||
Empty bool
|
||||
}
|
||||
|
||||
type TSMRangeOptions struct {
|
||||
Latest bool
|
||||
FilterByTS []int
|
||||
FilterByValue []int
|
||||
WithLabels bool
|
||||
SelectedLabels []interface{}
|
||||
Count int
|
||||
Align interface{}
|
||||
Aggregator Aggregator
|
||||
BucketDuration int
|
||||
BucketTimestamp interface{}
|
||||
Empty bool
|
||||
GroupByLabel interface{}
|
||||
Reducer interface{}
|
||||
}
|
||||
|
||||
type TSMRevRangeOptions struct {
|
||||
Latest bool
|
||||
FilterByTS []int
|
||||
FilterByValue []int
|
||||
WithLabels bool
|
||||
SelectedLabels []interface{}
|
||||
Count int
|
||||
Align interface{}
|
||||
Aggregator Aggregator
|
||||
BucketDuration int
|
||||
BucketTimestamp interface{}
|
||||
Empty bool
|
||||
GroupByLabel interface{}
|
||||
Reducer interface{}
|
||||
}
|
||||
|
||||
type TSMGetOptions struct {
|
||||
Latest bool
|
||||
WithLabels bool
|
||||
SelectedLabels []interface{}
|
||||
}
|
||||
|
||||
// TSAdd - Adds one or more observations to a t-digest sketch.
|
||||
// For more information - https://redis.io/commands/ts.add/
|
||||
func (c cmdable) TSAdd(ctx context.Context, key string, timestamp interface{}, value float64) *IntCmd {
|
||||
args := []interface{}{"TS.ADD", key, timestamp, value}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSAddWithArgs - Adds one or more observations to a t-digest sketch.
|
||||
// This function also allows for specifying additional options such as:
|
||||
// Retention, ChunkSize, Encoding, DuplicatePolicy and Labels.
|
||||
// For more information - https://redis.io/commands/ts.add/
|
||||
func (c cmdable) TSAddWithArgs(ctx context.Context, key string, timestamp interface{}, value float64, options *TSOptions) *IntCmd {
|
||||
args := []interface{}{"TS.ADD", key, timestamp, value}
|
||||
if options != nil {
|
||||
if options.Retention != 0 {
|
||||
args = append(args, "RETENTION", options.Retention)
|
||||
}
|
||||
if options.ChunkSize != 0 {
|
||||
args = append(args, "CHUNK_SIZE", options.ChunkSize)
|
||||
}
|
||||
if options.Encoding != "" {
|
||||
args = append(args, "ENCODING", options.Encoding)
|
||||
}
|
||||
|
||||
if options.DuplicatePolicy != "" {
|
||||
args = append(args, "DUPLICATE_POLICY", options.DuplicatePolicy)
|
||||
}
|
||||
if options.Labels != nil {
|
||||
args = append(args, "LABELS")
|
||||
for label, value := range options.Labels {
|
||||
args = append(args, label, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSCreate - Creates a new time-series key.
|
||||
// For more information - https://redis.io/commands/ts.create/
|
||||
func (c cmdable) TSCreate(ctx context.Context, key string) *StatusCmd {
|
||||
args := []interface{}{"TS.CREATE", key}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSCreateWithArgs - Creates a new time-series key with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Retention, ChunkSize, Encoding, DuplicatePolicy and Labels.
|
||||
// For more information - https://redis.io/commands/ts.create/
|
||||
func (c cmdable) TSCreateWithArgs(ctx context.Context, key string, options *TSOptions) *StatusCmd {
|
||||
args := []interface{}{"TS.CREATE", key}
|
||||
if options != nil {
|
||||
if options.Retention != 0 {
|
||||
args = append(args, "RETENTION", options.Retention)
|
||||
}
|
||||
if options.ChunkSize != 0 {
|
||||
args = append(args, "CHUNK_SIZE", options.ChunkSize)
|
||||
}
|
||||
if options.Encoding != "" {
|
||||
args = append(args, "ENCODING", options.Encoding)
|
||||
}
|
||||
|
||||
if options.DuplicatePolicy != "" {
|
||||
args = append(args, "DUPLICATE_POLICY", options.DuplicatePolicy)
|
||||
}
|
||||
if options.Labels != nil {
|
||||
args = append(args, "LABELS")
|
||||
for label, value := range options.Labels {
|
||||
args = append(args, label, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSAlter - Alters an existing time-series key with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Retention, ChunkSize and DuplicatePolicy.
|
||||
// For more information - https://redis.io/commands/ts.alter/
|
||||
func (c cmdable) TSAlter(ctx context.Context, key string, options *TSAlterOptions) *StatusCmd {
|
||||
args := []interface{}{"TS.ALTER", key}
|
||||
if options != nil {
|
||||
if options.Retention != 0 {
|
||||
args = append(args, "RETENTION", options.Retention)
|
||||
}
|
||||
if options.ChunkSize != 0 {
|
||||
args = append(args, "CHUNK_SIZE", options.ChunkSize)
|
||||
}
|
||||
if options.DuplicatePolicy != "" {
|
||||
args = append(args, "DUPLICATE_POLICY", options.DuplicatePolicy)
|
||||
}
|
||||
if options.Labels != nil {
|
||||
args = append(args, "LABELS")
|
||||
for label, value := range options.Labels {
|
||||
args = append(args, label, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSCreateRule - Creates a compaction rule from sourceKey to destKey.
|
||||
// For more information - https://redis.io/commands/ts.createrule/
|
||||
func (c cmdable) TSCreateRule(ctx context.Context, sourceKey string, destKey string, aggregator Aggregator, bucketDuration int) *StatusCmd {
|
||||
args := []interface{}{"TS.CREATERULE", sourceKey, destKey, "AGGREGATION", aggregator.String(), bucketDuration}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSCreateRuleWithArgs - Creates a compaction rule from sourceKey to destKey with additional option.
|
||||
// This function allows for specifying additional option such as:
|
||||
// alignTimestamp.
|
||||
// For more information - https://redis.io/commands/ts.createrule/
|
||||
func (c cmdable) TSCreateRuleWithArgs(ctx context.Context, sourceKey string, destKey string, aggregator Aggregator, bucketDuration int, options *TSCreateRuleOptions) *StatusCmd {
|
||||
args := []interface{}{"TS.CREATERULE", sourceKey, destKey, "AGGREGATION", aggregator.String(), bucketDuration}
|
||||
if options != nil {
|
||||
if options.alignTimestamp != 0 {
|
||||
args = append(args, options.alignTimestamp)
|
||||
}
|
||||
}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSIncrBy - Increments the value of a time-series key by the specified timestamp.
|
||||
// For more information - https://redis.io/commands/ts.incrby/
|
||||
func (c cmdable) TSIncrBy(ctx context.Context, Key string, timestamp float64) *IntCmd {
|
||||
args := []interface{}{"TS.INCRBY", Key, timestamp}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSIncrByWithArgs - Increments the value of a time-series key by the specified timestamp with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Timestamp, Retention, ChunkSize, Uncompressed and Labels.
|
||||
// For more information - https://redis.io/commands/ts.incrby/
|
||||
func (c cmdable) TSIncrByWithArgs(ctx context.Context, key string, timestamp float64, options *TSIncrDecrOptions) *IntCmd {
|
||||
args := []interface{}{"TS.INCRBY", key, timestamp}
|
||||
if options != nil {
|
||||
if options.Timestamp != 0 {
|
||||
args = append(args, "TIMESTAMP", options.Timestamp)
|
||||
}
|
||||
if options.Retention != 0 {
|
||||
args = append(args, "RETENTION", options.Retention)
|
||||
}
|
||||
if options.ChunkSize != 0 {
|
||||
args = append(args, "CHUNK_SIZE", options.ChunkSize)
|
||||
}
|
||||
if options.Uncompressed {
|
||||
args = append(args, "UNCOMPRESSED")
|
||||
}
|
||||
if options.Labels != nil {
|
||||
args = append(args, "LABELS")
|
||||
for label, value := range options.Labels {
|
||||
args = append(args, label, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSDecrBy - Decrements the value of a time-series key by the specified timestamp.
|
||||
// For more information - https://redis.io/commands/ts.decrby/
|
||||
func (c cmdable) TSDecrBy(ctx context.Context, Key string, timestamp float64) *IntCmd {
|
||||
args := []interface{}{"TS.DECRBY", Key, timestamp}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSDecrByWithArgs - Decrements the value of a time-series key by the specified timestamp with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Timestamp, Retention, ChunkSize, Uncompressed and Labels.
|
||||
// For more information - https://redis.io/commands/ts.decrby/
|
||||
func (c cmdable) TSDecrByWithArgs(ctx context.Context, key string, timestamp float64, options *TSIncrDecrOptions) *IntCmd {
|
||||
args := []interface{}{"TS.DECRBY", key, timestamp}
|
||||
if options != nil {
|
||||
if options.Timestamp != 0 {
|
||||
args = append(args, "TIMESTAMP", options.Timestamp)
|
||||
}
|
||||
if options.Retention != 0 {
|
||||
args = append(args, "RETENTION", options.Retention)
|
||||
}
|
||||
if options.ChunkSize != 0 {
|
||||
args = append(args, "CHUNK_SIZE", options.ChunkSize)
|
||||
}
|
||||
if options.Uncompressed {
|
||||
args = append(args, "UNCOMPRESSED")
|
||||
}
|
||||
if options.Labels != nil {
|
||||
args = append(args, "LABELS")
|
||||
for label, value := range options.Labels {
|
||||
args = append(args, label, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSDel - Deletes a range of samples from a time-series key.
|
||||
// For more information - https://redis.io/commands/ts.del/
|
||||
func (c cmdable) TSDel(ctx context.Context, Key string, fromTimestamp int, toTimestamp int) *IntCmd {
|
||||
args := []interface{}{"TS.DEL", Key, fromTimestamp, toTimestamp}
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSDeleteRule - Deletes a compaction rule from sourceKey to destKey.
|
||||
// For more information - https://redis.io/commands/ts.deleterule/
|
||||
func (c cmdable) TSDeleteRule(ctx context.Context, sourceKey string, destKey string) *StatusCmd {
|
||||
args := []interface{}{"TS.DELETERULE", sourceKey, destKey}
|
||||
cmd := NewStatusCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSGetWithArgs - Gets the last sample of a time-series key with additional option.
|
||||
// This function allows for specifying additional option such as:
|
||||
// Latest.
|
||||
// For more information - https://redis.io/commands/ts.get/
|
||||
func (c cmdable) TSGetWithArgs(ctx context.Context, key string, options *TSGetOptions) *TSTimestampValueCmd {
|
||||
args := []interface{}{"TS.GET", key}
|
||||
if options != nil {
|
||||
if options.Latest {
|
||||
args = append(args, "LATEST")
|
||||
}
|
||||
}
|
||||
cmd := newTSTimestampValueCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSGet - Gets the last sample of a time-series key.
|
||||
// For more information - https://redis.io/commands/ts.get/
|
||||
func (c cmdable) TSGet(ctx context.Context, key string) *TSTimestampValueCmd {
|
||||
args := []interface{}{"TS.GET", key}
|
||||
cmd := newTSTimestampValueCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type TSTimestampValue struct {
|
||||
Timestamp int64
|
||||
Value float64
|
||||
}
|
||||
type TSTimestampValueCmd struct {
|
||||
baseCmd
|
||||
val TSTimestampValue
|
||||
}
|
||||
|
||||
func newTSTimestampValueCmd(ctx context.Context, args ...interface{}) *TSTimestampValueCmd {
|
||||
return &TSTimestampValueCmd{
|
||||
baseCmd: baseCmd{
|
||||
ctx: ctx,
|
||||
args: args,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueCmd) String() string {
|
||||
return cmdString(cmd, cmd.val)
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueCmd) SetVal(val TSTimestampValue) {
|
||||
cmd.val = val
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueCmd) Result() (TSTimestampValue, error) {
|
||||
return cmd.val, cmd.err
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueCmd) Val() TSTimestampValue {
|
||||
return cmd.val
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueCmd) readReply(rd *proto.Reader) (err error) {
|
||||
n, err := rd.ReadMapLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val = TSTimestampValue{}
|
||||
for i := 0; i < n; i++ {
|
||||
timestamp, err := rd.ReadInt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value, err := rd.ReadString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val.Timestamp = timestamp
|
||||
cmd.val.Value, err = strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TSInfo - Returns information about a time-series key.
|
||||
// For more information - https://redis.io/commands/ts.info/
|
||||
func (c cmdable) TSInfo(ctx context.Context, key string) *MapStringInterfaceCmd {
|
||||
args := []interface{}{"TS.INFO", key}
|
||||
cmd := NewMapStringInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSInfoWithArgs - Returns information about a time-series key with additional option.
|
||||
// This function allows for specifying additional option such as:
|
||||
// Debug.
|
||||
// For more information - https://redis.io/commands/ts.info/
|
||||
func (c cmdable) TSInfoWithArgs(ctx context.Context, key string, options *TSInfoOptions) *MapStringInterfaceCmd {
|
||||
args := []interface{}{"TS.INFO", key}
|
||||
if options != nil {
|
||||
if options.Debug {
|
||||
args = append(args, "DEBUG")
|
||||
}
|
||||
}
|
||||
cmd := NewMapStringInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSMAdd - Adds multiple samples to multiple time-series keys.
|
||||
// For more information - https://redis.io/commands/ts.madd/
|
||||
func (c cmdable) TSMAdd(ctx context.Context, ktvSlices [][]interface{}) *IntSliceCmd {
|
||||
args := []interface{}{"TS.MADD"}
|
||||
for _, ktv := range ktvSlices {
|
||||
args = append(args, ktv...)
|
||||
}
|
||||
cmd := NewIntSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSQueryIndex - Returns all the keys matching the filter expression.
|
||||
// For more information - https://redis.io/commands/ts.queryindex/
|
||||
func (c cmdable) TSQueryIndex(ctx context.Context, filterExpr []string) *StringSliceCmd {
|
||||
args := []interface{}{"TS.QUERYINDEX"}
|
||||
for _, f := range filterExpr {
|
||||
args = append(args, f)
|
||||
}
|
||||
cmd := NewStringSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSRevRange - Returns a range of samples from a time-series key in reverse order.
|
||||
// For more information - https://redis.io/commands/ts.revrange/
|
||||
func (c cmdable) TSRevRange(ctx context.Context, key string, fromTimestamp int, toTimestamp int) *TSTimestampValueSliceCmd {
|
||||
args := []interface{}{"TS.REVRANGE", key, fromTimestamp, toTimestamp}
|
||||
cmd := newTSTimestampValueSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSRevRangeWithArgs - Returns a range of samples from a time-series key in reverse order with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Latest, FilterByTS, FilterByValue, Count, Align, Aggregator,
|
||||
// BucketDuration, BucketTimestamp and Empty.
|
||||
// For more information - https://redis.io/commands/ts.revrange/
|
||||
func (c cmdable) TSRevRangeWithArgs(ctx context.Context, key string, fromTimestamp int, toTimestamp int, options *TSRevRangeOptions) *TSTimestampValueSliceCmd {
|
||||
args := []interface{}{"TS.REVRANGE", key, fromTimestamp, toTimestamp}
|
||||
if options != nil {
|
||||
if options.Latest {
|
||||
args = append(args, "LATEST")
|
||||
}
|
||||
if options.FilterByTS != nil {
|
||||
args = append(args, "FILTER_BY_TS")
|
||||
for _, f := range options.FilterByTS {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.FilterByValue != nil {
|
||||
args = append(args, "FILTER_BY_VALUE")
|
||||
for _, f := range options.FilterByValue {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.Count != 0 {
|
||||
args = append(args, "COUNT", options.Count)
|
||||
}
|
||||
if options.Align != nil {
|
||||
args = append(args, "ALIGN", options.Align)
|
||||
}
|
||||
if options.Aggregator != 0 {
|
||||
args = append(args, "AGGREGATION", options.Aggregator.String())
|
||||
}
|
||||
if options.BucketDuration != 0 {
|
||||
args = append(args, options.BucketDuration)
|
||||
}
|
||||
if options.BucketTimestamp != nil {
|
||||
args = append(args, "BUCKETTIMESTAMP", options.BucketTimestamp)
|
||||
}
|
||||
if options.Empty {
|
||||
args = append(args, "EMPTY")
|
||||
}
|
||||
}
|
||||
cmd := newTSTimestampValueSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSRange - Returns a range of samples from a time-series key.
|
||||
// For more information - https://redis.io/commands/ts.range/
|
||||
func (c cmdable) TSRange(ctx context.Context, key string, fromTimestamp int, toTimestamp int) *TSTimestampValueSliceCmd {
|
||||
args := []interface{}{"TS.RANGE", key, fromTimestamp, toTimestamp}
|
||||
cmd := newTSTimestampValueSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSRangeWithArgs - Returns a range of samples from a time-series key with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Latest, FilterByTS, FilterByValue, Count, Align, Aggregator,
|
||||
// BucketDuration, BucketTimestamp and Empty.
|
||||
// For more information - https://redis.io/commands/ts.range/
|
||||
func (c cmdable) TSRangeWithArgs(ctx context.Context, key string, fromTimestamp int, toTimestamp int, options *TSRangeOptions) *TSTimestampValueSliceCmd {
|
||||
args := []interface{}{"TS.RANGE", key, fromTimestamp, toTimestamp}
|
||||
if options != nil {
|
||||
if options.Latest {
|
||||
args = append(args, "LATEST")
|
||||
}
|
||||
if options.FilterByTS != nil {
|
||||
args = append(args, "FILTER_BY_TS")
|
||||
for _, f := range options.FilterByTS {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.FilterByValue != nil {
|
||||
args = append(args, "FILTER_BY_VALUE")
|
||||
for _, f := range options.FilterByValue {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.Count != 0 {
|
||||
args = append(args, "COUNT", options.Count)
|
||||
}
|
||||
if options.Align != nil {
|
||||
args = append(args, "ALIGN", options.Align)
|
||||
}
|
||||
if options.Aggregator != 0 {
|
||||
args = append(args, "AGGREGATION", options.Aggregator.String())
|
||||
}
|
||||
if options.BucketDuration != 0 {
|
||||
args = append(args, options.BucketDuration)
|
||||
}
|
||||
if options.BucketTimestamp != nil {
|
||||
args = append(args, "BUCKETTIMESTAMP", options.BucketTimestamp)
|
||||
}
|
||||
if options.Empty {
|
||||
args = append(args, "EMPTY")
|
||||
}
|
||||
}
|
||||
cmd := newTSTimestampValueSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type TSTimestampValueSliceCmd struct {
|
||||
baseCmd
|
||||
val []TSTimestampValue
|
||||
}
|
||||
|
||||
func newTSTimestampValueSliceCmd(ctx context.Context, args ...interface{}) *TSTimestampValueSliceCmd {
|
||||
return &TSTimestampValueSliceCmd{
|
||||
baseCmd: baseCmd{
|
||||
ctx: ctx,
|
||||
args: args,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueSliceCmd) String() string {
|
||||
return cmdString(cmd, cmd.val)
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueSliceCmd) SetVal(val []TSTimestampValue) {
|
||||
cmd.val = val
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueSliceCmd) Result() ([]TSTimestampValue, error) {
|
||||
return cmd.val, cmd.err
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueSliceCmd) Val() []TSTimestampValue {
|
||||
return cmd.val
|
||||
}
|
||||
|
||||
func (cmd *TSTimestampValueSliceCmd) readReply(rd *proto.Reader) (err error) {
|
||||
n, err := rd.ReadArrayLen()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val = make([]TSTimestampValue, n)
|
||||
for i := 0; i < n; i++ {
|
||||
_, _ = rd.ReadArrayLen()
|
||||
timestamp, err := rd.ReadInt()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value, err := rd.ReadString()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cmd.val[i].Timestamp = timestamp
|
||||
cmd.val[i].Value, err = strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// TSMRange - Returns a range of samples from multiple time-series keys.
|
||||
// For more information - https://redis.io/commands/ts.mrange/
|
||||
func (c cmdable) TSMRange(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string) *MapStringSliceInterfaceCmd {
|
||||
args := []interface{}{"TS.MRANGE", fromTimestamp, toTimestamp, "FILTER"}
|
||||
for _, f := range filterExpr {
|
||||
args = append(args, f)
|
||||
}
|
||||
cmd := NewMapStringSliceInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSMRangeWithArgs - Returns a range of samples from multiple time-series keys with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Latest, FilterByTS, FilterByValue, WithLabels, SelectedLabels,
|
||||
// Count, Align, Aggregator, BucketDuration, BucketTimestamp,
|
||||
// Empty, GroupByLabel and Reducer.
|
||||
// For more information - https://redis.io/commands/ts.mrange/
|
||||
func (c cmdable) TSMRangeWithArgs(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string, options *TSMRangeOptions) *MapStringSliceInterfaceCmd {
|
||||
args := []interface{}{"TS.MRANGE", fromTimestamp, toTimestamp}
|
||||
if options != nil {
|
||||
if options.Latest {
|
||||
args = append(args, "LATEST")
|
||||
}
|
||||
if options.FilterByTS != nil {
|
||||
args = append(args, "FILTER_BY_TS")
|
||||
for _, f := range options.FilterByTS {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.FilterByValue != nil {
|
||||
args = append(args, "FILTER_BY_VALUE")
|
||||
for _, f := range options.FilterByValue {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.WithLabels {
|
||||
args = append(args, "WITHLABELS")
|
||||
}
|
||||
if options.SelectedLabels != nil {
|
||||
args = append(args, "SELECTED_LABELS")
|
||||
args = append(args, options.SelectedLabels...)
|
||||
}
|
||||
if options.Count != 0 {
|
||||
args = append(args, "COUNT", options.Count)
|
||||
}
|
||||
if options.Align != nil {
|
||||
args = append(args, "ALIGN", options.Align)
|
||||
}
|
||||
if options.Aggregator != 0 {
|
||||
args = append(args, "AGGREGATION", options.Aggregator.String())
|
||||
}
|
||||
if options.BucketDuration != 0 {
|
||||
args = append(args, options.BucketDuration)
|
||||
}
|
||||
if options.BucketTimestamp != nil {
|
||||
args = append(args, "BUCKETTIMESTAMP", options.BucketTimestamp)
|
||||
}
|
||||
if options.Empty {
|
||||
args = append(args, "EMPTY")
|
||||
}
|
||||
}
|
||||
args = append(args, "FILTER")
|
||||
for _, f := range filterExpr {
|
||||
args = append(args, f)
|
||||
}
|
||||
if options != nil {
|
||||
if options.GroupByLabel != nil {
|
||||
args = append(args, "GROUPBY", options.GroupByLabel)
|
||||
}
|
||||
if options.Reducer != nil {
|
||||
args = append(args, "REDUCE", options.Reducer)
|
||||
}
|
||||
}
|
||||
cmd := NewMapStringSliceInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSMRevRange - Returns a range of samples from multiple time-series keys in reverse order.
|
||||
// For more information - https://redis.io/commands/ts.mrevrange/
|
||||
func (c cmdable) TSMRevRange(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string) *MapStringSliceInterfaceCmd {
|
||||
args := []interface{}{"TS.MREVRANGE", fromTimestamp, toTimestamp, "FILTER"}
|
||||
for _, f := range filterExpr {
|
||||
args = append(args, f)
|
||||
}
|
||||
cmd := NewMapStringSliceInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSMRevRangeWithArgs - Returns a range of samples from multiple time-series keys in reverse order with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Latest, FilterByTS, FilterByValue, WithLabels, SelectedLabels,
|
||||
// Count, Align, Aggregator, BucketDuration, BucketTimestamp,
|
||||
// Empty, GroupByLabel and Reducer.
|
||||
// For more information - https://redis.io/commands/ts.mrevrange/
|
||||
func (c cmdable) TSMRevRangeWithArgs(ctx context.Context, fromTimestamp int, toTimestamp int, filterExpr []string, options *TSMRevRangeOptions) *MapStringSliceInterfaceCmd {
|
||||
args := []interface{}{"TS.MREVRANGE", fromTimestamp, toTimestamp}
|
||||
if options != nil {
|
||||
if options.Latest {
|
||||
args = append(args, "LATEST")
|
||||
}
|
||||
if options.FilterByTS != nil {
|
||||
args = append(args, "FILTER_BY_TS")
|
||||
for _, f := range options.FilterByTS {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.FilterByValue != nil {
|
||||
args = append(args, "FILTER_BY_VALUE")
|
||||
for _, f := range options.FilterByValue {
|
||||
args = append(args, f)
|
||||
}
|
||||
}
|
||||
if options.WithLabels {
|
||||
args = append(args, "WITHLABELS")
|
||||
}
|
||||
if options.SelectedLabels != nil {
|
||||
args = append(args, "SELECTED_LABELS")
|
||||
args = append(args, options.SelectedLabels...)
|
||||
}
|
||||
if options.Count != 0 {
|
||||
args = append(args, "COUNT", options.Count)
|
||||
}
|
||||
if options.Align != nil {
|
||||
args = append(args, "ALIGN", options.Align)
|
||||
}
|
||||
if options.Aggregator != 0 {
|
||||
args = append(args, "AGGREGATION", options.Aggregator.String())
|
||||
}
|
||||
if options.BucketDuration != 0 {
|
||||
args = append(args, options.BucketDuration)
|
||||
}
|
||||
if options.BucketTimestamp != nil {
|
||||
args = append(args, "BUCKETTIMESTAMP", options.BucketTimestamp)
|
||||
}
|
||||
if options.Empty {
|
||||
args = append(args, "EMPTY")
|
||||
}
|
||||
}
|
||||
args = append(args, "FILTER")
|
||||
for _, f := range filterExpr {
|
||||
args = append(args, f)
|
||||
}
|
||||
if options != nil {
|
||||
if options.GroupByLabel != nil {
|
||||
args = append(args, "GROUPBY", options.GroupByLabel)
|
||||
}
|
||||
if options.Reducer != nil {
|
||||
args = append(args, "REDUCE", options.Reducer)
|
||||
}
|
||||
}
|
||||
cmd := NewMapStringSliceInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSMGet - Returns the last sample of multiple time-series keys.
|
||||
// For more information - https://redis.io/commands/ts.mget/
|
||||
func (c cmdable) TSMGet(ctx context.Context, filters []string) *MapStringSliceInterfaceCmd {
|
||||
args := []interface{}{"TS.MGET", "FILTER"}
|
||||
for _, f := range filters {
|
||||
args = append(args, f)
|
||||
}
|
||||
cmd := NewMapStringSliceInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// TSMGetWithArgs - Returns the last sample of multiple time-series keys with additional options.
|
||||
// This function allows for specifying additional options such as:
|
||||
// Latest, WithLabels and SelectedLabels.
|
||||
// For more information - https://redis.io/commands/ts.mget/
|
||||
func (c cmdable) TSMGetWithArgs(ctx context.Context, filters []string, options *TSMGetOptions) *MapStringSliceInterfaceCmd {
|
||||
args := []interface{}{"TS.MGET"}
|
||||
if options != nil {
|
||||
if options.Latest {
|
||||
args = append(args, "LATEST")
|
||||
}
|
||||
if options.WithLabels {
|
||||
args = append(args, "WITHLABELS")
|
||||
}
|
||||
if options.SelectedLabels != nil {
|
||||
args = append(args, "SELECTED_LABELS")
|
||||
args = append(args, options.SelectedLabels...)
|
||||
}
|
||||
}
|
||||
args = append(args, "FILTER")
|
||||
for _, f := range filters {
|
||||
args = append(args, f)
|
||||
}
|
||||
cmd := NewMapStringSliceInterfaceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -2,5 +2,5 @@ package redis
|
|||
|
||||
// Version is the current release version.
|
||||
func Version() string {
|
||||
return "9.1.0"
|
||||
return "9.2.1"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ github.com/prometheus/common/model
|
|||
github.com/prometheus/procfs
|
||||
github.com/prometheus/procfs/internal/fs
|
||||
github.com/prometheus/procfs/internal/util
|
||||
# github.com/redis/go-redis/v9 v9.1.0
|
||||
# github.com/redis/go-redis/v9 v9.2.1
|
||||
## explicit; go 1.18
|
||||
github.com/redis/go-redis/v9
|
||||
github.com/redis/go-redis/v9/internal
|
||||
|
|
|
|||
Loading…
Reference in New Issue