redis / rueidis

A fast Golang Redis client that supports Client Side Caching, Auto Pipelining, Generics OM, RedisJSON, RedisBloom, RediSearch, etc.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add DecodeSliceOfJSON to handle []Struct results easier

sgasho opened this issue · comments

(init idea: Add *RedisMessage.ScanSlice(dst any) to handle []Struct results easier)

When values of key1, key2 are both instances of X, code below returns an error of course because DecodeJSON handles only string

type X struct {
	Name string
}

xs := make([]*X, 0)
if err := redisClient.Do(ctx, s.redisClient.B().Mget().Key("key1", "key2").Build()).DecodeJSON(xs); err != nil {
    return err
}

I could not find any method to scan a slice of struct so I would like to add one, like "ScanSlice".
Scanning slice of struct in golang is not always easy so providing a scanning-slice method would be helpful.

some libraries, for example, sqlx.DB has a method "SelectContext" to scan a slice of struct and this is really helpful for us.

xs := make([]*X, 0)
if err := sqlx.DB.SelectContext(ctx, &xs, q, args...); err != nil { return err }

// -> xs = []&X{{Name: "name1"}, {Name: "name2"}, ....}

Hi @sgasho,

I know a ScanSlice could be helpful, but what it should do, and how it does that is too vague. It seems to carry too many different expectations. Every time I use things like sqlx.DB.SelectContext, I always wonder how will they meet my expectations and I sometimes find they don't.

I would prefer a much more clear API, for example a helper like this:

func DecodeSliceOfJSON[T any](resp rueidis.RedisResult, target *[]*T) error {
	arr, err := resp.ToArray()
	if err != nil {
		return err
	}
	xs := make([]*T, len(arr))
	for i, a := range arr {
		if err = a.DecodeJSON(xs[i]); err != nil && !rueidis.IsRedisNil(err) {
			return err
		}
	}
	*target = xs
	return nil
}

and you could use it like this

var xs []*X
err := DecodeSliceOfJSON(client.Do(context.Background(), client.B().Mget().Key("key1", "key2").Build()), &xs)

@rueian

It seems to carry too many different expectations. Every time I use things like sqlx.DB.SelectContext, I always wonder how will they meet my expectations and I sometimes find they don't.

I see, and I found that key-value store has a higher degree of freedom than relational databases, which could lead more complicated implementation.

In fact, SelectContext uses the reflect package to do some pretty complicated things. That's a lot of work to maintain.

I would prefer a much more clear API, for example a helper like this:

I like it. that is so simple and no need to use reflect package. adding some error patterns makes it perfect.

Thanks for sharing your idea!

Hi @sgasho, thank you for your contribution! This can be a very handy helper. Would you also like to add some examples to the README?

@rueian

thank you for your contribution! This can be a very handy helper.

thank you for the review!

Would you also like to add some examples to the README?

Sure, of course! I'm gonna explain with some examples and open another PR.