1
0
mirror of https://github.com/redis/go-redis.git synced 2025-07-28 06:42:00 +03:00

Refactor reply parser.

This commit is contained in:
Vladimir Mihailenco
2015-10-07 17:09:20 +03:00
parent 2d37474474
commit b23b9b7727
9 changed files with 383 additions and 275 deletions

View File

@ -28,7 +28,7 @@ var (
type Cmder interface {
args() []interface{}
parseReply(*conn) error
readReply(*conn) error
setErr(error)
reset()
@ -152,14 +152,20 @@ func (cmd *Cmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *Cmd) parseReply(cn *conn) error {
cmd.val, cmd.err = parseReply(cn, parseSlice)
// Convert to string to preserve old behaviour.
// TODO: remove in v4
if v, ok := cmd.val.([]byte); ok {
cmd.val = string(v)
func (cmd *Cmd) readReply(cn *conn) error {
val, err := readReply(cn, sliceParser)
if err != nil {
cmd.err = err
return cmd.err
}
return cmd.err
if v, ok := val.([]byte); ok {
// Convert to string to preserve old behaviour.
// TODO: remove in v4
cmd.val = string(v)
} else {
cmd.val = val
}
return nil
}
//------------------------------------------------------------------------------
@ -191,8 +197,8 @@ func (cmd *SliceCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *SliceCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseSlice)
func (cmd *SliceCmd) readReply(cn *conn) error {
v, err := readReply(cn, sliceParser)
if err != nil {
cmd.err = err
return err
@ -234,8 +240,8 @@ func (cmd *StatusCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *StatusCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, nil)
func (cmd *StatusCmd) readReply(cn *conn) error {
v, err := readReply(cn, nil)
if err != nil {
cmd.err = err
return err
@ -273,8 +279,8 @@ func (cmd *IntCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *IntCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, nil)
func (cmd *IntCmd) readReply(cn *conn) error {
v, err := readReply(cn, nil)
if err != nil {
cmd.err = err
return err
@ -316,8 +322,8 @@ func (cmd *DurationCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *DurationCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, nil)
func (cmd *DurationCmd) readReply(cn *conn) error {
v, err := readReply(cn, nil)
if err != nil {
cmd.err = err
return err
@ -357,8 +363,8 @@ func (cmd *BoolCmd) String() string {
var ok = []byte("OK")
func (cmd *BoolCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, nil)
func (cmd *BoolCmd) readReply(cn *conn) error {
v, err := readReply(cn, nil)
// `SET key value NX` returns nil when key already exists, which
// is inconsistent with `SETNX key value`.
// TODO: is this okay?
@ -443,8 +449,8 @@ func (cmd *StringCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *StringCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, nil)
func (cmd *StringCmd) readReply(cn *conn) error {
v, err := readReply(cn, nil)
if err != nil {
cmd.err = err
return err
@ -482,8 +488,8 @@ func (cmd *FloatCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *FloatCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, nil)
func (cmd *FloatCmd) readReply(cn *conn) error {
v, err := readReply(cn, nil)
if err != nil {
cmd.err = err
return err
@ -522,8 +528,8 @@ func (cmd *StringSliceCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *StringSliceCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseStringSlice)
func (cmd *StringSliceCmd) readReply(cn *conn) error {
v, err := readReply(cn, stringSliceParser)
if err != nil {
cmd.err = err
return err
@ -561,8 +567,8 @@ func (cmd *BoolSliceCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *BoolSliceCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseBoolSlice)
func (cmd *BoolSliceCmd) readReply(cn *conn) error {
v, err := readReply(cn, boolSliceParser)
if err != nil {
cmd.err = err
return err
@ -600,8 +606,8 @@ func (cmd *StringStringMapCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *StringStringMapCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseStringStringMap)
func (cmd *StringStringMapCmd) readReply(cn *conn) error {
v, err := readReply(cn, stringStringMapParser)
if err != nil {
cmd.err = err
return err
@ -639,8 +645,8 @@ func (cmd *StringIntMapCmd) reset() {
cmd.err = nil
}
func (cmd *StringIntMapCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseStringIntMap)
func (cmd *StringIntMapCmd) readReply(cn *conn) error {
v, err := readReply(cn, stringIntMapParser)
if err != nil {
cmd.err = err
return err
@ -678,8 +684,8 @@ func (cmd *ZSliceCmd) String() string {
return cmdString(cmd, cmd.val)
}
func (cmd *ZSliceCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseZSlice)
func (cmd *ZSliceCmd) readReply(cn *conn) error {
v, err := readReply(cn, zSliceParser)
if err != nil {
cmd.err = err
return err
@ -719,8 +725,8 @@ func (cmd *ScanCmd) String() string {
return cmdString(cmd, cmd.keys)
}
func (cmd *ScanCmd) parseReply(cn *conn) error {
vi, err := parseReply(cn, parseSlice)
func (cmd *ScanCmd) readReply(cn *conn) error {
vi, err := readReply(cn, sliceParser)
if err != nil {
cmd.err = err
return cmd.err
@ -743,8 +749,9 @@ func (cmd *ScanCmd) parseReply(cn *conn) error {
//------------------------------------------------------------------------------
type ClusterSlotInfo struct {
Start, End int
Addrs []string
Start int
End int
Addrs []string
}
type ClusterSlotCmd struct {
@ -774,8 +781,8 @@ func (cmd *ClusterSlotCmd) reset() {
cmd.err = nil
}
func (cmd *ClusterSlotCmd) parseReply(cn *conn) error {
v, err := parseReply(cn, parseClusterSlotInfoSlice)
func (cmd *ClusterSlotCmd) readReply(cn *conn) error {
v, err := readReply(cn, clusterSlotInfoSliceParser)
if err != nil {
cmd.err = err
return err
@ -786,99 +793,62 @@ func (cmd *ClusterSlotCmd) parseReply(cn *conn) error {
//------------------------------------------------------------------------------
// Location type for GEO operations in Redis
// GeoLocation is used with GeoAdd to add geospatial location.
type GeoLocation struct {
Name string
Name string
Longitude, Latitude, Distance float64
GeoHash int64
GeoHash int64
}
type GeoCmd struct {
// GeoRadiusQuery is used with GeoRadius to query geospatial index.
type GeoRadiusQuery struct {
Key string
Longitude float64
Latitude float64
Radius float64
// Can be m, km, ft, or mi. Default is km.
Unit string
WithCoordinates bool
WithDistance bool
WithGeoHash bool
Count int
// Can be ASC or DESC. Default is no sort order.
Sort string
}
type GeoLocationCmd struct {
baseCmd
locations []GeoLocation
}
// Query type for geo radius
type GeoRadiusQuery struct {
Key string
Longitude, Latitude, Radius float64
// Unit default to km when nil
Unit string
WithCoordinates, WithDistance, WithGeoHash bool
// Count default to 0 and ignored limit.
Count int
// Sort default to unsorted, ASC or DESC otherwise
Sort string
func NewGeoLocationCmd(args ...interface{}) *GeoLocationCmd {
return &GeoLocationCmd{baseCmd: baseCmd{_args: args, _clusterKeyPos: 1}}
}
func NewGeoCmd(args ...interface{}) *GeoCmd {
return &GeoCmd{baseCmd: baseCmd{_args: args, _clusterKeyPos: 1}}
}
func (cmd *GeoCmd) reset() {
func (cmd *GeoLocationCmd) reset() {
cmd.locations = nil
cmd.err = nil
}
func (cmd *GeoCmd) Val() ([]GeoLocation) {
func (cmd *GeoLocationCmd) Val() []GeoLocation {
return cmd.locations
}
func (cmd *GeoCmd) Result() ([]GeoLocation, error) {
func (cmd *GeoLocationCmd) Result() ([]GeoLocation, error) {
return cmd.locations, cmd.err
}
func (cmd *GeoCmd) String() string {
func (cmd *GeoLocationCmd) String() string {
return cmdString(cmd, cmd.locations)
}
func (cmd *GeoCmd) parseReply(cn *conn) error {
vi, err := parseReply(cn, parseSlice)
func (cmd *GeoLocationCmd) readReply(cn *conn) error {
reply, err := readReply(cn, geoLocationSliceParser)
if err != nil {
cmd.err = err
return cmd.err
}
v := vi.([]interface{})
if len(v) == 0 {
return nil
}
if _, ok := v[0].(string); ok { // Location names only (single level string array)
for _, keyi := range v {
cmd.locations = append(cmd.locations, GeoLocation{Name: keyi.(string)})
}
} else { // Full location details (nested arrays)
for _, keyi := range v {
tmpLocation := GeoLocation{}
keyiface := keyi.([]interface{})
for _, subKeyi := range keyiface {
if strVal, ok := subKeyi.(string); ok {
if len(tmpLocation.Name) == 0 {
tmpLocation.Name = strVal
} else {
tmpLocation.Distance, err = strconv.ParseFloat(strVal, 64)
if err != nil {
return err
}
}
} else if intVal, ok := subKeyi.(int64); ok {
tmpLocation.GeoHash = intVal
} else if ifcVal, ok := subKeyi.([]interface{}); ok {
tmpLocation.Longitude, err = strconv.ParseFloat(ifcVal[0].(string), 64)
if err != nil {
return err
}
tmpLocation.Latitude, err = strconv.ParseFloat(ifcVal[1].(string), 64)
if err != nil {
return err
}
}
}
cmd.locations = append(cmd.locations, tmpLocation)
}
return err
}
cmd.locations = reply.([]GeoLocation)
return nil
}