package core import ( "context" "encoding/json" "fmt" "strings" "github.com/go-redis/redis/v8" ) 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) JSONMSet(key string, kv map[string]any) error { 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, path, fmt.Sprintf("'%s'", string(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) JSONSet(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, fmt.Sprintf("'%s'", string(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) 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, fmt.Sprintf("'%s'", string(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) } return respToArray[int64](rh.Do(rh.ctx, args...).Result()) } 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() }