diff --git a/.travis.yml b/.travis.yml index 219b05c..bd11997 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ language: go go: - - 1.9.x - 1.10.x - - tip + - 1.11.x matrix: allow_failures: @@ -18,6 +17,7 @@ before_install: - docker ps -a - curl -L -s https://github.com/golang/dep/releases/download/v0.3.1/dep-linux-amd64 -o $GOPATH/bin/dep - chmod +x $GOPATH/bin/dep + - go get honnef.co/go/tools/cmd/staticcheck - go get golang.org/x/tools/cmd/cover - go get github.com/mattn/goveralls @@ -28,7 +28,8 @@ script: - go test -v . - go test -covermode=count -coverprofile=profile.cov . - go vet -x . + - staticcheck . after_script: - $HOME/gopath/bin/goveralls -coverprofile=profile.cov -service=travis-ci - + diff --git a/README.md b/README.md index e184c9a..1b3853c 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,11 @@ Go-ReJSON is a [Go](https://golang.org/) client for [rejson](https://github.com/ - [x] [JSON.ARRPOP](http://rejson.io/commands/#jsonarrpop) - [x] [JSON.ARRTRIM](http://rejson.io/commands/#jsonarrtrim) - [x] [JSON.ARRINSERT](http://rejson.io/commands/#jsonarrinsert) -- [ ] [JSON.OBJKEYS](http://rejson.io/commands/#jsonobjkeys) -- [ ] [JSON.OBJLEN](http://rejson.io/commands/#jsonobjlen) -- [ ] [JSON.DEBUG](http://rejson.io/commands/#jsondebug) -- [ ] [JSON.FORGET](http://rejson.io/commands/#jsonforget) -- [ ] [JSON.RESP](http://rejson.io/commands/#jsonresp) +- [x] [JSON.OBJKEYS](http://rejson.io/commands/#jsonobjkeys) +- [x] [JSON.OBJLEN](http://rejson.io/commands/#jsonobjlen) +- [x] [JSON.DEBUG](http://rejson.io/commands/#jsondebug) +- [x] [JSON.FORGET](http://rejson.io/commands/#jsonforget) +- [x] [JSON.RESP](http://rejson.io/commands/#jsonresp) ## Example usage ```golang diff --git a/examples/json_obj.go b/examples/json_obj.go new file mode 100644 index 0000000..649cd83 --- /dev/null +++ b/examples/json_obj.go @@ -0,0 +1,93 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "github.com/gomodule/redigo/redis" + "github.com/nitishm/go-rejson" + "log" +) + +func main() { + var addr = flag.String("Server", "localhost:6379", "Redis server address") + + flag.Parse() + + conn, err := redis.Dial("tcp", *addr) + if err != nil { + log.Fatalf("Failed to connect to redis-server @ %s", *addr) + } + defer func() { + conn.Do("FLUSHALL") + conn.Close() + }() + + type Object struct { + Name string `json:"name"` + LastSeen int64 `json:"lastSeen"` + LoggedOut bool `json:"loggedOut"` + } + + obj := Object{"Leonard Cohen", 1478476800, true} + res, err := rejson.JSONSet(conn, "obj", ".", obj, false, false) + if err != nil { + log.Fatalf("Failed to JSONSet") + return + } + fmt.Println("obj:", res) + + res, err = rejson.JSONGet(conn, "obj", ".") + if err != nil { + log.Fatalf("Failed to JSONGet") + return + } + var objOut Object + err = json.Unmarshal(res.([]byte), &objOut) + if err != nil { + log.Fatalf("Failed to JSON Unmarshal") + return + } + fmt.Println("got obj:", objOut) + + res, err = rejson.JSONObjLen(conn, "obj", ".") + if err != nil { + log.Fatalf("Failed to JSONObjLen") + return + } + fmt.Println("length:", res) + + res, err = rejson.JSONObjKeys(conn, "obj", ".") + if err != nil { + log.Fatalf("Failed to JSONObjKeys") + return + } + fmt.Println("keys:", res) + + res, err = rejson.JSONDebug(conn, rejson.DebugHelpSubcommand, "obj", ".") + if err != nil { + log.Fatalf("Failed to JSONDebug") + return + } + fmt.Println(res) + res, err = rejson.JSONDebug(conn, rejson.DebugMemorySubcommand, "obj", ".") + if err != nil { + log.Fatalf("Failed to JSONDebug") + return + } + fmt.Println("Memory used by obj:", res) + + res, err = rejson.JSONGet(conn, "obj", ".", + &rejson.JSONGetOptionIndent{"\t"}, &rejson.JSONGetOptionNewLine{"\n"}, + &rejson.JSONGetOptionSpace{" "}, &rejson.JSONGetOptionNoEscape{}) + if err != nil { + log.Fatalf("Failed to JSONGet") + return + } + err = json.Unmarshal(res.([]byte), &objOut) + if err != nil { + log.Fatalf("Failed to JSON Unmarshal") + return + } + fmt.Println("got obj with options:", objOut) +} diff --git a/rejson.go b/rejson.go index 290ab44..f1272d2 100644 --- a/rejson.go +++ b/rejson.go @@ -3,30 +3,95 @@ package rejson import ( "encoding/json" "fmt" + "strings" "github.com/gomodule/redigo/redis" ) -// PopArrLast gives index of the last element for JSONArrPop -const PopArrLast = -1 +const ( + // PopArrLast gives index of the last element for JSONArrPop + PopArrLast = -1 + // DebugMemorySubcommand provide the corresponding MEMORY sub commands for JSONDebug + DebugMemorySubcommand = "MEMORY" + // DebugHelpSubcommand provide the corresponding HELP sub commands for JSONDebug + DebugHelpSubcommand = "HELP" + // DebugHelpOutput is the ouput of command JSON.Debug HELP [path] + DebugHelpOutput = "MEMORY [path] - reports memory usage\nHELP - this message" +) + +// JSONGetOption provides methods various options for the JSON.GET Method +type JSONGetOption interface { + optionTypeValue() (string, string) +} + +// INDENT sets the indentation string for nested levels +type getOptionIndent struct { + indentation string +} + +func (opt *getOptionIndent) optionTypeValue() (string, string) { + return "INDENT", opt.indentation +} + +// NEWLINE sets the string that's printed at the end of each line +type getOptionNewLine struct { + lineBreak string +} + +func (opt *getOptionNewLine) optionTypeValue() (string, string) { + return "NEWLINE", opt.lineBreak +} + +// SPACE sets the string that's put between a key and a value +type getOptionSpace struct { + space string +} + +func (opt *getOptionSpace) optionTypeValue() (string, string) { + return "SPACE", opt.space +} + +// NOESCAPE option will disable the sending of \uXXXX escapes for non-ascii characters +type getOptionNoEscape struct{} + +func (opt *getOptionNoEscape) optionTypeValue() (string, string) { + return "NOESCAPE", "" +} + +// NewJSONGetOptionIndent provides new INDENT options for JSON.GET Method +func NewJSONGetOptionIndent(val string) JSONGetOption { return &getOptionIndent{val} } + +// NewJSONGetOptionNewLine provides new NEWLINE options for JSON.GET Method +func NewJSONGetOptionNewLine(val string) JSONGetOption { return &getOptionNewLine{val} } + +// NewJSONGetOptionSpace provides new SPACE options for JSON.GET Method +func NewJSONGetOptionSpace(val string) JSONGetOption { return &getOptionSpace{val} } + +// NewJSONGetOptionNoEscape provides new NOESCAPE options for JSON.GET Method +func NewJSONGetOptionNoEscape() JSONGetOption { return &getOptionNoEscape{} } // commandMux maps command name to a command function var commandMux = map[string]func(argsIn ...interface{}) (argsOut []interface{}, err error){ "JSON.SET": commandJSONSet, "JSON.GET": commandJSONGet, - "JSON.DEL": commandJSONDel, + "JSON.DEL": commandJSON, "JSON.MGET": commandJSONMGet, - "JSON.TYPE": commandJSONType, + "JSON.TYPE": commandJSON, "JSON.NUMINCRBY": commandJSONNumIncrBy, "JSON.NUMMULTBY": commandJSONNumMultBy, "JSON.STRAPPEND": commandJSONStrAppend, - "JSON.STRLEN": commandJSONStrLen, + "JSON.STRLEN": commandJSON, "JSON.ARRAPPEND": commandJSONArrAppend, - "JSON.ARRLEN": commandJSONArrLen, + "JSON.ARRLEN": commandJSON, "JSON.ARRPOP": commandJSONArrPop, "JSON.ARRINDEX": commandJSONArrIndex, "JSON.ARRTRIM": commandJSONArrTrim, "JSON.ARRINSERT": commandJSONArrInsert, + "JSON.OBJKEYS": commandJSON, + "JSON.OBJLEN": commandJSON, + "JSON.DEBUG": commandJSONDebug, + "JSON.FORGET": commandJSON, + "JSON.RESP": commandJSON, } func commandJSONSet(argsIn ...interface{}) (argsOut []interface{}, err error) { @@ -44,7 +109,7 @@ func commandJSONSet(argsIn ...interface{}) (argsOut []interface{}, err error) { argsOut = append(argsOut, b) if NX && XX { - err = fmt.Errorf("Both NX and XX cannot be true") + err = fmt.Errorf("both NX and XX cannot be true") return nil, err } @@ -60,10 +125,11 @@ func commandJSONGet(argsIn ...interface{}) (argsOut []interface{}, err error) { key := argsIn[0] path := argsIn[1] argsOut = append(argsOut, key, path) + argsOut = append(argsOut, argsIn[2:]...) return } -func commandJSONDel(argsIn ...interface{}) (argsOut []interface{}, err error) { +func commandJSON(argsIn ...interface{}) (argsOut []interface{}, err error) { key := argsIn[0] path := argsIn[1] argsOut = append(argsOut, key, path) @@ -78,13 +144,6 @@ func commandJSONMGet(argsIn ...interface{}) (argsOut []interface{}, err error) { return } -func commandJSONType(argsIn ...interface{}) (argsOut []interface{}, err error) { - key := argsIn[0] - path := argsIn[1] - argsOut = append(argsOut, key, path) - return -} - func commandJSONNumIncrBy(argsIn ...interface{}) (argsOut []interface{}, err error) { key := argsIn[0] path := argsIn[1] @@ -109,13 +168,6 @@ func commandJSONStrAppend(argsIn ...interface{}) (argsOut []interface{}, err err return } -func commandJSONStrLen(argsIn ...interface{}) (argsOut []interface{}, err error) { - key := argsIn[0] - path := argsIn[1] - argsOut = append(argsOut, key, path) - return -} - func commandJSONArrAppend(argsIn ...interface{}) (argsOut []interface{}, err error) { keys := argsIn[0] path := argsIn[1] @@ -131,13 +183,6 @@ func commandJSONArrAppend(argsIn ...interface{}) (argsOut []interface{}, err err return } -func commandJSONArrLen(argsIn ...interface{}) (argsOut []interface{}, err error) { - key := argsIn[0] - path := argsIn[1] - argsOut = append(argsOut, key, path) - return -} - func commandJSONArrPop(argsIn ...interface{}) (argsOut []interface{}, err error) { key := argsIn[0] path := argsIn[1] @@ -196,6 +241,14 @@ func commandJSONArrTrim(argsIn ...interface{}) (argsOut []interface{}, err error return } +func commandJSONDebug(argsIn ...interface{}) (argsOut []interface{}, err error) { + subcommand := argsIn[0] + key := argsIn[1] + path := argsIn[2] + argsOut = append(argsOut, subcommand, key, path) + return +} + // CommandBuilder is used to build a command that can be used directly with redigo's conn.Do() // This is especially useful if you do not need to conn.Do() and instead need to use the JSON.* commands in a // MUTLI/EXEC scenario along with some other operations like GET/SET/HGET/HSET/... @@ -227,12 +280,25 @@ func JSONSet(conn redis.Conn, key string, path string, obj interface{}, NX bool, // JSONGet used to get a json object // JSON.GET // [INDENT indentation-string] -// [NEWLINE line-break-string] +// [NEWLINE line-break-string] // [SPACE space-string] -// [NOESCAPE] -// [path ...] -func JSONGet(conn redis.Conn, key string, path string) (res interface{}, err error) { - name, args, _ := CommandBuilder("JSON.GET", key, path) +// [NOESCAPE] +// [path ...] +func JSONGet(conn redis.Conn, key string, path string, opts ...JSONGetOption) (res interface{}, err error) { + args := make([]interface{}, 0) + args = append(args, key) + + for _, op := range opts { + ty, va := op.optionTypeValue() + + args = append(args, ty) + if ty != "NOESCAPE" { + args = append(args, va) + } + } + args = append(args, path) + + name, args, _ := CommandBuilder("JSON.GET", args...) return conn.Do(name, args...) } @@ -240,7 +306,7 @@ func JSONGet(conn redis.Conn, key string, path string) (res interface{}, err err // JSON.MGET [key ...] func JSONMGet(conn redis.Conn, path string, keys ...string) (res interface{}, err error) { if len(keys) == 0 { - err = fmt.Errorf("Need atlesat one key as an argument") + err = fmt.Errorf("need atlesat one key as an argument") return nil, err } @@ -299,7 +365,7 @@ func JSONStrLen(conn redis.Conn, key string, path string) (res interface{}, err // JSON.ARRAPPEND [json ...] func JSONArrAppend(conn redis.Conn, key string, path string, values ...interface{}) (res interface{}, err error) { if len(values) == 0 { - err = fmt.Errorf("Need atlesat one value string as an argument") + err = fmt.Errorf("need atlesat one value string as an argument") return nil, err } @@ -332,7 +398,7 @@ func JSONArrIndex(conn redis.Conn, key, path string, jsonValue interface{}, opti ln := len(optionalRange) if ln > 2 { - return nil, fmt.Errorf("Need atmost two integeral value as an argument representing array range") + return nil, fmt.Errorf("need atmost two integeral value as an argument representing array range") } else if ln == 1 { // only inclusive start is present args = append(args, optionalRange[0]) } else if ln == 2 { // both inclusive start and exclusive end are present @@ -353,7 +419,7 @@ func JSONArrTrim(conn redis.Conn, key, path string, start, end int) (res interfa // JSON.ARRINSERT [json ...] func JSONArrInsert(conn redis.Conn, key, path string, index int, values ...interface{}) (res interface{}, err error) { if len(values) == 0 { - err = fmt.Errorf("Need atlesat one value string as an argument") + err = fmt.Errorf("need atlesat one value string as an argument") return nil, err } @@ -363,3 +429,79 @@ func JSONArrInsert(conn redis.Conn, key, path string, index int, values ...inter name, args, _ := CommandBuilder("JSON.ARRINSERT", args...) return conn.Do(name, args...) } + +// JSONObjKeys returns the keys in the object that's referenced by path +// JSON.OBJKEYS [path] +func JSONObjKeys(conn redis.Conn, key, path string) (res interface{}, err error) { + name, args, _ := CommandBuilder("JSON.OBJKEYS", key, path) + res, err = conn.Do(name, args...) + if err != nil { + return + } + // JSON.OBJKEYS returns slice of string as slice of uint8 + slc := make([]string, 0, 10) + for _, r := range res.([]interface{}) { + slc = append(slc, tostring(r)) + } + res = slc + return +} + +// JSONObjLen report the number of keys in the JSON Object at path in key +// JSON.OBJLEN [path] +func JSONObjLen(conn redis.Conn, key, path string) (res interface{}, err error) { + name, args, _ := CommandBuilder("JSON.OBJLEN", key, path) + return conn.Do(name, args...) +} + +// JSONDebug reports information +// JSON.DEBUG +// JSON.DEBUG MEMORY [path] - report the memory usage in bytes of a value. path defaults to root if not provided. +// JSON.DEBUG HELP - reply with a helpful message +func JSONDebug(conn redis.Conn, subcommand, key, path string) (res interface{}, err error) { + if subcommand != DebugMemorySubcommand && subcommand != DebugHelpSubcommand { + err = fmt.Errorf("unknown subcommand - try `JSON.DEBUG HELP`") + return + } + name, args, _ := CommandBuilder("JSON.DEBUG", subcommand, key, path) + res, err = conn.Do(name, args...) + if err != nil { + return + } + // JSONDebugMemorySubcommand returns an integer representing memory usage + if subcommand == DebugMemorySubcommand { + return res.(int64), err + } + // JSONDebugHelpSubcommand returns slice of string of Help as slice of uint8 + hlp := make([]string, 0, 10) + for _, r := range res.([]interface{}) { + hlp = append(hlp, tostring(r)) + } + res = strings.Join(hlp, "\n") + return +} + +//JSONForget is an alias for JSONDel +func JSONForget(conn redis.Conn, key string, path string) (res interface{}, err error) { + name, args, _ := CommandBuilder("JSON.FORGET", key, path) + return conn.Do(name, args...) +} + +//JSONResp returns the JSON in key in Redis Serialization Protocol (RESP). +//JSON.RESP [path] +func JSONResp(conn redis.Conn, key string, path string) (res interface{}, err error) { + name, args, _ := CommandBuilder("JSON.RESP", key, path) + return conn.Do(name, args...) +} + +// tostring converts each byte in slice into character, else panic out +func tostring(lst interface{}) (str string) { + _lst, ok := lst.([]byte) + if !ok { + panic("error: something went wrong") + } + for _, s := range _lst { + str += string(s) + } + return +} diff --git a/rejson_test.go b/rejson_test.go index 7f796e8..c1bb036 100644 --- a/rejson_test.go +++ b/rejson_test.go @@ -184,9 +184,10 @@ func TestJSONGet(t *testing.T) { } type args struct { - conn redis.Conn - key string - path string + conn redis.Conn + key string + path string + options []JSONGetOption } tests := []struct { name string @@ -197,9 +198,10 @@ func TestJSONGet(t *testing.T) { { name: "SimpleString", args: args{ - conn: conn, - key: "kstr", - path: ".", + conn: conn, + key: "kstr", + path: ".", + options: []JSONGetOption{}, }, wantRes: []byte("\"simplestring\""), wantErr: false, @@ -207,33 +209,51 @@ func TestJSONGet(t *testing.T) { { name: "SimpleInt", args: args{ - conn: conn, - key: "kint", - path: ".", + conn: conn, + key: "kint", + path: ".", + options: []JSONGetOption{}, }, wantRes: []byte("123"), wantErr: false, }, + { + name: "SimpleStruct", + args: args{ + conn: conn, + key: "kstruct", + path: ".", + options: []JSONGetOption{}, + }, + wantRes: []byte("{\"name\":\"Item#1\",\"number\":1}"), + wantErr: false, + }, { name: "SimpleStruct", args: args{ conn: conn, key: "kstruct", path: ".", + options: []JSONGetOption{ + NewJSONGetOptionIndent("\t"), + NewJSONGetOptionNewLine("\n"), + NewJSONGetOptionNoEscape(), + NewJSONGetOptionSpace(" "), + }, }, - wantRes: []byte("{\"name\":\"Item#1\",\"number\":1}"), + wantRes: []byte("{\n\t\"name\": \"Item#1\",\n\t\"number\": 1\n}"), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - gotRes, err := JSONGet(tt.args.conn, tt.args.key, tt.args.path) + gotRes, err := JSONGet(tt.args.conn, tt.args.key, tt.args.path, tt.args.options...) if (err != nil) != tt.wantErr { t.Errorf("JSONGet() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(gotRes, tt.wantRes) { - t.Errorf("JSONGet() = %v, want %v", gotRes, tt.wantRes) + t.Errorf("\nJSONGet() = %v,\nwant = %v", gotRes, tt.wantRes) } }) } @@ -1104,10 +1124,10 @@ func TestJSONArrPop(t *testing.T) { } type args struct { - conn redis.Conn - key string - path string - index int + conn redis.Conn + key string + path string + index int } tests := []struct { name string @@ -1470,3 +1490,349 @@ func TestJSONArrInsert(t *testing.T) { }) } } + +func TestJSONObjLen(t *testing.T) { + conn, err := redis.Dial("tcp", ":6379") + if err != nil { + t.Fatal("Could not connect to redis.") + return + } + defer func() { + conn.Do("FLUSHALL") + conn.Close() + }() + + type Object struct { + Name string `json:"name"` + LastSeen int64 `json:"lastSeen"` + LoggedOut bool `json:"loggedOut"` + } + obj := Object{"Leonard Cohen", 1478476800, true} + _, err = JSONSet(conn, "tobj", ".", obj, false, false) + if err != nil { + return + } + + _, err = JSONSet(conn, "tstr", ".", "SimpleString", false, false) + if err != nil { + return + } + type args struct { + conn redis.Conn + key string + path string + } + tests := []struct { + name string + args args + wantRes interface{} + wantErr bool + }{ + { + name: "SimpleObject", + args: args{ + conn: conn, + key: "tobj", + path: ".", + }, + wantRes: int64(3), + wantErr: false, + }, + { + name: "SimpleString", + args: args{ + conn: conn, + key: "tstr", + path: ".", + }, + wantRes: redis.Error("ERR wrong type of path value - expected object but found string"), + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotRes, err := JSONObjLen(tt.args.conn, tt.args.key, tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("JSONObjLen() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotRes, tt.wantRes) { + t.Errorf("JSONObjLen() = %v, want %v", gotRes, tt.wantRes) + } + }) + } +} + +func TestJSONObjKeys(t *testing.T) { + conn, err := redis.Dial("tcp", ":6379") + if err != nil { + t.Fatal("Could not connect to redis.") + return + } + defer func() { + conn.Do("FLUSHALL") + conn.Close() + }() + + type Object struct { + Name string `json:"name"` + LastSeen int64 `json:"lastSeen"` + LoggedOut bool `json:"loggedOut"` + } + obj := Object{"Leonard Cohen", 1478476800, true} + _, err = JSONSet(conn, "tobj", ".", obj, false, false) + if err != nil { + return + } + + _, err = JSONSet(conn, "tstr", ".", "SimpleString", false, false) + if err != nil { + return + } + type args struct { + conn redis.Conn + key string + path string + } + tests := []struct { + name string + args args + wantRes interface{} + wantErr bool + }{ + { + name: "SimpleObject", + args: args{ + conn: conn, + key: "tobj", + path: ".", + }, + wantRes: []string{"name", "lastSeen", "loggedOut"}, + wantErr: false, + }, + { + name: "SimpleString", + args: args{ + conn: conn, + key: "tstr", + path: ".", + }, + wantRes: redis.Error("ERR wrong type of path value - expected object but found string"), + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotRes, err := JSONObjKeys(tt.args.conn, tt.args.key, tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("JSONObjKeys() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotRes, tt.wantRes) { + t.Errorf("JSONObjKeys() = %v, want %v", gotRes, tt.wantRes) + } + }) + } +} + +func TestJSONDebug(t *testing.T) { + conn, err := redis.Dial("tcp", ":6379") + if err != nil { + t.Fatal("Could not connect to redis.") + return + } + defer func() { + conn.Do("FLUSHALL") + conn.Close() + }() + + _, err = JSONSet(conn, "tstr", ".", "SimpleString", false, false) + if err != nil { + return + } + type args struct { + conn redis.Conn + subCommand string + key string + path string + } + tests := []struct { + name string + args args + wantRes interface{} + wantErr bool + }{ + { + name: "Debug Help", + args: args{ + conn: conn, + subCommand: DebugHelpSubcommand, + key: "tstr", + path: ".", + }, + wantRes: DebugHelpOutput, + wantErr: false, + }, + { + name: "Debug Memory", + args: args{ + conn: conn, + subCommand: DebugMemorySubcommand, + key: "tstr", + path: ".", + }, + wantRes: int64(36), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotRes, err := JSONDebug(tt.args.conn, tt.args.subCommand, tt.args.key, tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("JSONDebug() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotRes, tt.wantRes) { + t.Errorf("JSONDebug() = %v, want %v", gotRes, tt.wantRes) + } + }) + } +} + +func TestJSONForget(t *testing.T) { + conn, err := redis.Dial("tcp", ":6379") + if err != nil { + t.Fatal("Could not connect to redis.") + return + } + defer func() { + conn.Do("FLUSHALL") + conn.Close() + }() + + _, err = JSONSet(conn, "kstr", ".", "simplestring", false, false) + if err != nil { + return + } + + testObj := TestObject{ + Name: "Item#1", + Number: 1, + } + + _, err = JSONSet(conn, "kstruct", ".", testObj, false, false) + if err != nil { + return + } + + type args struct { + conn redis.Conn + key string + path string + } + tests := []struct { + name string + args args + wantRes interface{} + wantErr bool + }{ + { + name: "SimpleString", + args: args{ + conn: conn, + key: "kstr", + path: ".", + }, + wantRes: int64(1), + wantErr: false, + }, + { + name: "SimpleStructFieldOK", + args: args{ + conn: conn, + key: "kstruct", + path: "name", + }, + wantRes: int64(1), + wantErr: false, + }, + { + name: "SimpleStructFieldNotOK", + args: args{ + conn: conn, + key: "kstruct", + path: "foobar", + }, + wantRes: int64(0), + wantErr: false, + }, + { + name: "SimpleStruct", + args: args{ + conn: conn, + key: "kstruct", + path: ".", + }, + wantRes: int64(1), + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotRes, err := JSONForget(tt.args.conn, tt.args.key, tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("JSONForget() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotRes, tt.wantRes) { + t.Errorf("JSONForget() = %t, want %t", gotRes, tt.wantRes) + } + }) + } +} + +func TestJSONResp(t *testing.T) { + conn, err := redis.Dial("tcp", ":6379") + if err != nil { + t.Fatal("Could not connect to redis.") + return + } + defer func() { + conn.Do("FLUSHALL") + conn.Close() + }() + + _, err = JSONSet(conn, "tstr", ".", "SimpleString", false, false) + if err != nil { + return + } + type args struct { + conn redis.Conn + key string + path string + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "RESP", + args: args{ + conn: conn, + key: "tstr", + path: ".", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := JSONResp(tt.args.conn, tt.args.key, tt.args.path) + if (err != nil) != tt.wantErr { + t.Errorf("JSONResp() error = %v, wantErr %v", err, tt.wantErr) + return + } + }) + } +} diff --git a/staticcheck.conf b/staticcheck.conf new file mode 100644 index 0000000..28b36b6 --- /dev/null +++ b/staticcheck.conf @@ -0,0 +1 @@ +# Staticcheck Custom configurations (currently default configurations are used)