mirror of
https://github.com/redis/go-redis.git
synced 2025-07-28 06:42:00 +03:00
Merge branch 'master' into ndyakov/token-based-auth
This commit is contained in:
2
.github/actions/run-tests/action.yml
vendored
2
.github/actions/run-tests/action.yml
vendored
@ -25,7 +25,7 @@ runs:
|
|||||||
|
|
||||||
# Mapping of redis version to redis testing containers
|
# Mapping of redis version to redis testing containers
|
||||||
declare -A redis_version_mapping=(
|
declare -A redis_version_mapping=(
|
||||||
["8.0-RC1"]="8.0-RC1-pre"
|
["8.0-RC2"]="8.0-RC2-pre"
|
||||||
["7.4.2"]="rs-7.4.0-v2"
|
["7.4.2"]="rs-7.4.0-v2"
|
||||||
["7.2.7"]="rs-7.2.0-v14"
|
["7.2.7"]="rs-7.2.0-v14"
|
||||||
)
|
)
|
||||||
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@ -18,7 +18,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
redis-version:
|
redis-version:
|
||||||
- "8.0-RC1" # 8.0 RC1
|
- "8.0-RC2" # 8.0 RC2
|
||||||
- "7.4.2" # should use redis stack 7.4
|
- "7.4.2" # should use redis stack 7.4
|
||||||
go-version:
|
go-version:
|
||||||
- "1.23.x"
|
- "1.23.x"
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
|
|
||||||
# Mapping of redis version to redis testing containers
|
# Mapping of redis version to redis testing containers
|
||||||
declare -A redis_version_mapping=(
|
declare -A redis_version_mapping=(
|
||||||
["8.0-RC1"]="8.0-RC1-pre"
|
["8.0-RC2"]="8.0-RC2-pre"
|
||||||
["7.4.2"]="rs-7.4.0-v2"
|
["7.4.2"]="rs-7.4.0-v2"
|
||||||
)
|
)
|
||||||
if [[ -v redis_version_mapping[$REDIS_VERSION] ]]; then
|
if [[ -v redis_version_mapping[$REDIS_VERSION] ]]; then
|
||||||
@ -72,7 +72,7 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
redis-version:
|
redis-version:
|
||||||
- "8.0-RC1" # 8.0 RC1
|
- "8.0-RC2" # 8.0 RC2
|
||||||
- "7.4.2" # should use redis stack 7.4
|
- "7.4.2" # should use redis stack 7.4
|
||||||
- "7.2.7" # should redis stack 7.2
|
- "7.2.7" # should redis stack 7.2
|
||||||
go-version:
|
go-version:
|
||||||
|
4
.github/workflows/golangci-lint.yml
vendored
4
.github/workflows/golangci-lint.yml
vendored
@ -21,7 +21,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v6.5.2
|
uses: golangci/golangci-lint-action@v7.0.0
|
||||||
with:
|
with:
|
||||||
verify: false # disable verifying the configuration since golangci is currently introducing breaking changes in the configuration
|
verify: true
|
||||||
|
|
||||||
|
@ -1,3 +1,34 @@
|
|||||||
|
version: "2"
|
||||||
run:
|
run:
|
||||||
timeout: 5m
|
timeout: 5m
|
||||||
tests: false
|
tests: false
|
||||||
|
linters:
|
||||||
|
settings:
|
||||||
|
staticcheck:
|
||||||
|
checks:
|
||||||
|
- all
|
||||||
|
# Incorrect or missing package comment.
|
||||||
|
# https://staticcheck.dev/docs/checks/#ST1000
|
||||||
|
- -ST1000
|
||||||
|
# Omit embedded fields from selector expression.
|
||||||
|
# https://staticcheck.dev/docs/checks/#QF1008
|
||||||
|
- -QF1008
|
||||||
|
- -ST1003
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
presets:
|
||||||
|
- comments
|
||||||
|
- common-false-positives
|
||||||
|
- legacy
|
||||||
|
- std-error-handling
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
formatters:
|
||||||
|
exclusions:
|
||||||
|
generated: lax
|
||||||
|
paths:
|
||||||
|
- third_party$
|
||||||
|
- builtin$
|
||||||
|
- examples$
|
||||||
|
@ -1412,7 +1412,8 @@ func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
|
|||||||
|
|
||||||
cmd.val = make(map[string][]interface{})
|
cmd.val = make(map[string][]interface{})
|
||||||
|
|
||||||
if readType == proto.RespMap {
|
switch readType {
|
||||||
|
case proto.RespMap:
|
||||||
n, err := rd.ReadMapLen()
|
n, err := rd.ReadMapLen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -1435,7 +1436,7 @@ func (cmd *MapStringSliceInterfaceCmd) readReply(rd *proto.Reader) (err error) {
|
|||||||
cmd.val[k][j] = value
|
cmd.val[k][j] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if readType == proto.RespArray {
|
case proto.RespArray:
|
||||||
// RESP2 response
|
// RESP2 response
|
||||||
n, err := rd.ReadArrayLen()
|
n, err := rd.ReadArrayLen()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -155,6 +155,12 @@ func isEmptyValue(v reflect.Value) bool {
|
|||||||
return v.Float() == 0
|
return v.Float() == 0
|
||||||
case reflect.Interface, reflect.Pointer:
|
case reflect.Interface, reflect.Pointer:
|
||||||
return v.IsNil()
|
return v.IsNil()
|
||||||
|
case reflect.Struct:
|
||||||
|
if v.Type() == reflect.TypeOf(time.Time{}) {
|
||||||
|
return v.IsZero()
|
||||||
|
}
|
||||||
|
// Only supports the struct time.Time,
|
||||||
|
// subsequent iterations will follow the func Scan support decoder.
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -2578,6 +2578,63 @@ var _ = Describe("Commands", func() {
|
|||||||
"val2",
|
"val2",
|
||||||
"val",
|
"val",
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
type setOmitEmpty struct {
|
||||||
|
Set1 string `redis:"set1"`
|
||||||
|
Set2 int `redis:"set2,omitempty"`
|
||||||
|
Set3 time.Duration `redis:"set3,omitempty"`
|
||||||
|
Set4 string `redis:"set4,omitempty"`
|
||||||
|
Set5 time.Time `redis:"set5,omitempty"`
|
||||||
|
Set6 *numberStruct `redis:"set6,omitempty"`
|
||||||
|
Set7 numberStruct `redis:"set7,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
hSet = client.HSet(ctx, "hash3", &setOmitEmpty{
|
||||||
|
Set1: "val",
|
||||||
|
})
|
||||||
|
Expect(hSet.Err()).NotTo(HaveOccurred())
|
||||||
|
// both set1 and set7 are set
|
||||||
|
// custom struct is not omitted
|
||||||
|
Expect(hSet.Val()).To(Equal(int64(2)))
|
||||||
|
|
||||||
|
hGetAll := client.HGetAll(ctx, "hash3")
|
||||||
|
Expect(hGetAll.Err()).NotTo(HaveOccurred())
|
||||||
|
Expect(hGetAll.Val()).To(Equal(map[string]string{
|
||||||
|
"set1": "val",
|
||||||
|
"set7": `{"Number":0}`,
|
||||||
|
}))
|
||||||
|
var hash3 setOmitEmpty
|
||||||
|
Expect(hGetAll.Scan(&hash3)).NotTo(HaveOccurred())
|
||||||
|
Expect(hash3.Set1).To(Equal("val"))
|
||||||
|
Expect(hash3.Set2).To(Equal(0))
|
||||||
|
Expect(hash3.Set3).To(Equal(time.Duration(0)))
|
||||||
|
Expect(hash3.Set4).To(Equal(""))
|
||||||
|
Expect(hash3.Set5).To(Equal(time.Time{}))
|
||||||
|
Expect(hash3.Set6).To(BeNil())
|
||||||
|
Expect(hash3.Set7).To(Equal(numberStruct{}))
|
||||||
|
|
||||||
|
now := time.Now()
|
||||||
|
hSet = client.HSet(ctx, "hash4", setOmitEmpty{
|
||||||
|
Set1: "val",
|
||||||
|
Set5: now,
|
||||||
|
Set6: &numberStruct{
|
||||||
|
Number: 5,
|
||||||
|
},
|
||||||
|
Set7: numberStruct{
|
||||||
|
Number: 3,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
Expect(hSet.Err()).NotTo(HaveOccurred())
|
||||||
|
Expect(hSet.Val()).To(Equal(int64(4)))
|
||||||
|
|
||||||
|
hGetAll = client.HGetAll(ctx, "hash4")
|
||||||
|
Expect(hGetAll.Err()).NotTo(HaveOccurred())
|
||||||
|
Expect(hGetAll.Val()).To(Equal(map[string]string{
|
||||||
|
"set1": "val",
|
||||||
|
"set5": now.Format(time.RFC3339Nano),
|
||||||
|
"set6": `{"Number":5}`,
|
||||||
|
"set7": `{"Number":3}`,
|
||||||
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should HSetNX", func() {
|
It("should HSetNX", func() {
|
||||||
@ -7619,12 +7676,16 @@ type numberStruct struct {
|
|||||||
Number int
|
Number int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *numberStruct) MarshalBinary() ([]byte, error) {
|
func (n numberStruct) MarshalBinary() ([]byte, error) {
|
||||||
return json.Marshal(s)
|
return json.Marshal(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *numberStruct) UnmarshalBinary(b []byte) error {
|
func (n *numberStruct) UnmarshalBinary(b []byte) error {
|
||||||
return json.Unmarshal(b, s)
|
return json.Unmarshal(b, n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *numberStruct) ScanRedis(str string) error {
|
||||||
|
return json.Unmarshal([]byte(str), n)
|
||||||
}
|
}
|
||||||
|
|
||||||
func deref(viface interface{}) interface{} {
|
func deref(viface interface{}) interface{} {
|
||||||
|
@ -19,6 +19,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
retract (
|
retract (
|
||||||
v9.5.3 // This version was accidentally released.
|
|
||||||
v9.7.2 // This version was accidentally released.
|
v9.7.2 // This version was accidentally released.
|
||||||
|
v9.5.3 // This version was accidentally released.
|
||||||
)
|
)
|
||||||
|
@ -16,6 +16,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
retract (
|
retract (
|
||||||
v9.5.3 // This version was accidentally released.
|
|
||||||
v9.7.2 // This version was accidentally released.
|
v9.7.2 // This version was accidentally released.
|
||||||
|
v9.5.3 // This version was accidentally released.
|
||||||
)
|
)
|
||||||
|
@ -24,6 +24,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
retract (
|
retract (
|
||||||
v9.5.3 // This version was accidentally released.
|
|
||||||
v9.7.2 // This version was accidentally released.
|
v9.7.2 // This version was accidentally released.
|
||||||
|
v9.5.3 // This version was accidentally released.
|
||||||
)
|
)
|
||||||
|
@ -23,6 +23,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
retract (
|
retract (
|
||||||
v9.5.3 // This version was accidentally released.
|
|
||||||
v9.7.2 // This version was accidentally released.
|
v9.7.2 // This version was accidentally released.
|
||||||
|
v9.5.3 // This version was accidentally released.
|
||||||
)
|
)
|
||||||
|
@ -265,9 +265,10 @@ func (opt *Options) init() {
|
|||||||
opt.ConnMaxIdleTime = 30 * time.Minute
|
opt.ConnMaxIdleTime = 30 * time.Minute
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.MaxRetries == -1 {
|
switch opt.MaxRetries {
|
||||||
|
case -1:
|
||||||
opt.MaxRetries = 0
|
opt.MaxRetries = 0
|
||||||
} else if opt.MaxRetries == 0 {
|
case 0:
|
||||||
opt.MaxRetries = 3
|
opt.MaxRetries = 3
|
||||||
}
|
}
|
||||||
switch opt.MinRetryBackoff {
|
switch opt.MinRetryBackoff {
|
||||||
|
@ -113,9 +113,10 @@ type ClusterOptions struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (opt *ClusterOptions) init() {
|
func (opt *ClusterOptions) init() {
|
||||||
if opt.MaxRedirects == -1 {
|
switch opt.MaxRedirects {
|
||||||
|
case -1:
|
||||||
opt.MaxRedirects = 0
|
opt.MaxRedirects = 0
|
||||||
} else if opt.MaxRedirects == 0 {
|
case 0:
|
||||||
opt.MaxRedirects = 3
|
opt.MaxRedirects = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,9 @@ func (c *PubSub) init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *PubSub) String() string {
|
func (c *PubSub) String() string {
|
||||||
|
c.mu.Lock()
|
||||||
|
defer c.mu.Unlock()
|
||||||
|
|
||||||
channels := mapKeys(c.channels)
|
channels := mapKeys(c.channels)
|
||||||
channels = append(channels, mapKeys(c.patterns)...)
|
channels = append(channels, mapKeys(c.patterns)...)
|
||||||
channels = append(channels, mapKeys(c.schannels)...)
|
channels = append(channels, mapKeys(c.schannels)...)
|
||||||
|
5
ring.go
5
ring.go
@ -128,9 +128,10 @@ func (opt *RingOptions) init() {
|
|||||||
opt.NewConsistentHash = newRendezvous
|
opt.NewConsistentHash = newRendezvous
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.MaxRetries == -1 {
|
switch opt.MaxRetries {
|
||||||
|
case -1:
|
||||||
opt.MaxRetries = 0
|
opt.MaxRetries = 0
|
||||||
} else if opt.MaxRetries == 0 {
|
case 0:
|
||||||
opt.MaxRetries = 3
|
opt.MaxRetries = 3
|
||||||
}
|
}
|
||||||
switch opt.MinRetryBackoff {
|
switch opt.MinRetryBackoff {
|
||||||
|
@ -269,12 +269,22 @@ var _ = Describe("RedisTimeseries commands", Label("timeseries"), func() {
|
|||||||
if client.Options().Protocol == 2 {
|
if client.Options().Protocol == 2 {
|
||||||
Expect(resultInfo["labels"].([]interface{})[0]).To(BeEquivalentTo([]interface{}{"Time", "Series"}))
|
Expect(resultInfo["labels"].([]interface{})[0]).To(BeEquivalentTo([]interface{}{"Time", "Series"}))
|
||||||
Expect(resultInfo["retentionTime"]).To(BeEquivalentTo(10))
|
Expect(resultInfo["retentionTime"]).To(BeEquivalentTo(10))
|
||||||
|
if RedisVersion >= 8 {
|
||||||
|
Expect(resultInfo["duplicatePolicy"]).To(BeEquivalentTo("block"))
|
||||||
|
} else {
|
||||||
|
// Older versions of Redis had a bug where the duplicate policy was not set correctly
|
||||||
Expect(resultInfo["duplicatePolicy"]).To(BeEquivalentTo(redis.Nil))
|
Expect(resultInfo["duplicatePolicy"]).To(BeEquivalentTo(redis.Nil))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Expect(resultInfo["labels"].(map[interface{}]interface{})["Time"]).To(BeEquivalentTo("Series"))
|
Expect(resultInfo["labels"].(map[interface{}]interface{})["Time"]).To(BeEquivalentTo("Series"))
|
||||||
Expect(resultInfo["retentionTime"]).To(BeEquivalentTo(10))
|
Expect(resultInfo["retentionTime"]).To(BeEquivalentTo(10))
|
||||||
|
if RedisVersion >= 8 {
|
||||||
|
Expect(resultInfo["duplicatePolicy"]).To(BeEquivalentTo("block"))
|
||||||
|
} else {
|
||||||
|
// Older versions of Redis had a bug where the duplicate policy was not set correctly
|
||||||
Expect(resultInfo["duplicatePolicy"]).To(BeEquivalentTo(redis.Nil))
|
Expect(resultInfo["duplicatePolicy"]).To(BeEquivalentTo(redis.Nil))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
opt = &redis.TSAlterOptions{DuplicatePolicy: "min"}
|
opt = &redis.TSAlterOptions{DuplicatePolicy: "min"}
|
||||||
resultAlter, err = client.TSAlter(ctx, "1", opt).Result()
|
resultAlter, err = client.TSAlter(ctx, "1", opt).Result()
|
||||||
Expect(err).NotTo(HaveOccurred())
|
Expect(err).NotTo(HaveOccurred())
|
||||||
|
Reference in New Issue
Block a user