From 256bfd030c294d2d7bea4ca2c3082f2d49ae9aef Mon Sep 17 00:00:00 2001 From: mountain Date: Wed, 19 Jul 2023 09:31:01 +0900 Subject: [PATCH] =?UTF-8?q?redison=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- redis.go | 386 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 386 insertions(+) diff --git a/redis.go b/redis.go index 7b16f2a..de68d70 100644 --- a/redis.go +++ b/redis.go @@ -2,8 +2,11 @@ package gocommon import ( "context" + "encoding/json" + "fmt" "os" "strconv" + "strings" "github.com/go-redis/redis/v8" ) @@ -62,3 +65,386 @@ func NewRedisClient(uri string) (*redis.Client, error) { option.DB += newidx return redis.NewClient(option), nil } + +type SetOption = string +type GetOption = [2]any + +const ( + // JSONSET command Options + SetOptionNX SetOption = "NX" + SetOptionXX SetOption = "XX" +) + +var ( + GetOptionSPACE = GetOption{"SPACE", " "} + GetOptionINDENT = GetOption{"INDENT", "\t"} + GetOptionNEWLINE = GetOption{"NEWLINE", "\n"} + GetOptionNOESCAPE = GetOption{"NOESCAPE", ""} +) + +// gocommon으로 옮길 거 +type RedisonHandler struct { + *redis.Client + ctx context.Context +} + +func NewRedisonHandler(ctx context.Context, redisClient *redis.Client) *RedisonHandler { + return &RedisonHandler{ + Client: redisClient, + ctx: ctx, + } +} + +func respToArray[T any](resp any, err error) ([]T, error) { + if err != nil { + return nil, err + } + + resArr := resp.([]any) + v := make([]T, len(resArr)) + for i, e := range resArr { + v[i] = e.(T) + } + return v, nil +} + +func appendArgs[T any](args []any, ext ...T) []any { + for _, e := range ext { + args = append(args, e) + } + return args +} + +func (rh *RedisonHandler) JSONMSetRel(key string, prefixPath string, kv map[string]any) error { + if len(prefixPath) > 0 && !strings.HasSuffix(prefixPath, ".") { + prefixPath += "." + } + + pl := rh.Pipeline() + for path, obj := range kv { + b, err := json.Marshal(obj) + if err != nil { + return err + } + pl.Do(rh.ctx, "JSON.SET", key, prefixPath+path, b) + } + + cmders, err := pl.Exec(rh.ctx) + if err != nil { + return err + } + + for _, cmder := range cmders { + if cmder.Err() != nil { + return cmder.Err() + } + } + return nil +} + +func (rh *RedisonHandler) JSONMSet(key string, kv map[string]any) error { + return rh.JSONMSetRel(key, "", kv) +} + +func (rh *RedisonHandler) jsonSetMergeJSONSet(cmd, key, path string, obj any, opts ...SetOption) (bool, error) { + b, err := json.Marshal(obj) + if err != nil { + return false, err + } + + args := []any{ + "JSON.SET", + key, + path, + b, + } + if len(opts) > 0 { + args = append(args, opts[0]) + } + + res, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return false, err + } + + return res.(string) == "OK", nil +} + +func (rh *RedisonHandler) JSONSet(key, path string, obj any, opts ...SetOption) (bool, error) { + return rh.jsonSetMergeJSONSet("JSON.SET", key, path, obj, opts...) +} + +func (rh *RedisonHandler) JSONMerge(key, path string, obj any, opts ...SetOption) (bool, error) { + return rh.jsonSetMergeJSONSet("JSON.MERGE", key, path, obj, opts...) +} + +func (rh *RedisonHandler) JSONGet(key, path string, opts ...GetOption) (res any, err error) { + args := appendArgs[string]([]any{ + "JSON.GET", + key, + }, strings.Split(path, " ")...) + + for _, opt := range opts { + args = append(args, opt[:]...) + } + + return rh.Do(rh.ctx, args...).Result() +} + +func (rh *RedisonHandler) JSONGetString(key, path string) ([]string, error) { + return respToArray[string](rh.JSONResp(key, path)) +} + +func (rh *RedisonHandler) JSONGetInt64(key, path string) ([]int64, error) { + return respToArray[int64](rh.JSONResp(key, path)) +} + +func (rh *RedisonHandler) JSONMGet(path string, keys ...string) (res any, err error) { + args := appendArgs[string]([]any{ + "JSON.MGET", + path, + }, keys...) + return rh.Do(rh.ctx, args...).Result() +} + +func (rh *RedisonHandler) JSONMDel(key string, paths []string) error { + pl := rh.Pipeline() + for _, path := range paths { + args := []any{ + "JSON.DEL", + key, + path, + } + pl.Do(rh.ctx, args...) + } + _, err := pl.Exec(rh.ctx) + return err +} + +func (rh *RedisonHandler) JSONDel(key, path string) (int64, error) { + args := []any{ + "JSON.DEL", + key, + path, + } + resp, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return 0, err + } + + return resp.(int64), nil +} + +func (rh *RedisonHandler) JSONType(key, path string) ([]string, error) { + args := []any{ + "JSON.TYPE", + key, + path, + } + return respToArray[string](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONNumIncrBy(key, path string, number int) ([]any, error) { + args := []any{ + "JSON.NUMINCRBY", + key, + path, + number, + } + resp, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return nil, err + } + + return resp.([]any), nil +} + +func (rh *RedisonHandler) JSONNumMultBy(key, path string, number int) (res any, err error) { + args := []any{ + "JSON.NUMMULTBY", + key, + path, + number, + } + resp, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return nil, err + } + + return resp.([]any), nil +} + +func (rh *RedisonHandler) JSONStrAppend(key, path string, jsonstring string) ([]int64, error) { + args := []any{ + "JSON.STRAPPEND", + key, + path, + fmt.Sprintf(`'"%s"'`, jsonstring), + } + return respToArray[int64](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONStrLen(key, path string) (res []int64, err error) { + args := []any{ + "JSON.STRLEN", + key, + path, + } + return respToArray[int64](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONArrAppend(key, path string, values ...any) (int64, error) { + args := []any{ + "JSON.ARRAPPEND", + key, + path, + } + resp, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return 0, err + } + + return resp.(int64), nil +} + +func (rh *RedisonHandler) JSONArrLen(key, path string) ([]int64, error) { + args := []any{ + "JSON.ARRLEN", + key, + path, + } + return respToArray[int64](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONArrPop(key, path string, index int) (res any, err error) { + args := []any{ + "JSON.ARRPOP", + key, + path, + index, + } + resp, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return nil, err + } + return resp.([]any)[0], nil +} + +func appendValues(args []any, values ...any) []any { + for _, jsonValue := range values { + switch jsonValue := jsonValue.(type) { + case string: + args = append(args, fmt.Sprintf(`'"%s"'`, jsonValue)) + case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: + args = append(args, jsonValue) + default: + bt, _ := json.Marshal(jsonValue) + args = append(args, bt) + } + } + return args +} + +func (rh *RedisonHandler) JSONArrIndex(key, path string, jsonValue any, optionalRange ...int) ([]int64, error) { + args := appendValues([]any{ + "JSON.ARRINDEX", + key, + path, + }, jsonValue) + + return respToArray[int64](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONArrTrim(key, path string, start, end int) (res any, err error) { + args := []any{ + "JSON.ARRTRIM", + key, + path, + start, + end, + } + return respToArray[int64](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONArrInsert(key, path string, index int, values ...any) (res any, err error) { + args := appendValues([]any{ + "JSON.ARRINSERT", + key, + path, + index, + }, values...) + + return respToArray[int64](rh.Do(rh.ctx, args...).Result()) +} + +func (rh *RedisonHandler) JSONObjKeys(key, path string) ([]string, error) { + args := []any{ + "JSON.OBJKEYS", + key, + path, + } + + res, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return nil, err + } + + resArr := res.([]any) + resArr = resArr[0].([]any) + slc := make([]string, len(resArr)) + + for i, r := range resArr { + slc[i] = r.(string) + } + + return slc, nil +} + +func (rh *RedisonHandler) JSONObjLen(key, path string) ([]int64, error) { + args := []any{ + "JSON.OBJLEN", + key, + } + + if path != "$" { + args = append(args, path) + } + + resp, err := rh.Do(rh.ctx, args...).Result() + if err != nil { + return nil, err + } + + switch resp := resp.(type) { + case []any: + return respToArray[int64](resp, nil) + + case int64: + return []int64{resp}, nil + } + + return []int64{0}, nil +} + +func (rh *RedisonHandler) JSONDebug(key, path string) (res any, err error) { + args := []any{ + "JSON.DEBUG", + "MEMORY", + key, + path, + } + return rh.Do(rh.ctx, args...).Result() +} + +func (rh *RedisonHandler) JSONForget(key, path string) (int64, error) { + return rh.JSONDel(key, path) +} + +func (rh *RedisonHandler) JSONResp(key, path string) (res any, err error) { + args := []any{ + "JSON.RESP", + key, + path, + } + return rh.Do(rh.ctx, args...).Result() +}