Преглед изворни кода

Convert Conn to interface.

Gary Burd пре 13 година
родитељ
комит
65a3845eca
3 измењених фајлова са 115 додато и 53 уклоњено
  1. 18 38
      redis/conn.go
  2. 15 15
      redis/conn_test.go
  3. 82 0
      redis/redis.go

+ 18 - 38
redis/conn.go

@@ -12,10 +12,6 @@
 // License for the specific language governing permissions and limitations
 // under the License.
 
-// Package redis is a client for the Redis database.
-//
-// Package redis only supports the binary-safe Redis protocol, so you can use
-// it with any Redis version >= 1.2.0.
 package redis
 
 import (
@@ -29,20 +25,8 @@ import (
 	"time"
 )
 
-// Conn represents a connection to a Redis server.
-//
-// Conn objects are not thread-safe.
-//
-// The Conn Do and Receive methods return a Redis reply. The following table
-// shows how Redis reply types map to Go language types.
-// 
-//  Redis type          Go type
-//  Integer             int64
-//  Status              string
-//  Bulk                []byte or nil if value not present
-//  Multi-Bulk          []interface{} or nil if value not present
-//  Error               redis.Error
-type Conn struct {
+// conn is the low-level implementation of Conn
+type conn struct {
 	rw      bufio.ReadWriter
 	conn    net.Conn
 	err     error
@@ -50,7 +34,9 @@ type Conn struct {
 }
 
 // Dial connects to the Redis server at the given network and address.
-func Dial(network, address string) (*Conn, error) {
+// 
+// The returned connection is not thread-safe.
+func Dial(network, address string) (Conn, error) {
 	netConn, err := net.Dial(network, address)
 	if err != nil {
 		return nil, err
@@ -60,7 +46,7 @@ func Dial(network, address string) (*Conn, error) {
 
 // DialTimeout acts like Dial but takes a timeout. The timeout includes name
 // resolution, if required.
-func DialTimeout(network, address string, timeout time.Duration) (*Conn, error) {
+func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
 	netConn, err := net.DialTimeout(network, address, timeout)
 	if err != nil {
 		return nil, err
@@ -68,8 +54,8 @@ func DialTimeout(network, address string, timeout time.Duration) (*Conn, error)
 	return newConn(netConn), nil
 }
 
-func newConn(netConn net.Conn) *Conn {
-	return &Conn{
+func newConn(netConn net.Conn) Conn {
+	return &conn{
 		conn: netConn,
 		rw: bufio.ReadWriter{
 			bufio.NewReader(netConn),
@@ -79,24 +65,24 @@ func newConn(netConn net.Conn) *Conn {
 }
 
 // Close closes the connection.
-func (c *Conn) Close() error {
+func (c *conn) Close() error {
 	return c.conn.Close()
 }
 
 // Err returns the permanent error for this connection.
-func (c *Conn) Err() error {
+func (c *conn) Err() error {
 	return c.err
 }
 
 // Do sends a command to the server and returns the received reply.
-func (c *Conn) Do(cmd string, args ...interface{}) (interface{}, error) {
+func (c *conn) Do(cmd string, args ...interface{}) (interface{}, error) {
 	if err := c.Send(cmd, args...); err != nil {
 		return nil, err
 	}
 	return c.Receive()
 }
 
-func (c *Conn) writeN(prefix byte, n int) error {
+func (c *conn) writeN(prefix byte, n int) error {
 	c.scratch = append(c.scratch[0:0], prefix)
 	c.scratch = strconv.AppendInt(c.scratch, int64(n), 10)
 	c.scratch = append(c.scratch, "\r\n"...)
@@ -104,7 +90,7 @@ func (c *Conn) writeN(prefix byte, n int) error {
 	return err
 }
 
-func (c *Conn) writeString(s string) error {
+func (c *conn) writeString(s string) error {
 	if err := c.writeN('$', len(s)); err != nil {
 		return err
 	}
@@ -115,7 +101,7 @@ func (c *Conn) writeString(s string) error {
 	return err
 }
 
-func (c *Conn) writeBytes(p []byte) error {
+func (c *conn) writeBytes(p []byte) error {
 	if err := c.writeN('$', len(p)); err != nil {
 		return err
 	}
@@ -126,7 +112,7 @@ func (c *Conn) writeBytes(p []byte) error {
 	return err
 }
 
-func (c *Conn) readLine() ([]byte, error) {
+func (c *conn) readLine() ([]byte, error) {
 	p, err := c.rw.ReadSlice('\n')
 	if err == bufio.ErrBufferFull {
 		return nil, errors.New("redigo: long response line")
@@ -141,12 +127,7 @@ func (c *Conn) readLine() ([]byte, error) {
 	return p[:i], nil
 }
 
-// Error represets an error returned in a command reply.
-type Error string
-
-func (err Error) Error() string { return string(err) }
-
-func (c *Conn) parseReply() (interface{}, error) {
+func (c *conn) parseReply() (interface{}, error) {
 	line, err := c.readLine()
 	if err != nil {
 		return nil, err
@@ -201,7 +182,7 @@ func (c *Conn) parseReply() (interface{}, error) {
 }
 
 // Send sends a command for the server without waiting for a reply.
-func (c *Conn) Send(cmd string, args ...interface{}) error {
+func (c *conn) Send(cmd string, args ...interface{}) error {
 	if c.err != nil {
 		return c.err
 	}
@@ -237,7 +218,7 @@ func (c *Conn) Send(cmd string, args ...interface{}) error {
 }
 
 // Receive receives a single reply from the server
-func (c *Conn) Receive() (interface{}, error) {
+func (c *conn) Receive() (interface{}, error) {
 	c.err = c.rw.Flush()
 	if c.err != nil {
 		return nil, c.err
@@ -247,7 +228,6 @@ func (c *Conn) Receive() (interface{}, error) {
 		c.err = err
 	} else if e, ok := v.(Error); ok {
 		err = e
-		v = nil
 	}
 	return v, err
 }

+ 15 - 15
redis/conn_test.go

@@ -52,7 +52,7 @@ var sendTests = []struct {
 func TestSend(t *testing.T) {
 	for _, tt := range sendTests {
 		var buf bytes.Buffer
-		c := Conn{rw: bufio.ReadWriter{Writer: bufio.NewWriter(&buf)}}
+		c := conn{rw: bufio.ReadWriter{Writer: bufio.NewWriter(&buf)}}
 		err := c.Send(tt.args[0].(string), tt.args[1:]...)
 		if err != nil {
 			t.Errorf("Send(%v) returned error %v", tt.args, err)
@@ -112,7 +112,7 @@ var receiveTests = []struct {
 
 func TestReceive(t *testing.T) {
 	for _, tt := range receiveTests {
-		c := Conn{rw: bufio.ReadWriter{
+		c := conn{rw: bufio.ReadWriter{
 			Reader: bufio.NewReader(strings.NewReader(tt.reply)),
 			Writer: bufio.NewWriter(nil), // writer need to support Flush
 		}}
@@ -133,18 +133,18 @@ func TestReceive(t *testing.T) {
 	}
 }
 
-func connect() (*Conn, error) {
-	conn, err := Dial("tcp", ":6379")
+func connect() (Conn, error) {
+	c, err := Dial("tcp", ":6379")
 	if err != nil {
 		return nil, err
 	}
 
-	reply, err := conn.Do("SELECT", "9")
+	reply, err := c.Do("SELECT", "9")
 	if err != nil {
 		return nil, err
 	}
 
-	reply, err = conn.Do("DBSIZE")
+	reply, err = c.Do("DBSIZE")
 	if err != nil {
 		return nil, err
 	}
@@ -153,10 +153,10 @@ func connect() (*Conn, error) {
 		return nil, errors.New("Database #9 is not empty, test can not continue")
 	}
 
-	return conn, nil
+	return c, nil
 }
 
-func disconnect(c *Conn) error {
+func disconnect(c Conn) error {
 	_, err := c.Do("SELECT", "9")
 	if err != nil {
 		return nil
@@ -223,20 +223,20 @@ var testCommands = []struct {
 }
 
 func TestCommands(t *testing.T) {
-	conn, err := connect()
+	c, err := connect()
 	if err != nil {
 		t.Fatalf("Error connection to database, %v", err)
 	}
-	defer disconnect(conn)
+	defer disconnect(c)
 
-	for _, c := range testCommands {
-		actual, err := conn.Do(c.args[0].(string), c.args[1:]...)
+	for _, cmd := range testCommands {
+		actual, err := c.Do(cmd.args[0].(string), cmd.args[1:]...)
 		if err != nil {
-			t.Errorf("Do(%v) returned error %v", c.args, err)
+			t.Errorf("Do(%v) returned error %v", cmd.args, err)
 			continue
 		}
-		if !reflect.DeepEqual(actual, c.expected) {
-			t.Errorf("Do(%v) = %v, want %v", c.args, actual, c.expected)
+		if !reflect.DeepEqual(actual, cmd.expected) {
+			t.Errorf("Do(%v) = %v, want %v", cmd.args, actual, cmd.expected)
 		}
 	}
 }

+ 82 - 0
redis/redis.go

@@ -0,0 +1,82 @@
+// 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.
+
+// Package redis is a client for the Redis database.
+//
+// Package redis only supports the binary-safe Redis protocol, so you can use
+// it with any Redis version >= 1.2.0.
+package redis
+
+// Error represets an error returned in a command reply.
+type Error string
+
+func (err Error) Error() string { return string(err) }
+
+// Conn represents a connection to a Redis server.
+//
+// The Do method executes a Redis command. Command arguments of type string and
+// []byte are sent to the server as is. All other argument types are formatted
+// using the fmt.Fprint() function. Command replies are represented as Go types
+// as follows:
+// 
+//  Redis type          Go type
+//  error               redis.Error
+//  integer             int64
+//  status              string
+//  bulk                []byte or nil if value not present.
+//  multi-bulk          []interface{} or nil if value not present.
+//
+// Connections support pipelining using the Send and Receive methods. Send
+// formats and buffers outgoing commands. Receive flushes the outgoing command
+// buffer and reads an incoming reply. The following example shows a simple
+// pipeline:
+//
+//  c.Send("SET", "foo", "bar")
+//  c.Send("GET", "foo")
+//  // reply from SET
+//  if _, err := c.Receive(); err != nil {
+//      return err
+//  }
+//  // reply from GET
+//  v, err := c.Receive()
+//  if err != nil {
+//      return err
+//  }
+//  
+// This API can be used to implement a blocking subscriber:
+//
+//  c.Do("SUBSCRIBE", "foo")
+//  for {
+//      reply, err := c.Receive()
+//      if err != nil {
+//          // handle error
+//      }
+//      // consume message
+//  }
+type Conn interface {
+	// Close closes the connection.
+	Close() error
+
+	// Err returns the permanent error for this connection.
+	Err() error
+
+	// Do sends a command to the server and returns the received reply.
+	Do(cmd string, args ...interface{}) (reply interface{}, err error)
+
+	// Send sends a command for the server without waiting for a reply.
+	Send(cmd string, args ...interface{}) error
+
+	// Receive receives a single reply from the server
+	Receive() (reply interface{}, err error)
+}