mirror of https://github.com/ledisdb/ledisdb.git
add client ledis lib and ledis-cli
This commit is contained in:
parent
9e09e607c8
commit
55bce5f553
|
@ -0,0 +1,81 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"github.com/siddontang/ledisdb/client/go/ledis"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var ip = flag.String("h", "127.0.0.1", "ledisdb server ip (default 127.0.0.1)")
|
||||
var port = flag.Int("p", 6380, "ledisdb server port (default 6380)")
|
||||
var socket = flag.String("s", "", "ledisdb server socket, overwrite ip and port")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
cfg := new(ledis.Config)
|
||||
if len(*socket) > 0 {
|
||||
cfg.Addr = *socket
|
||||
} else {
|
||||
cfg.Addr = fmt.Sprintf("%s:%d", *ip, *port)
|
||||
}
|
||||
|
||||
cfg.MaxIdleConns = 1
|
||||
|
||||
c := ledis.NewClient(cfg)
|
||||
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
fmt.Printf("ledis %s > ", cfg.Addr)
|
||||
|
||||
cmd, _ := reader.ReadString('\n')
|
||||
|
||||
cmds := strings.Fields(cmd)
|
||||
if len(cmds) == 0 {
|
||||
continue
|
||||
} else {
|
||||
args := make([]interface{}, len(cmds[1:]))
|
||||
for i := range args {
|
||||
args[i] = cmds[1+i]
|
||||
}
|
||||
r, err := c.Do(cmds[0], args...)
|
||||
if err != nil {
|
||||
fmt.Printf("%s", err.Error())
|
||||
} else {
|
||||
printReply(r)
|
||||
}
|
||||
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printReply(reply interface{}) {
|
||||
switch reply := reply.(type) {
|
||||
case int64:
|
||||
fmt.Printf("(integer) %d", reply)
|
||||
case string:
|
||||
fmt.Printf("%q", reply)
|
||||
case []byte:
|
||||
fmt.Printf("%q", reply)
|
||||
case nil:
|
||||
fmt.Printf("(empty list or set)")
|
||||
case ledis.Error:
|
||||
fmt.Printf("%s", string(reply))
|
||||
case []interface{}:
|
||||
for i, v := range reply {
|
||||
fmt.Printf("%d) ", i)
|
||||
if v == nil {
|
||||
fmt.Printf("(nil)")
|
||||
} else {
|
||||
fmt.Printf("%q", v)
|
||||
}
|
||||
}
|
||||
default:
|
||||
fmt.Printf("invalid ledis reply")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package ledis
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
pingPeriod time.Duration = 3 * time.Second
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Addr string
|
||||
MaxIdleConns int
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
sync.Mutex
|
||||
|
||||
cfg *Config
|
||||
proto string
|
||||
|
||||
conns *list.List
|
||||
}
|
||||
|
||||
func NewClient(cfg *Config) *Client {
|
||||
c := new(Client)
|
||||
|
||||
c.cfg = cfg
|
||||
|
||||
if strings.Contains(cfg.Addr, "/") {
|
||||
c.proto = "unix"
|
||||
} else {
|
||||
c.proto = "tcp"
|
||||
}
|
||||
|
||||
c.conns = list.New()
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) Do(cmd string, args ...interface{}) (interface{}, error) {
|
||||
co := c.get()
|
||||
r, err := co.Do(cmd, args...)
|
||||
c.put(co)
|
||||
|
||||
return r, err
|
||||
}
|
||||
|
||||
func (c *Client) Close() {
|
||||
c.Lock()
|
||||
defer c.Unlock()
|
||||
|
||||
for c.conns.Len() > 0 {
|
||||
e := c.conns.Front()
|
||||
co := e.Value.(*Conn)
|
||||
c.conns.Remove(e)
|
||||
|
||||
co.finalize()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) Get() *Conn {
|
||||
return c.get()
|
||||
}
|
||||
|
||||
func (c *Client) get() *Conn {
|
||||
c.Lock()
|
||||
if c.conns.Len() == 0 {
|
||||
c.Unlock()
|
||||
|
||||
return c.newConn()
|
||||
} else {
|
||||
e := c.conns.Front()
|
||||
co := e.Value.(*Conn)
|
||||
c.conns.Remove(e)
|
||||
|
||||
c.Unlock()
|
||||
|
||||
return co
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Client) put(conn *Conn) {
|
||||
c.Lock()
|
||||
if c.conns.Len() >= c.cfg.MaxIdleConns {
|
||||
c.Unlock()
|
||||
conn.finalize()
|
||||
} else {
|
||||
conn.lastActive = time.Now()
|
||||
c.conns.PushFront(conn)
|
||||
c.Unlock()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,309 @@
|
|||
package ledis
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Error represents an error returned in a command reply.
|
||||
type Error string
|
||||
|
||||
func (err Error) Error() string { return string(err) }
|
||||
|
||||
type Conn struct {
|
||||
client *Client
|
||||
|
||||
c net.Conn
|
||||
br *bufio.Reader
|
||||
bw *bufio.Writer
|
||||
|
||||
lastActive time.Time
|
||||
|
||||
// Scratch space for formatting argument length.
|
||||
// '*' or '$', length, "\r\n"
|
||||
lenScratch [32]byte
|
||||
|
||||
// Scratch space for formatting integers and floats.
|
||||
numScratch [40]byte
|
||||
}
|
||||
|
||||
func (c *Conn) Close() {
|
||||
c.client.put(c)
|
||||
}
|
||||
|
||||
func (c *Conn) Do(cmd string, args ...interface{}) (interface{}, error) {
|
||||
if err := c.connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.writeCommand(cmd, args); err != nil {
|
||||
c.finalize()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := c.bw.Flush(); err != nil {
|
||||
c.finalize()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reply, err := c.readReply(); err != nil {
|
||||
c.finalize()
|
||||
return nil, err
|
||||
} else {
|
||||
if e, ok := reply.(Error); ok {
|
||||
return reply, e
|
||||
} else {
|
||||
return reply, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) finalize() {
|
||||
if c.c != nil {
|
||||
c.c.Close()
|
||||
c.c = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Conn) connect() error {
|
||||
if c.c != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
c.c, err = net.Dial(c.client.proto, c.client.cfg.Addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.br != nil {
|
||||
c.br.Reset(c.c)
|
||||
} else {
|
||||
c.br = bufio.NewReader(c.c)
|
||||
}
|
||||
|
||||
if c.bw != nil {
|
||||
c.bw.Reset(c.c)
|
||||
} else {
|
||||
c.bw = bufio.NewWriter(c.c)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Conn) writeLen(prefix byte, n int) error {
|
||||
c.lenScratch[len(c.lenScratch)-1] = '\n'
|
||||
c.lenScratch[len(c.lenScratch)-2] = '\r'
|
||||
i := len(c.lenScratch) - 3
|
||||
for {
|
||||
c.lenScratch[i] = byte('0' + n%10)
|
||||
i -= 1
|
||||
n = n / 10
|
||||
if n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
c.lenScratch[i] = prefix
|
||||
_, err := c.bw.Write(c.lenScratch[i:])
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) writeString(s string) error {
|
||||
c.writeLen('$', len(s))
|
||||
c.bw.WriteString(s)
|
||||
_, err := c.bw.WriteString("\r\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) writeBytes(p []byte) error {
|
||||
c.writeLen('$', len(p))
|
||||
c.bw.Write(p)
|
||||
_, err := c.bw.WriteString("\r\n")
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) writeInt64(n int64) error {
|
||||
return c.writeBytes(strconv.AppendInt(c.numScratch[:0], n, 10))
|
||||
}
|
||||
|
||||
func (c *Conn) writeFloat64(n float64) error {
|
||||
return c.writeBytes(strconv.AppendFloat(c.numScratch[:0], n, 'g', -1, 64))
|
||||
}
|
||||
|
||||
func (c *Conn) writeCommand(cmd string, args []interface{}) (err error) {
|
||||
c.writeLen('*', 1+len(args))
|
||||
err = c.writeString(cmd)
|
||||
for _, arg := range args {
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
switch arg := arg.(type) {
|
||||
case string:
|
||||
err = c.writeString(arg)
|
||||
case []byte:
|
||||
err = c.writeBytes(arg)
|
||||
case int:
|
||||
err = c.writeInt64(int64(arg))
|
||||
case int64:
|
||||
err = c.writeInt64(arg)
|
||||
case float64:
|
||||
err = c.writeFloat64(arg)
|
||||
case bool:
|
||||
if arg {
|
||||
err = c.writeString("1")
|
||||
} else {
|
||||
err = c.writeString("0")
|
||||
}
|
||||
case nil:
|
||||
err = c.writeString("")
|
||||
default:
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprint(&buf, arg)
|
||||
err = c.writeBytes(buf.Bytes())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Conn) readLine() ([]byte, error) {
|
||||
p, err := c.br.ReadSlice('\n')
|
||||
if err == bufio.ErrBufferFull {
|
||||
return nil, errors.New("ledis: long response line")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i := len(p) - 2
|
||||
if i < 0 || p[i] != '\r' {
|
||||
return nil, errors.New("ledis: bad response line terminator")
|
||||
}
|
||||
return p[:i], nil
|
||||
}
|
||||
|
||||
// parseLen parses bulk string and array lengths.
|
||||
func parseLen(p []byte) (int, error) {
|
||||
if len(p) == 0 {
|
||||
return -1, errors.New("ledis: malformed length")
|
||||
}
|
||||
|
||||
if p[0] == '-' && len(p) == 2 && p[1] == '1' {
|
||||
// handle $-1 and $-1 null replies.
|
||||
return -1, nil
|
||||
}
|
||||
|
||||
var n int
|
||||
for _, b := range p {
|
||||
n *= 10
|
||||
if b < '0' || b > '9' {
|
||||
return -1, errors.New("ledis: illegal bytes in length")
|
||||
}
|
||||
n += int(b - '0')
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// parseInt parses an integer reply.
|
||||
func parseInt(p []byte) (interface{}, error) {
|
||||
if len(p) == 0 {
|
||||
return 0, errors.New("ledis: malformed integer")
|
||||
}
|
||||
|
||||
var negate bool
|
||||
if p[0] == '-' {
|
||||
negate = true
|
||||
p = p[1:]
|
||||
if len(p) == 0 {
|
||||
return 0, errors.New("ledis: malformed integer")
|
||||
}
|
||||
}
|
||||
|
||||
var n int64
|
||||
for _, b := range p {
|
||||
n *= 10
|
||||
if b < '0' || b > '9' {
|
||||
return 0, errors.New("ledis: illegal bytes in length")
|
||||
}
|
||||
n += int64(b - '0')
|
||||
}
|
||||
|
||||
if negate {
|
||||
n = -n
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
var (
|
||||
okReply interface{} = "OK"
|
||||
pongReply interface{} = "PONG"
|
||||
)
|
||||
|
||||
func (c *Conn) readReply() (interface{}, error) {
|
||||
line, err := c.readLine()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(line) == 0 {
|
||||
return nil, errors.New("ledis: short response line")
|
||||
}
|
||||
switch line[0] {
|
||||
case '+':
|
||||
switch {
|
||||
case len(line) == 3 && line[1] == 'O' && line[2] == 'K':
|
||||
// Avoid allocation for frequent "+OK" response.
|
||||
return okReply, nil
|
||||
case len(line) == 5 && line[1] == 'P' && line[2] == 'O' && line[3] == 'N' && line[4] == 'G':
|
||||
// Avoid allocation in PING command benchmarks :)
|
||||
return pongReply, nil
|
||||
default:
|
||||
return string(line[1:]), nil
|
||||
}
|
||||
case '-':
|
||||
return Error(string(line[1:])), nil
|
||||
case ':':
|
||||
return parseInt(line[1:])
|
||||
case '$':
|
||||
n, err := parseLen(line[1:])
|
||||
if n < 0 || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := make([]byte, n)
|
||||
_, err = io.ReadFull(c.br, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if line, err := c.readLine(); err != nil {
|
||||
return nil, err
|
||||
} else if len(line) != 0 {
|
||||
return nil, errors.New("ledis: bad bulk string format")
|
||||
}
|
||||
return p, nil
|
||||
case '*':
|
||||
n, err := parseLen(line[1:])
|
||||
if n < 0 || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := make([]interface{}, n)
|
||||
for i := range r {
|
||||
r[i], err = c.readReply()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
return nil, errors.New("ledis: unexpected response line")
|
||||
}
|
||||
|
||||
func (c *Client) newConn() *Conn {
|
||||
co := new(Conn)
|
||||
co.client = c
|
||||
|
||||
return co
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2012 Gary Burd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
|
@ -0,0 +1,15 @@
|
|||
package ledis
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestClient(t *testing.T) {
|
||||
cfg := new(Config)
|
||||
cfg.Addr = "127.0.0.1:6380"
|
||||
cfg.MaxIdleConns = 4
|
||||
|
||||
c := NewClient(cfg)
|
||||
|
||||
c.Close()
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
package ledis
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// ErrNil indicates that a reply value is nil.
|
||||
var ErrNil = errors.New("ledis: nil returned")
|
||||
|
||||
// Int is a helper that converts a command reply to an integer. If err is not
|
||||
// equal to nil, then Int returns 0, err. Otherwise, Int converts the
|
||||
// reply to an int as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// integer int(reply), nil
|
||||
// bulk string parsed reply, nil
|
||||
// nil 0, ErrNil
|
||||
// other 0, error
|
||||
func Int(reply interface{}, err error) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case int64:
|
||||
x := int(reply)
|
||||
if int64(x) != reply {
|
||||
return 0, strconv.ErrRange
|
||||
}
|
||||
return x, nil
|
||||
case []byte:
|
||||
n, err := strconv.ParseInt(string(reply), 10, 0)
|
||||
return int(n), err
|
||||
case nil:
|
||||
return 0, ErrNil
|
||||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Int, got type %T", reply)
|
||||
}
|
||||
|
||||
// Int64 is a helper that converts a command reply to 64 bit integer. If err is
|
||||
// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
|
||||
// reply to an int64 as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// integer reply, nil
|
||||
// bulk string parsed reply, nil
|
||||
// nil 0, ErrNil
|
||||
// other 0, error
|
||||
func Int64(reply interface{}, err error) (int64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case int64:
|
||||
return reply, nil
|
||||
case []byte:
|
||||
n, err := strconv.ParseInt(string(reply), 10, 64)
|
||||
return n, err
|
||||
case nil:
|
||||
return 0, ErrNil
|
||||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Int64, got type %T", reply)
|
||||
}
|
||||
|
||||
var errNegativeInt = errors.New("ledis: unexpected value for Uint64")
|
||||
|
||||
// Uint64 is a helper that converts a command reply to 64 bit integer. If err is
|
||||
// not equal to nil, then Int returns 0, err. Otherwise, Int64 converts the
|
||||
// reply to an int64 as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// integer reply, nil
|
||||
// bulk string parsed reply, nil
|
||||
// nil 0, ErrNil
|
||||
// other 0, error
|
||||
func Uint64(reply interface{}, err error) (uint64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case int64:
|
||||
if reply < 0 {
|
||||
return 0, errNegativeInt
|
||||
}
|
||||
return uint64(reply), nil
|
||||
case []byte:
|
||||
n, err := strconv.ParseUint(string(reply), 10, 64)
|
||||
return n, err
|
||||
case nil:
|
||||
return 0, ErrNil
|
||||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Uint64, got type %T", reply)
|
||||
}
|
||||
|
||||
// Float64 is a helper that converts a command reply to 64 bit float. If err is
|
||||
// not equal to nil, then Float64 returns 0, err. Otherwise, Float64 converts
|
||||
// the reply to an int as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// bulk string parsed reply, nil
|
||||
// nil 0, ErrNil
|
||||
// other 0, error
|
||||
func Float64(reply interface{}, err error) (float64, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case []byte:
|
||||
n, err := strconv.ParseFloat(string(reply), 64)
|
||||
return n, err
|
||||
case nil:
|
||||
return 0, ErrNil
|
||||
case Error:
|
||||
return 0, reply
|
||||
}
|
||||
return 0, fmt.Errorf("ledis: unexpected type for Float64, got type %T", reply)
|
||||
}
|
||||
|
||||
// String is a helper that converts a command reply to a string. If err is not
|
||||
// equal to nil, then String returns "", err. Otherwise String converts the
|
||||
// reply to a string as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// bulk string string(reply), nil
|
||||
// simple string reply, nil
|
||||
// nil "", ErrNil
|
||||
// other "", error
|
||||
func String(reply interface{}, err error) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case []byte:
|
||||
return string(reply), nil
|
||||
case string:
|
||||
return reply, nil
|
||||
case nil:
|
||||
return "", ErrNil
|
||||
case Error:
|
||||
return "", reply
|
||||
}
|
||||
return "", fmt.Errorf("ledis: unexpected type for String, got type %T", reply)
|
||||
}
|
||||
|
||||
// Bytes is a helper that converts a command reply to a slice of bytes. If err
|
||||
// is not equal to nil, then Bytes returns nil, err. Otherwise Bytes converts
|
||||
// the reply to a slice of bytes as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// bulk string reply, nil
|
||||
// simple string []byte(reply), nil
|
||||
// nil nil, ErrNil
|
||||
// other nil, error
|
||||
func Bytes(reply interface{}, err error) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case []byte:
|
||||
return reply, nil
|
||||
case string:
|
||||
return []byte(reply), nil
|
||||
case nil:
|
||||
return nil, ErrNil
|
||||
case Error:
|
||||
return nil, reply
|
||||
}
|
||||
return nil, fmt.Errorf("ledis: unexpected type for Bytes, got type %T", reply)
|
||||
}
|
||||
|
||||
// Bool is a helper that converts a command reply to a boolean. If err is not
|
||||
// equal to nil, then Bool returns false, err. Otherwise Bool converts the
|
||||
// reply to boolean as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// integer value != 0, nil
|
||||
// bulk string strconv.ParseBool(reply)
|
||||
// nil false, ErrNil
|
||||
// other false, error
|
||||
func Bool(reply interface{}, err error) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case int64:
|
||||
return reply != 0, nil
|
||||
case []byte:
|
||||
return strconv.ParseBool(string(reply))
|
||||
case nil:
|
||||
return false, ErrNil
|
||||
case Error:
|
||||
return false, reply
|
||||
}
|
||||
return false, fmt.Errorf("ledis: unexpected type for Bool, got type %T", reply)
|
||||
}
|
||||
|
||||
// MultiBulk is deprecated. Use Values.
|
||||
func MultiBulk(reply interface{}, err error) ([]interface{}, error) { return Values(reply, err) }
|
||||
|
||||
// Values is a helper that converts an array command reply to a []interface{}.
|
||||
// If err is not equal to nil, then Values returns nil, err. Otherwise, Values
|
||||
// converts the reply as follows:
|
||||
//
|
||||
// Reply type Result
|
||||
// array reply, nil
|
||||
// nil nil, ErrNil
|
||||
// other nil, error
|
||||
func Values(reply interface{}, err error) ([]interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case []interface{}:
|
||||
return reply, nil
|
||||
case nil:
|
||||
return nil, ErrNil
|
||||
case Error:
|
||||
return nil, reply
|
||||
}
|
||||
return nil, fmt.Errorf("ledis: unexpected type for Values, got type %T", reply)
|
||||
}
|
||||
|
||||
// Strings is a helper that converts an array command reply to a []string. If
|
||||
// err is not equal to nil, then Strings returns nil, err. If one of the array
|
||||
// items is not a bulk string or nil, then Strings returns an error.
|
||||
func Strings(reply interface{}, err error) ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch reply := reply.(type) {
|
||||
case []interface{}:
|
||||
result := make([]string, len(reply))
|
||||
for i := range reply {
|
||||
if reply[i] == nil {
|
||||
continue
|
||||
}
|
||||
p, ok := reply[i].([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("ledis: unexpected element type for Strings, got type %T", reply[i])
|
||||
}
|
||||
result[i] = string(p)
|
||||
}
|
||||
return result, nil
|
||||
case nil:
|
||||
return nil, ErrNil
|
||||
case Error:
|
||||
return nil, reply
|
||||
}
|
||||
return nil, fmt.Errorf("ledis: unexpected type for Strings, got type %T", reply)
|
||||
}
|
Loading…
Reference in New Issue