Skip to content

Commit e37a798

Browse files
authored
Merge branch 'master' into master
2 parents a5be5af + bb8d508 commit e37a798

File tree

8 files changed

+265
-16
lines changed

8 files changed

+265
-16
lines changed

CONTRIBUTING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,7 @@ The core team regularly looks at pull requests. We will provide
112112
feedback as soon as possible. After receiving our feedback, please respond
113113
within two weeks. After that time, we may close your PR if it isn't
114114
showing any activity.
115+
116+
## Support
117+
118+
Maintainers can provide limited support to contributors on discord: https://discord.gg/W4txy5AeKM

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@
33
[![build workflow](https://github.com/redis/go-redis/actions/workflows/build.yml/badge.svg)](https://github.com/redis/go-redis/actions)
44
[![PkgGoDev](https://pkg.go.dev/badge/github.com/redis/go-redis/v9)](https://pkg.go.dev/github.com/redis/go-redis/v9?tab=doc)
55
[![Documentation](https://img.shields.io/badge/redis-documentation-informational)](https://redis.uptrace.dev/)
6+
[![Go Report Card](https://goreportcard.com/badge/github.com/redis/go-redis/v9)](https://goreportcard.com/report/github.com/redis/go-redis/v9)
67
[![codecov](https://codecov.io/github/redis/go-redis/graph/badge.svg?token=tsrCZKuSSw)](https://codecov.io/github/redis/go-redis)
7-
[![Chat](https://discordapp.com/api/guilds/752070105847955518/widget.png)](https://discord.gg/rWtp5Aj)
8+
9+
[![Discord](https://img.shields.io/discord/697882427875393627.svg?style=social&logo=discord)](https://discord.gg/W4txy5AeKM)
10+
[![Twitch](https://img.shields.io/twitch/status/redisinc?style=social)](https://www.twitch.tv/redisinc)
11+
[![YouTube](https://img.shields.io/youtube/channel/views/UCD78lHSwYqMlyetR0_P4Vig?style=social)](https://www.youtube.com/redisinc)
12+
[![Twitter](https://img.shields.io/twitter/follow/redisinc?style=social)](https://twitter.com/redisinc)
13+
[![Stack Exchange questions](https://img.shields.io/stackexchange/stackoverflow/t/go-redis?style=social&logo=stackoverflow&label=Stackoverflow)](https://stackoverflow.com/questions/tagged/go-redis)
814

915
> go-redis is the official Redis client library for the Go programming language. It offers a straightforward interface for interacting with Redis servers.
1016
@@ -44,7 +50,7 @@ in the `go.mod` to `go 1.24` in one of the next releases.
4450
## Resources
4551

4652
- [Discussions](https://github.com/redis/go-redis/discussions)
47-
- [Chat](https://discord.gg/rWtp5Aj)
53+
- [Chat](https://discord.gg/W4txy5AeKM)
4854
- [Reference](https://pkg.go.dev/github.com/redis/go-redis/v9)
4955
- [Examples](https://pkg.go.dev/github.com/redis/go-redis/v9#pkg-examples)
5056

command.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3831,7 +3831,8 @@ func (cmd *MapStringStringSliceCmd) readReply(rd *proto.Reader) error {
38313831
}
38323832

38333833
// -----------------------------------------------------------------------
3834-
// MapStringInterfaceCmd represents a command that returns a map of strings to interface{}.
3834+
3835+
// MapMapStringInterfaceCmd represents a command that returns a map of strings to interface{}.
38353836
type MapMapStringInterfaceCmd struct {
38363837
baseCmd
38373838
val map[string]interface{}

commands.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,8 @@ func appendArg(dst []interface{}, arg interface{}) []interface{} {
8181
return dst
8282
case time.Time, time.Duration, encoding.BinaryMarshaler, net.IP:
8383
return append(dst, arg)
84+
case nil:
85+
return dst
8486
default:
8587
// scan struct field
8688
v := reflect.ValueOf(arg)
@@ -153,6 +155,12 @@ func isEmptyValue(v reflect.Value) bool {
153155
return v.Float() == 0
154156
case reflect.Interface, reflect.Pointer:
155157
return v.IsNil()
158+
case reflect.Struct:
159+
if v.Type() == reflect.TypeOf(time.Time{}) {
160+
return v.IsZero()
161+
}
162+
// Only supports the struct time.Time,
163+
// subsequent iterations will follow the func Scan support decoder.
156164
}
157165
return false
158166
}
@@ -330,7 +338,7 @@ func (info LibraryInfo) Validate() error {
330338
return nil
331339
}
332340

333-
// Hello Set the resp protocol used.
341+
// Hello sets the resp protocol used.
334342
func (c statefulCmdable) Hello(ctx context.Context,
335343
ver int, username, password, clientName string,
336344
) *MapStringInterfaceCmd {

commands_test.go

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2578,6 +2578,63 @@ var _ = Describe("Commands", func() {
25782578
"val2",
25792579
"val",
25802580
}))
2581+
2582+
type setOmitEmpty struct {
2583+
Set1 string `redis:"set1"`
2584+
Set2 int `redis:"set2,omitempty"`
2585+
Set3 time.Duration `redis:"set3,omitempty"`
2586+
Set4 string `redis:"set4,omitempty"`
2587+
Set5 time.Time `redis:"set5,omitempty"`
2588+
Set6 *numberStruct `redis:"set6,omitempty"`
2589+
Set7 numberStruct `redis:"set7,omitempty"`
2590+
}
2591+
2592+
hSet = client.HSet(ctx, "hash3", &setOmitEmpty{
2593+
Set1: "val",
2594+
})
2595+
Expect(hSet.Err()).NotTo(HaveOccurred())
2596+
// both set1 and set7 are set
2597+
// custom struct is not omitted
2598+
Expect(hSet.Val()).To(Equal(int64(2)))
2599+
2600+
hGetAll := client.HGetAll(ctx, "hash3")
2601+
Expect(hGetAll.Err()).NotTo(HaveOccurred())
2602+
Expect(hGetAll.Val()).To(Equal(map[string]string{
2603+
"set1": "val",
2604+
"set7": `{"Number":0}`,
2605+
}))
2606+
var hash3 setOmitEmpty
2607+
Expect(hGetAll.Scan(&hash3)).NotTo(HaveOccurred())
2608+
Expect(hash3.Set1).To(Equal("val"))
2609+
Expect(hash3.Set2).To(Equal(0))
2610+
Expect(hash3.Set3).To(Equal(time.Duration(0)))
2611+
Expect(hash3.Set4).To(Equal(""))
2612+
Expect(hash3.Set5).To(Equal(time.Time{}))
2613+
Expect(hash3.Set6).To(BeNil())
2614+
Expect(hash3.Set7).To(Equal(numberStruct{}))
2615+
2616+
now := time.Now()
2617+
hSet = client.HSet(ctx, "hash4", setOmitEmpty{
2618+
Set1: "val",
2619+
Set5: now,
2620+
Set6: &numberStruct{
2621+
Number: 5,
2622+
},
2623+
Set7: numberStruct{
2624+
Number: 3,
2625+
},
2626+
})
2627+
Expect(hSet.Err()).NotTo(HaveOccurred())
2628+
Expect(hSet.Val()).To(Equal(int64(4)))
2629+
2630+
hGetAll = client.HGetAll(ctx, "hash4")
2631+
Expect(hGetAll.Err()).NotTo(HaveOccurred())
2632+
Expect(hGetAll.Val()).To(Equal(map[string]string{
2633+
"set1": "val",
2634+
"set5": now.Format(time.RFC3339Nano),
2635+
"set6": `{"Number":5}`,
2636+
"set7": `{"Number":3}`,
2637+
}))
25812638
})
25822639

25832640
It("should HSetNX", func() {
@@ -7209,6 +7266,17 @@ var _ = Describe("Commands", func() {
72097266
Expect(err).NotTo(HaveOccurred())
72107267
Expect(vals).To(Equal([]interface{}{int64(12), proto.RedisError("error"), "abc"}))
72117268
})
7269+
7270+
It("returns empty values when args are nil", func() {
7271+
vals, err := client.Eval(
7272+
ctx,
7273+
"return {ARGV[1]}",
7274+
[]string{},
7275+
nil,
7276+
).Result()
7277+
Expect(err).NotTo(HaveOccurred())
7278+
Expect(vals).To(BeEmpty())
7279+
})
72127280
})
72137281

72147282
Describe("EvalRO", func() {
@@ -7232,6 +7300,17 @@ var _ = Describe("Commands", func() {
72327300
Expect(err).NotTo(HaveOccurred())
72337301
Expect(vals).To(Equal([]interface{}{int64(12), proto.RedisError("error"), "abc"}))
72347302
})
7303+
7304+
It("returns empty values when args are nil", func() {
7305+
vals, err := client.EvalRO(
7306+
ctx,
7307+
"return {ARGV[1]}",
7308+
[]string{},
7309+
nil,
7310+
).Result()
7311+
Expect(err).NotTo(HaveOccurred())
7312+
Expect(vals).To(BeEmpty())
7313+
})
72357314
})
72367315

72377316
Describe("Functions", func() {
@@ -7597,12 +7676,16 @@ type numberStruct struct {
75977676
Number int
75987677
}
75997678

7600-
func (s *numberStruct) MarshalBinary() ([]byte, error) {
7601-
return json.Marshal(s)
7679+
func (n numberStruct) MarshalBinary() ([]byte, error) {
7680+
return json.Marshal(n)
7681+
}
7682+
7683+
func (n *numberStruct) UnmarshalBinary(b []byte) error {
7684+
return json.Unmarshal(b, n)
76027685
}
76037686

7604-
func (s *numberStruct) UnmarshalBinary(b []byte) error {
7605-
return json.Unmarshal(b, s)
7687+
func (n *numberStruct) ScanRedis(str string) error {
7688+
return json.Unmarshal([]byte(str), n)
76067689
}
76077690

76087691
func deref(viface interface{}) interface{} {

doctests/home_json_example_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,107 @@ func ExampleClient_search_json() {
227227
// London - 1
228228
// Tel Aviv - 2
229229
}
230+
231+
func ExampleClient_search_hash() {
232+
ctx := context.Background()
233+
234+
rdb := redis.NewClient(&redis.Options{
235+
Addr: "localhost:6379",
236+
Password: "", // no password docs
237+
DB: 0, // use default DB
238+
Protocol: 2,
239+
})
240+
241+
// REMOVE_START
242+
rdb.Del(ctx, "huser:1", "huser:2", "huser:3")
243+
rdb.FTDropIndex(ctx, "hash-idx:users")
244+
// REMOVE_END
245+
246+
// STEP_START make_hash_index
247+
_, err := rdb.FTCreate(
248+
ctx,
249+
"hash-idx:users",
250+
// Options:
251+
&redis.FTCreateOptions{
252+
OnHash: true,
253+
Prefix: []interface{}{"huser:"},
254+
},
255+
// Index schema fields:
256+
&redis.FieldSchema{
257+
FieldName: "name",
258+
FieldType: redis.SearchFieldTypeText,
259+
},
260+
&redis.FieldSchema{
261+
FieldName: "city",
262+
FieldType: redis.SearchFieldTypeTag,
263+
},
264+
&redis.FieldSchema{
265+
FieldName: "age",
266+
FieldType: redis.SearchFieldTypeNumeric,
267+
},
268+
).Result()
269+
270+
if err != nil {
271+
panic(err)
272+
}
273+
// STEP_END
274+
275+
user1 := map[string]interface{}{
276+
"name": "Paul John",
277+
"email": "[email protected]",
278+
"age": 42,
279+
"city": "London",
280+
}
281+
282+
user2 := map[string]interface{}{
283+
"name": "Eden Zamir",
284+
"email": "[email protected]",
285+
"age": 29,
286+
"city": "Tel Aviv",
287+
}
288+
289+
user3 := map[string]interface{}{
290+
"name": "Paul Zamir",
291+
"email": "[email protected]",
292+
"age": 35,
293+
"city": "Tel Aviv",
294+
}
295+
296+
// STEP_START add_hash_data
297+
_, err = rdb.HSet(ctx, "huser:1", user1).Result()
298+
299+
if err != nil {
300+
panic(err)
301+
}
302+
303+
_, err = rdb.HSet(ctx, "huser:2", user2).Result()
304+
305+
if err != nil {
306+
panic(err)
307+
}
308+
309+
_, err = rdb.HSet(ctx, "huser:3", user3).Result()
310+
311+
if err != nil {
312+
panic(err)
313+
}
314+
// STEP_END
315+
316+
// STEP_START query1_hash
317+
findPaulHashResult, err := rdb.FTSearch(
318+
ctx,
319+
"hash-idx:users",
320+
"Paul @age:[30 40]",
321+
).Result()
322+
323+
if err != nil {
324+
panic(err)
325+
}
326+
327+
fmt.Println(findPaulHashResult)
328+
// >>> {1 [{huser:3 <nil> <nil> <nil> map[age:35 city:Tel Aviv...
329+
// STEP_END
330+
331+
// Output:
332+
// {1 [{huser:3 <nil> <nil> <nil> map[age:35 city:Tel Aviv email:[email protected] name:Paul Zamir]}]}
333+
}

0 commit comments

Comments
 (0)