[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#841081: RFP: golang-gopkg-dancannon-gorethink.v1 -- RethinkDB driver for Go



Package: wnpp
Severity: wishlist
Tags: patch
Control: block 793749 by -1

* Package name    : golang-gopkg-dancannon-gorethink.v1
  Version         : 1.4.1
  Upstream Author : Daniel Cannon <daniel@danielcannon.co.uk>
* URL             : https://github.com/dancannon/gorethink
* License         : Apache-2.0
  Programming Lang: Go
  Description     : RethinkDB driver for Go

 RethinkDB >= 2.0 compatible driver. The driver uses a connection
 pool at all times, by default it creates and frees connections
 automatically. It's safe for concurrent use by multiple goroutines.


This package is a dependency of telegraf latest upstream releases, it
was already in the archive but got removed due to being unused. See
<https://bugs.debian.org/829277>.


Attached a working and tested packaging, where only the ITP bug number
needs to be filled in the debian/changelog. The other patch is required
to get the git repository back to a proper upstream version, because it
was at v2 now.

Thanks,
Guillem
From a0006f79e905db75aeb673ff08344ba3fc3dfa17 Mon Sep 17 00:00:00 2001
From: Guillem Jover <gjover@sipwise.com>
Date: Mon, 17 Oct 2016 13:59:45 +0200
Subject: [PATCH 1/2] Revert import of v2.0.1 back to v1.4.1

---
 .travis.yml                       |   2 -
 CHANGELOG.md                      |  40 ----
 README.md                         |  33 +--
 checkers_test.go                  |   2 +-
 cluster.go                        |  43 ++--
 connection.go                     |  20 +-
 connection_handshake.go           | 450 --------------------------------------
 connection_helper.go              |  55 ++++-
 cursor.go                         | 262 +++++++---------------
 cursor_test.go                    |  86 --------
 doc.go                            |   2 +-
 encoding/encoder_test.go          |  23 --
 encoding/encoder_types.go         |  69 ++----
 errors.go                         |   2 +-
 example_query_aggregation_test.go |  30 +--
 gorethink.go                      |   2 +-
 gorethink_test.go                 |   4 +
 node.go                           |   2 +-
 pseudotypes.go                    |   2 +-
 ql2/ql2.pb.go                     |  15 +-
 ql2/ql2.proto                     |  15 +-
 query.go                          |  28 +--
 query_admin.go                    |  12 +-
 query_admin_test.go               |  32 +--
 query_aggregation.go              |  44 +---
 query_aggregation_test.go         |  41 +---
 query_control.go                  |   2 +-
 query_db.go                       |   2 +-
 query_geospatial.go               |   2 +-
 query_geospatial_test.go          |   2 +-
 query_join.go                     |   5 +-
 query_join_test.go                |   7 +-
 query_manipulation.go             |   2 +-
 query_math.go                     |   2 +-
 query_select.go                   |   2 +-
 query_select_test.go              |  12 +-
 query_string.go                   |   2 +-
 query_table.go                    |   4 +-
 query_table_test.go               |   1 +
 query_test.go                     |  17 --
 query_time.go                     |   2 +-
 query_transformation.go           |  23 +-
 query_write.go                    |   3 +-
 session.go                        |  11 +-
 session_test.go                   |  58 +----
 utils.go                          |   5 +-
 46 files changed, 270 insertions(+), 1210 deletions(-)
 delete mode 100644 connection_handshake.go

diff --git a/.travis.yml b/.travis.yml
index 342c4db..2870132 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,8 +6,6 @@ go:
 
 cache: apt
 
-go_import_path: gopkg.in/dancannon/gorethink.v2
-
 before_script:
   - source /etc/lsb-release && echo "deb http://download.rethinkdb.com/apt $DISTRIB_CODENAME main" | sudo tee /etc/apt/sources.list.d/rethinkdb.list
   - wget -qO- http://download.rethinkdb.com/apt/pubkey.gpg | sudo apt-key add -
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d1aaae..0ac94f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,46 +2,6 @@
 All notable changes to this project will be documented in this file.
 This project adheres to [Semantic Versioning](http://semver.org/).
 
-## v2.0.1 - 2016-04-14
-
-### Added
- - Added `UnionWithOpts` term which allows `Union` to be called with optional arguments (such as `Interleave`)
- - Added `IncludeOffsets` and `IncludeTypes` optional arguments to `ChangesOpts`
- - Added `Conflict` optional argument to `InsertOpts`
-
-### Fixed
- - Fixed error when connecting to database as non-admin user, please note that `DiscoverHosts` will not work with user authentication at this time due to the fact that RethinkDB restricts access to the required system tables.
-
-## v2.0.0 - 2016-04-13
-
-### Changed
-
- - GoRethink now uses the v1.0 RethinkDB protocol which supports RethinkDB v2.3 and above. If you are using RethinkDB 2.2 or older please set `HandshakeVersion` when creating a session. For example:
-```go
-r.Connect(
-    ...
-    HandshakeVersion: r.HandshakeV0_4,
-    ...
-)
-```
-
-### Added
- - Added support for username/password authentication. To login pass your username and password when creating a session using the `Username` and `Password` fields in the `ConnectOpts`.
- - Added the `Grant` term
- - Added the `Ordered` optional argument to `EqJoin`
- - Added the `Fold` term and examples
- - Added the `ReadOne` and `ReadAll` helper functions for quickly executing a query and scanning the result into a variable. For examples see the godocs.
- - Added the `Peek` and `Skip` functions to the `Cursor`.
- - Added support for referential arrays in structs
- - Added the `Durability` argument to `RunOpts`/`ExecOpts`
-
-### Deprecated
- - Deprecated the root `Wait` term, `r.Table(...).Wait()` should now be used instead.
- - Deprecated session authentication using `AuthKey` 
-
-### Fixed
- - Fixed issue with `ReconfigureOpts` field `PrimaryTag`
-
 ## v1.4.1 - 2016-04-02
 
 ### Fixed
diff --git a/README.md b/README.md
index 41893d8..159d37f 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@
 
 ![GoRethink Logo](https://raw.github.com/wiki/dancannon/gorethink/gopher-and-thinker-s.png "Golang Gopher and RethinkDB Thinker")
 
-Current version: v2.0.1 (RethinkDB v2.3)
+Current version: v1.4.1 (RethinkDB v2.2)
 
 Please note that this version of the driver only supports versions of RethinkDB using the v0.4 protocol (any versions of the driver older than RethinkDB 2.0 will not work).
 
@@ -22,7 +22,7 @@ go get -u github.com/dancannon/gorethink
 
 Or (pinned to the v1.x.x tag)
 ```
-go get gopkg.in/dancannon/gorethink.v2
+go get gopkg.in/dancannon/gorethink.v1
 ```
 
 ## Connection
@@ -91,35 +91,6 @@ if err != nil {
 
 When `DiscoverHosts` is true any nodes are added to the cluster after the initial connection then the new node will be added to the pool of available nodes used by GoRethink. Unfortunately the canonical address of each server in the cluster **MUST** be set as otherwise clients will try to connect to the database nodes locally. For more information about how to set a RethinkDB servers canonical address set this page http://www.rethinkdb.com/docs/config-file/.
 
-## User Authentication
-
-To login with a username and password you should first create a user, this can be done by writing to the `users` system table and then grant that user access to any tables or databases they need access to. This queries can also be executed in the RethinkDB admin console.
-
-```go
-err := r.DB("rethinkdb").Table("users").Insert(map[string]string{
-    "id": "john",
-    "password": "p455w0rd",
-}).Exec(session)
-...
-err = r.DB("blog").Table("posts").Grant("john", map[string]bool{
-    "read": true,
-    "write": true,
-}).Exec(session)
-...
-```
-
-Finally the username and password should be passed to `Connect` when creating your session, for example:
-
-```go
-session, err := r.Connect(r.ConnectOpts{
-    Address: "localhost:28015",
-    Database: "blog",
-    Username: "john",
-    Password: "p455w0rd",
-})
-```
-
-Please note that `DiscoverHosts` will not work with user authentication at this time due to the fact that RethinkDB restricts access to the required system tables.
 
 ## Query Functions
 
diff --git a/checkers_test.go b/checkers_test.go
index ab10fa9..5a0bcac 100644
--- a/checkers_test.go
+++ b/checkers_test.go
@@ -6,7 +6,7 @@ import (
 
 	test "gopkg.in/check.v1"
 
-	"gopkg.in/dancannon/gorethink.v2/types"
+	"gopkg.in/dancannon/gorethink.v1/types"
 )
 
 type jsonChecker struct {
diff --git a/cluster.go b/cluster.go
index 76ae683..f4945bb 100644
--- a/cluster.go
+++ b/cluster.go
@@ -222,23 +222,28 @@ func (c *Cluster) connectNodes(hosts []Host) {
 		}
 		defer conn.Close()
 
-		if c.opts.DiscoverHosts {
-			q, err := newQuery(
-				DB("rethinkdb").Table("server_status"),
-				map[string]interface{}{},
-				c.opts,
-			)
-			if err != nil {
-				Log.Warnf("Error building query: %s", err)
-				continue
-			}
+		q, err := newQuery(
+			DB("rethinkdb").Table("server_status"),
+			map[string]interface{}{},
+			c.opts,
+		)
+		if err != nil {
+			Log.Warnf("Error building query: %s", err)
+			continue
+		}
 
-			_, cursor, err := conn.Query(q)
-			if err != nil {
-				Log.Warnf("Error fetching cluster status: %s", err)
-				continue
-			}
+		_, cursor, err := conn.Query(q)
+		if err != nil {
+			Log.Warnf("Error fetching cluster status: %s", err)
+			continue
+		}
+
+		// TODO: connect to seed hosts using `.Server()` to get server ID. Need
+		// some way of making this backwards compatible
+
+		// TODO: AFTER try to discover hosts
 
+		if c.opts.DiscoverHosts {
 			var results []nodeStatus
 			err = cursor.All(&results)
 			if err != nil {
@@ -260,13 +265,7 @@ func (c *Cluster) connectNodes(hosts []Host) {
 				}
 			}
 		} else {
-			svrRsp, err := conn.Server()
-			if err != nil {
-				Log.Warnf("Error fetching server ID: %s", err)
-				continue
-			}
-
-			node, err := c.connectNode(svrRsp.ID, []Host{host})
+			node, err := c.connectNode(host.String(), []Host{host})
 			if err == nil {
 				if _, ok := nodeSet[node.ID]; !ok {
 					Log.WithFields(logrus.Fields{
diff --git a/connection.go b/connection.go
index b4e58db..d103cf7 100644
--- a/connection.go
+++ b/connection.go
@@ -9,7 +9,7 @@ import (
 	"sync/atomic"
 	"time"
 
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 const (
@@ -63,14 +63,16 @@ func NewConnection(address string, opts *ConnectOpts) (*Connection, error) {
 		return nil, RQLConnectionError{rqlError(err.Error())}
 	}
 
-	// Send handshake
-	handshake, err := c.handshake(opts.HandshakeVersion)
-	if err != nil {
-		return nil, err
+	// Send handshake request
+	if err = c.writeHandshakeReq(); err != nil {
+		c.Close()
+		return nil, RQLConnectionError{rqlError(err.Error())}
 	}
-
-	if err = handshake.Send(); err != nil {
-		return nil, err
+	// Read handshake response
+	err = c.readHandshakeSuccess()
+	if err != nil {
+		c.Close()
+		return nil, RQLConnectionError{rqlError(err.Error())}
 	}
 
 	return c, nil
@@ -110,8 +112,6 @@ func (c *Connection) Query(q Query) (*Response, *Cursor, error) {
 	// Add token if query is a START/NOREPLY_WAIT
 	if q.Type == p.Query_START || q.Type == p.Query_NOREPLY_WAIT || q.Type == p.Query_SERVER_INFO {
 		q.Token = c.nextToken()
-	}
-	if q.Type == p.Query_START || q.Type == p.Query_NOREPLY_WAIT {
 		if c.opts.Database != "" {
 			var err error
 			q.Opts["db"], err = DB(c.opts.Database).build()
diff --git a/connection_handshake.go b/connection_handshake.go
deleted file mode 100644
index c825674..0000000
--- a/connection_handshake.go
+++ /dev/null
@@ -1,450 +0,0 @@
-package gorethink
-
-import (
-	"bufio"
-	"crypto/hmac"
-	"crypto/rand"
-	"crypto/sha256"
-	"encoding/base64"
-	"encoding/binary"
-	"encoding/json"
-	"fmt"
-	"hash"
-	"io"
-	"strconv"
-	"strings"
-
-	"golang.org/x/crypto/pbkdf2"
-
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
-)
-
-type HandshakeVersion int
-
-const (
-	HandshakeV1_0 HandshakeVersion = iota
-	HandshakeV0_4
-)
-
-type connectionHandshake interface {
-	Send() error
-}
-
-func (c *Connection) handshake(version HandshakeVersion) (connectionHandshake, error) {
-	switch version {
-	case HandshakeV0_4:
-		return &connectionHandshakeV0_4{conn: c}, nil
-	case HandshakeV1_0:
-		return &connectionHandshakeV1_0{conn: c}, nil
-	default:
-		return nil, fmt.Errorf("Unrecognised handshake version")
-	}
-}
-
-type connectionHandshakeV0_4 struct {
-	conn *Connection
-}
-
-func (c *connectionHandshakeV0_4) Send() error {
-	// Send handshake request
-	if err := c.writeHandshakeReq(); err != nil {
-		c.conn.Close()
-		return RQLConnectionError{rqlError(err.Error())}
-	}
-	// Read handshake response
-	if err := c.readHandshakeSuccess(); err != nil {
-		c.conn.Close()
-		return RQLConnectionError{rqlError(err.Error())}
-	}
-
-	return nil
-}
-
-func (c *connectionHandshakeV0_4) writeHandshakeReq() error {
-	pos := 0
-	dataLen := 4 + 4 + len(c.conn.opts.AuthKey) + 4
-	data := make([]byte, dataLen)
-
-	// Send the protocol version to the server as a 4-byte little-endian-encoded integer
-	binary.LittleEndian.PutUint32(data[pos:], uint32(p.VersionDummy_V0_4))
-	pos += 4
-
-	// Send the length of the auth key to the server as a 4-byte little-endian-encoded integer
-	binary.LittleEndian.PutUint32(data[pos:], uint32(len(c.conn.opts.AuthKey)))
-	pos += 4
-
-	// Send the auth key as an ASCII string
-	if len(c.conn.opts.AuthKey) > 0 {
-		pos += copy(data[pos:], c.conn.opts.AuthKey)
-	}
-
-	// Send the protocol type as a 4-byte little-endian-encoded integer
-	binary.LittleEndian.PutUint32(data[pos:], uint32(p.VersionDummy_JSON))
-	pos += 4
-
-	return c.conn.writeData(data)
-}
-
-func (c *connectionHandshakeV0_4) readHandshakeSuccess() error {
-	reader := bufio.NewReader(c.conn.Conn)
-	line, err := reader.ReadBytes('\x00')
-	if err != nil {
-		if err == io.EOF {
-			return fmt.Errorf("Unexpected EOF: %s", string(line))
-		}
-		return err
-	}
-	// convert to string and remove trailing NUL byte
-	response := string(line[:len(line)-1])
-	if response != "SUCCESS" {
-		response = strings.TrimSpace(response)
-		// we failed authorization or something else terrible happened
-		return RQLDriverError{rqlError(fmt.Sprintf("Server dropped connection with message: \"%s\"", response))}
-	}
-
-	return nil
-}
-
-const (
-	handshakeV1_0_protocolVersionNumber = 0
-	handshakeV1_0_authenticationMethod  = "SCRAM-SHA-256"
-)
-
-type connectionHandshakeV1_0 struct {
-	conn   *Connection
-	reader *bufio.Reader
-
-	authMsg string
-}
-
-func (c *connectionHandshakeV1_0) Send() error {
-	c.reader = bufio.NewReader(c.conn.Conn)
-
-	// Generate client nonce
-	clientNonce, err := c.generateNonce()
-	if err != nil {
-		c.conn.Close()
-		return RQLDriverError{rqlError(fmt.Sprintf("Failed to generate client nonce: %s", err))}
-	}
-	// Send client first message
-	if err := c.writeFirstMessage(clientNonce); err != nil {
-		c.conn.Close()
-		return err
-	}
-	// Read status
-	if err := c.checkServerVersions(); err != nil {
-		c.conn.Close()
-		return err
-	}
-
-	// Read server first message
-	i, salt, serverNonce, err := c.readFirstMessage()
-	if err != nil {
-		c.conn.Close()
-		return err
-	}
-
-	// Check server nonce
-	if !strings.HasPrefix(serverNonce, clientNonce) {
-		return RQLAuthError{RQLDriverError{rqlError("Invalid nonce from server")}}
-	}
-
-	// Generate proof
-	saltedPass := c.saltPassword(i, salt)
-	clientProof := c.calculateProof(saltedPass, clientNonce, serverNonce)
-	serverSignature := c.serverSignature(saltedPass)
-
-	// Send client final message
-	if err := c.writeFinalMessage(serverNonce, clientProof); err != nil {
-		c.conn.Close()
-		return err
-	}
-	// Read server final message
-	if err := c.readFinalMessage(serverSignature); err != nil {
-		c.conn.Close()
-		return err
-	}
-
-	return nil
-}
-
-func (c *connectionHandshakeV1_0) writeFirstMessage(clientNonce string) error {
-	// Default username to admin if not set
-	username := "admin"
-	if c.conn.opts.Username != "" {
-		username = c.conn.opts.Username
-	}
-
-	c.authMsg = fmt.Sprintf("n=%s,r=%s", username, clientNonce)
-	msg := fmt.Sprintf(
-		`{"protocol_version": %d,"authentication": "n,,%s","authentication_method": "%s"}`,
-		handshakeV1_0_protocolVersionNumber, c.authMsg, handshakeV1_0_authenticationMethod,
-	)
-
-	pos := 0
-	dataLen := 4 + len(msg) + 1
-	data := make([]byte, dataLen)
-
-	// Send the protocol version to the server as a 4-byte little-endian-encoded integer
-	binary.LittleEndian.PutUint32(data[pos:], uint32(p.VersionDummy_V1_0))
-	pos += 4
-
-	// Send the auth message as an ASCII string
-	pos += copy(data[pos:], msg)
-
-	// Add null terminating byte
-	data[pos] = '\x00'
-
-	return c.writeData(data)
-}
-
-func (c *connectionHandshakeV1_0) checkServerVersions() error {
-	b, err := c.readResponse()
-	if err != nil {
-		return err
-	}
-
-	// Read status
-	type versionsResponse struct {
-		Success            bool   `json:"success"`
-		MinProtocolVersion int    `json:"min_protocol_version"`
-		MaxProtocolVersion int    `json:"max_protocol_version"`
-		ServerVersion      string `json:"server_version"`
-		ErrorCode          int    `json:"error_code"`
-		Error              string `json:"error"`
-	}
-	var rsp *versionsResponse
-	statusStr := string(b)
-
-	if err := json.Unmarshal(b, &rsp); err != nil {
-		if strings.HasPrefix(statusStr, "ERROR: ") {
-			statusStr = strings.TrimPrefix(statusStr, "ERROR: ")
-			return RQLConnectionError{rqlError(statusStr)}
-		}
-
-		return RQLDriverError{rqlError(fmt.Sprintf("Error reading versions: %s", err))}
-	}
-
-	if !rsp.Success {
-		return c.handshakeError(rsp.ErrorCode, rsp.Error)
-	}
-	if rsp.MinProtocolVersion > handshakeV1_0_protocolVersionNumber ||
-		rsp.MaxProtocolVersion < handshakeV1_0_protocolVersionNumber {
-		return RQLDriverError{rqlError(
-			fmt.Sprintf(
-				"Unsupported protocol version %d, expected between %d and %d.",
-				handshakeV1_0_protocolVersionNumber,
-				rsp.MinProtocolVersion,
-				rsp.MaxProtocolVersion,
-			),
-		)}
-	}
-
-	return nil
-}
-
-func (c *connectionHandshakeV1_0) readFirstMessage() (i int64, salt []byte, serverNonce string, err error) {
-	b, err2 := c.readResponse()
-	if err2 != nil {
-		err = err2
-		return
-	}
-
-	// Read server message
-	type firstMessageResponse struct {
-		Success        bool   `json:"success"`
-		Authentication string `json:"authentication"`
-		ErrorCode      int    `json:"error_code"`
-		Error          string `json:"error"`
-	}
-	var rsp *firstMessageResponse
-
-	if err2 := json.Unmarshal(b, &rsp); err2 != nil {
-		err = RQLDriverError{rqlError(fmt.Sprintf("Error parsing auth response: %s", err2))}
-		return
-	}
-	if !rsp.Success {
-		err = c.handshakeError(rsp.ErrorCode, rsp.Error)
-		return
-	}
-
-	c.authMsg += ","
-	c.authMsg += rsp.Authentication
-
-	// Parse authentication field
-	auth := map[string]string{}
-	parts := strings.Split(rsp.Authentication, ",")
-	for _, part := range parts {
-		i := strings.Index(part, "=")
-		if i != -1 {
-			auth[part[:i]] = part[i+1:]
-		}
-	}
-
-	// Extract return values
-	if v, ok := auth["i"]; ok {
-		i, err = strconv.ParseInt(v, 10, 64)
-		if err != nil {
-			return
-		}
-	}
-	if v, ok := auth["s"]; ok {
-		salt, err = base64.StdEncoding.DecodeString(v)
-		if err != nil {
-			return
-		}
-	}
-	if v, ok := auth["r"]; ok {
-		serverNonce = v
-	}
-
-	return
-}
-
-func (c *connectionHandshakeV1_0) writeFinalMessage(serverNonce, clientProof string) error {
-	authMsg := "c=biws,r="
-	authMsg += serverNonce
-	authMsg += ",p="
-	authMsg += clientProof
-
-	msg := fmt.Sprintf(`{"authentication": "%s"}`, authMsg)
-
-	pos := 0
-	dataLen := len(msg) + 1
-	data := make([]byte, dataLen)
-
-	// Send the auth message as an ASCII string
-	pos += copy(data[pos:], msg)
-
-	// Add null terminating byte
-	data[pos] = '\x00'
-
-	return c.writeData(data)
-}
-
-func (c *connectionHandshakeV1_0) readFinalMessage(serverSignature string) error {
-	b, err := c.readResponse()
-	if err != nil {
-		return err
-	}
-
-	// Read server message
-	type finalMessageResponse struct {
-		Success        bool   `json:"success"`
-		Authentication string `json:"authentication"`
-		ErrorCode      int    `json:"error_code"`
-		Error          string `json:"error"`
-	}
-	var rsp *finalMessageResponse
-
-	if err := json.Unmarshal(b, &rsp); err != nil {
-		return RQLDriverError{rqlError(fmt.Sprintf("Error parsing auth response: %s", err))}
-	}
-	if !rsp.Success {
-		return c.handshakeError(rsp.ErrorCode, rsp.Error)
-	}
-
-	// Parse authentication field
-	auth := map[string]string{}
-	parts := strings.Split(rsp.Authentication, ",")
-	for _, part := range parts {
-		i := strings.Index(part, "=")
-		if i != -1 {
-			auth[part[:i]] = part[i+1:]
-		}
-	}
-
-	// Validate server response
-	if serverSignature != auth["v"] {
-		return RQLAuthError{RQLDriverError{rqlError("Invalid server signature")}}
-	}
-
-	return nil
-}
-
-func (c *connectionHandshakeV1_0) writeData(data []byte) error {
-
-	if err := c.conn.writeData(data); err != nil {
-		return RQLConnectionError{rqlError(err.Error())}
-	}
-
-	return nil
-}
-
-func (c *connectionHandshakeV1_0) readResponse() ([]byte, error) {
-	line, err := c.reader.ReadBytes('\x00')
-	if err != nil {
-		if err == io.EOF {
-			return nil, RQLConnectionError{rqlError(fmt.Sprintf("Unexpected EOF: %s", string(line)))}
-		}
-		return nil, RQLConnectionError{rqlError(err.Error())}
-	}
-
-	// Strip null byte and return
-	return line[:len(line)-1], nil
-}
-
-func (c *connectionHandshakeV1_0) generateNonce() (string, error) {
-	const nonceSize = 24
-
-	b := make([]byte, nonceSize)
-	_, err := rand.Read(b)
-	if err != nil {
-		return "", err
-	}
-
-	return base64.StdEncoding.EncodeToString(b), nil
-}
-
-func (c *connectionHandshakeV1_0) saltPassword(iter int64, salt []byte) []byte {
-	pass := []byte(c.conn.opts.Password)
-
-	return pbkdf2.Key(pass, salt, int(iter), sha256.Size, sha256.New)
-}
-
-func (c *connectionHandshakeV1_0) calculateProof(saltedPass []byte, clientNonce, serverNonce string) string {
-	// Generate proof
-	c.authMsg += ",c=biws,r=" + serverNonce
-
-	mac := hmac.New(c.hashFunc(), saltedPass)
-	mac.Write([]byte("Client Key"))
-	clientKey := mac.Sum(nil)
-
-	hash := c.hashFunc()()
-	hash.Write(clientKey)
-	storedKey := hash.Sum(nil)
-
-	mac = hmac.New(c.hashFunc(), storedKey)
-	mac.Write([]byte(c.authMsg))
-	clientSignature := mac.Sum(nil)
-	clientProof := make([]byte, len(clientKey))
-	for i, _ := range clientKey {
-		clientProof[i] = clientKey[i] ^ clientSignature[i]
-	}
-
-	return base64.StdEncoding.EncodeToString(clientProof)
-}
-
-func (c *connectionHandshakeV1_0) serverSignature(saltedPass []byte) string {
-	mac := hmac.New(c.hashFunc(), saltedPass)
-	mac.Write([]byte("Server Key"))
-	serverKey := mac.Sum(nil)
-
-	mac = hmac.New(c.hashFunc(), serverKey)
-	mac.Write([]byte(c.authMsg))
-	serverSignature := mac.Sum(nil)
-
-	return base64.StdEncoding.EncodeToString(serverSignature)
-}
-
-func (c *connectionHandshakeV1_0) handshakeError(code int, message string) error {
-	if code >= 10 || code <= 20 {
-		return RQLAuthError{RQLDriverError{rqlError(message)}}
-	} else {
-		return RQLDriverError{rqlError(message)}
-	}
-}
-
-func (c *connectionHandshakeV1_0) hashFunc() func() hash.Hash {
-	return sha256.New
-}
diff --git a/connection_helper.go b/connection_helper.go
index a35522c..7634af7 100644
--- a/connection_helper.go
+++ b/connection_helper.go
@@ -1,6 +1,14 @@
 package gorethink
 
-import "encoding/binary"
+import (
+	"bufio"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"strings"
+
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
+)
 
 // Write 'data' to conn
 func (c *Connection) writeData(data []byte) error {
@@ -12,6 +20,51 @@ func (c *Connection) writeData(data []byte) error {
 	return nil
 }
 
+func (c *Connection) writeHandshakeReq() error {
+	pos := 0
+	dataLen := 4 + 4 + len(c.opts.AuthKey) + 4
+	data := make([]byte, dataLen)
+
+	// Send the protocol version to the server as a 4-byte little-endian-encoded integer
+	binary.LittleEndian.PutUint32(data[pos:], uint32(p.VersionDummy_V0_4))
+	pos += 4
+
+	// Send the length of the auth key to the server as a 4-byte little-endian-encoded integer
+	binary.LittleEndian.PutUint32(data[pos:], uint32(len(c.opts.AuthKey)))
+	pos += 4
+
+	// Send the auth key as an ASCII string
+	if len(c.opts.AuthKey) > 0 {
+		pos += copy(data[pos:], c.opts.AuthKey)
+	}
+
+	// Send the protocol type as a 4-byte little-endian-encoded integer
+	binary.LittleEndian.PutUint32(data[pos:], uint32(p.VersionDummy_JSON))
+	pos += 4
+
+	return c.writeData(data)
+}
+
+func (c *Connection) readHandshakeSuccess() error {
+	reader := bufio.NewReader(c.Conn)
+	line, err := reader.ReadBytes('\x00')
+	if err != nil {
+		if err == io.EOF {
+			return fmt.Errorf("Unexpected EOF: %s", string(line))
+		}
+		return err
+	}
+	// convert to string and remove trailing NUL byte
+	response := string(line[:len(line)-1])
+	if response != "SUCCESS" {
+		response = strings.TrimSpace(response)
+		// we failed authorization or something else terrible happened
+		return RQLDriverError{rqlError(fmt.Sprintf("Server dropped connection with message: \"%s\"", response))}
+	}
+
+	return nil
+}
+
 func (c *Connection) read(buf []byte, length int) (total int, err error) {
 	var n int
 	for total < length {
diff --git a/cursor.go b/cursor.go
index 29c53f4..aa11ff1 100644
--- a/cursor.go
+++ b/cursor.go
@@ -7,8 +7,8 @@ import (
 	"reflect"
 	"sync"
 
-	"gopkg.in/dancannon/gorethink.v2/encoding"
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	"gopkg.in/dancannon/gorethink.v1/encoding"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 var (
@@ -57,16 +57,15 @@ type Cursor struct {
 	term       *Term
 	opts       map[string]interface{}
 
-	mu           sync.RWMutex
-	lastErr      error
-	fetching     bool
-	closed       bool
-	finished     bool
-	isAtom       bool
-	pendingSkips int
-	buffer       []interface{}
-	responses    []json.RawMessage
-	profile      interface{}
+	mu        sync.RWMutex
+	lastErr   error
+	fetching  bool
+	closed    bool
+	finished  bool
+	isAtom    bool
+	buffer    []interface{}
+	responses []json.RawMessage
+	profile   interface{}
 }
 
 // Profile returns the information returned from the query profiler.
@@ -164,7 +163,7 @@ func (c *Cursor) Next(dest interface{}) bool {
 		return false
 	}
 
-	hasMore, err := c.nextLocked(dest, true)
+	hasMore, err := c.nextLocked(dest)
 	if c.handleErrorLocked(err) != nil {
 		c.mu.Unlock()
 		c.Close()
@@ -179,82 +178,78 @@ func (c *Cursor) Next(dest interface{}) bool {
 	return hasMore
 }
 
-func (c *Cursor) nextLocked(dest interface{}, progressCursor bool) (bool, error) {
+func (c *Cursor) nextLocked(dest interface{}) (bool, error) {
 	for {
-		if err := c.seekCursor(true); err != nil {
-			return false, err
+		if c.lastErr != nil {
+			return false, c.lastErr
 		}
 
-		if len(c.buffer) == 0 && c.finished {
+		// Check if response is closed/finished
+		if len(c.buffer) == 0 && len(c.responses) == 0 && c.closed {
+			return false, errCursorClosed
+		}
+
+		if len(c.buffer) == 0 && len(c.responses) == 0 && !c.finished {
+			err := c.fetchMore()
+			if err != nil {
+				return false, err
+			}
+			// Check if cursor was closed while fetching results
+			if c.closed {
+				return false, nil
+			}
+		}
+
+		if len(c.buffer) == 0 && len(c.responses) == 0 && c.finished {
 			return false, nil
 		}
 
-		if len(c.buffer) > 0 {
-			data := c.buffer[0]
-			if progressCursor {
-				c.buffer = c.buffer[1:]
+		if len(c.buffer) == 0 && len(c.responses) > 0 {
+			var response json.RawMessage
+			response, c.responses = c.responses[0], c.responses[1:]
+
+			var value interface{}
+			decoder := json.NewDecoder(bytes.NewBuffer(response))
+			if c.conn.opts.UseJSONNumber {
+				decoder.UseNumber()
+			}
+			err := decoder.Decode(&value)
+			if err != nil {
+				return false, err
 			}
 
-			err := encoding.Decode(dest, data)
+			value, err = recursivelyConvertPseudotype(value, c.opts)
 			if err != nil {
 				return false, err
 			}
 
-			return true, nil
+			// If response is an ATOM then try and convert to an array
+			if data, ok := value.([]interface{}); ok && c.isAtom {
+				for _, v := range data {
+					c.buffer = append(c.buffer, v)
+				}
+			} else if value == nil {
+				c.buffer = append(c.buffer, nil)
+			} else {
+				c.buffer = append(c.buffer, value)
+			}
 		}
-	}
-}
 
-// Peek behaves similarly to Next, retreiving the next document from the result set
-// and blocking if necessary. Peek, however, does not progress the position of the cursor.
-// This can be useful for expressions which can return different types to attempt to
-// decode them into different interfaces.
-//
-// Like Next, it will also automatically retrieve another batch of documents from
-// the server when the current one is exhausted, or before that in background
-// if possible.
-//
-// Unlike Next, Peek does not progress the position of the cursor. Peek
-// will return errors from decoding, but they will not be persisted in the cursor
-// and therefore will not be available on cursor.Err(). This can be useful for
-// expressions that can return different types to attempt to decode them into
-// different interfaces.
-//
-// Peek returns true if a document was successfully unmarshalled onto result,
-// and false at the end of the result set or if an error happened. Peek also
-// returns the error (if any) that occured
-func (c *Cursor) Peek(dest interface{}) (bool, error) {
-	c.mu.Lock()
-	if c.closed {
-		c.mu.Unlock()
-		return false, nil
-	}
+		if len(c.buffer) > 0 {
+			var data interface{}
+			data, c.buffer = c.buffer[0], c.buffer[1:]
 
-	hasMore, err := c.nextLocked(dest, false)
-	if _, isDecodeErr := err.(*encoding.DecodeTypeError); isDecodeErr {
-		c.mu.Unlock()
-		return false, err
-	}
+			err := encoding.Decode(dest, data)
+			if err != nil {
+				return false, err
+			}
 
-	if c.handleErrorLocked(err) != nil {
-		c.mu.Unlock()
-		c.Close()
-		return false, err
+			return true, nil
+		}
 	}
-	c.mu.Unlock()
-
-	return hasMore, nil
 }
 
-// Skip progresses the cursor by one record. It is useful after a successful
-// Peek to avoid duplicate decoding work.
-func (c *Cursor) Skip() {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-	c.pendingSkips++
-}
-
-// NextResponse retrieves the next raw response from the result set, blocking if necessary.
+// Next retrieves the next raw response from the result set, blocking if necessary.
 // Unlike Next the returned response is the raw JSON document returned from the
 // database.
 //
@@ -284,8 +279,24 @@ func (c *Cursor) NextResponse() ([]byte, bool) {
 
 func (c *Cursor) nextResponseLocked() ([]byte, bool, error) {
 	for {
-		if err := c.seekCursor(false); err != nil {
-			return nil, false, err
+		if c.lastErr != nil {
+			return nil, false, c.lastErr
+		}
+
+		// Check if response is closed/finished
+		if len(c.responses) == 0 && c.closed {
+			return nil, false, errCursorClosed
+		}
+
+		if len(c.responses) == 0 && !c.finished {
+			err := c.fetchMore()
+			if err != nil {
+				return nil, false, err
+			}
+			// Check if cursor was closed while fetching results
+			if c.closed {
+				return nil, false, nil
+			}
 		}
 
 		if len(c.responses) == 0 && c.finished {
@@ -510,110 +521,3 @@ func (c *Cursor) extendLocked(response *Response) {
 
 	putResponse(response)
 }
-
-// seekCursor takes care of loading more data if needed and applying pending skips
-//
-// bufferResponse determines whether the response will be parsed into the buffer
-func (c *Cursor) seekCursor(bufferResponse bool) error {
-	if c.lastErr != nil {
-		return c.lastErr
-	}
-
-	if len(c.buffer) == 0 && len(c.responses) == 0 && c.closed {
-		return errCursorClosed
-	}
-
-	// Loop over loading data, applying skips as necessary and loading more data as needed
-	// until either the cursor is closed or finished, or we have applied all outstanding
-	// skips and data is available
-	for {
-		c.applyPendingSkips(bufferResponse) // if we are buffering the responses, skip can drain from the buffer
-
-		if bufferResponse && len(c.buffer) == 0 && len(c.responses) > 0 {
-			if err := c.bufferNextResponse(); err != nil {
-				return err
-			}
-			continue // go around the loop again to re-apply pending skips
-		} else if len(c.buffer) == 0 && len(c.responses) == 0 && !c.finished && !c.closed {
-			//  We skipped all of our data, load some more
-			if err := c.fetchMore(); err != nil {
-				return err
-			}
-			continue // go around the loop again to re-apply pending skips
-		}
-		return nil
-	}
-}
-
-// applyPendingSkips applies all pending skips to the buffer and
-// returns whether there are more pending skips to be applied
-//
-// if drainFromBuffer is true, we will drain from the buffer, otherwise
-// we drain from the responses
-func (c *Cursor) applyPendingSkips(drainFromBuffer bool) (stillPending bool) {
-	if c.pendingSkips == 0 {
-		return false
-	}
-
-	if drainFromBuffer {
-		if len(c.buffer) > c.pendingSkips {
-			c.buffer = c.buffer[c.pendingSkips:]
-			c.pendingSkips = 0
-			return false
-		}
-
-		c.pendingSkips -= len(c.buffer)
-		c.buffer = c.buffer[:0]
-		return c.pendingSkips > 0
-	}
-
-	if len(c.responses) > c.pendingSkips {
-		c.responses = c.responses[c.pendingSkips:]
-		c.pendingSkips = 0
-		return false
-	}
-
-	c.pendingSkips -= len(c.responses)
-	c.responses = c.responses[:0]
-	return c.pendingSkips > 0
-}
-
-// bufferResponse reads a single response and stores the result into the buffer
-// if the response is from an atomic response, it will check if the
-// response contains multiple records and store them all into the buffer
-func (c *Cursor) bufferNextResponse() error {
-	// If there are no responses, nothing to do
-	if len(c.responses) == 0 {
-		return nil
-	}
-
-	response := c.responses[0]
-	c.responses = c.responses[1:]
-
-	var value interface{}
-	decoder := json.NewDecoder(bytes.NewBuffer(response))
-	if c.conn.opts.UseJSONNumber {
-		decoder.UseNumber()
-	}
-	err := decoder.Decode(&value)
-	if err != nil {
-		return err
-	}
-
-	value, err = recursivelyConvertPseudotype(value, c.opts)
-	if err != nil {
-		return err
-	}
-
-	// If response is an ATOM then try and convert to an array
-	if data, ok := value.([]interface{}); ok && c.isAtom {
-		for _, v := range data {
-			c.buffer = append(c.buffer, v)
-		}
-	} else if value == nil {
-		c.buffer = append(c.buffer, nil)
-	} else {
-		c.buffer = append(c.buffer, value)
-	}
-	return nil
-}
diff --git a/cursor_test.go b/cursor_test.go
index be1d83e..c7c67bb 100644
--- a/cursor_test.go
+++ b/cursor_test.go
@@ -1,7 +1,6 @@
 package gorethink
 
 import (
-	"fmt"
 	"time"
 
 	test "gopkg.in/check.v1"
@@ -443,88 +442,3 @@ func (s *RethinkSuite) TestCursorNextResponse_object(c *test.C) {
 	c.Assert(ok, test.Equals, true)
 	c.Assert(b, jsonEquals, []byte(`{"foo":"bar"}`))
 }
-
-func (s *RethinkSuite) TestCursorPeek_idempotency(c *test.C) {
-	res, err := Expr([]int{1, 2, 3}).Run(session)
-	c.Assert(err, test.IsNil)
-
-	var result int
-
-	// Test idempotency
-	for i := 0; i < 2; i++ {
-		hasMore, err := res.Peek(&result)
-		c.Assert(err, test.IsNil)
-		c.Assert(result, test.Equals, 1)
-		c.Assert(hasMore, test.Equals, true)
-	}
-
-}
-
-func (s *RethinkSuite) TestCursorPeek_wrong_type(c *test.C) {
-	res, err := Expr([]int{1, 2, 3}).Run(session)
-	c.Assert(err, test.IsNil)
-
-	// Test that wrongType doesn't break the cursor
-	wrongType := struct {
-		Name string
-		Age  int
-	}{}
-
-	hasMore, err := res.Peek(&wrongType)
-	c.Assert(err, test.NotNil)
-	c.Assert(hasMore, test.Equals, false)
-	c.Assert(res.Err(), test.IsNil)
-}
-
-func (s *RethinkSuite) TestCursorPeek_usage(c *test.C) {
-	res, err := Expr([]int{1, 2, 3}).Run(session)
-	c.Assert(err, test.IsNil)
-
-	var result int
-
-	// Test that Skip progresses our cursor
-	res.Skip()
-	hasMore, err := res.Peek(&result)
-	c.Assert(err, test.IsNil)
-	c.Assert(result, test.Equals, 2)
-	c.Assert(hasMore, test.Equals, true)
-
-	// Test that we can use Next afterwards and we get the same result
-	hasMore = res.Next(&result)
-	c.Assert(result, test.Equals, 2)
-	c.Assert(hasMore, test.Equals, true)
-}
-
-func (s *RethinkSuite) TestCursorSkip(c *test.C) {
-	res, err := Expr([]int{1, 2, 3}).Run(session)
-	c.Assert(err, test.IsNil)
-
-	res.Skip()
-
-	var result int
-	hasMore := res.Next(&result)
-	c.Assert(result, test.Equals, 2)
-	c.Assert(hasMore, test.Equals, true)
-}
-
-func ExampleCursor_Peek() {
-	res, err := Expr([]int{1, 2, 3}).Run(session)
-	if err != nil {
-		fmt.Print(err)
-		return
-	}
-
-	var result, altResult int
-	wasRead, err := res.Peek(&result) // Result is now 1
-	if err != nil {
-		fmt.Print(err)
-		return
-	} else if !wasRead {
-		fmt.Print("No data to read!")
-	}
-
-	res.Next(&altResult) // altResult is also 1, peek didn't progress the cursor
-
-	res.Skip()        // progress the cursor, skipping 2
-	res.Peek(&result) // result is now 3
-}
diff --git a/doc.go b/doc.go
index 24a7413..078b4ce 100644
--- a/doc.go
+++ b/doc.go
@@ -1,6 +1,6 @@
 // Package gorethink implements a Go driver for RethinkDB
 //
-// Current version: v2.0.1 (RethinkDB v2.3)
+// Current version: v1.4.1 (RethinkDB v2.2)
 // For more in depth information on how to use RethinkDB check out the API docs
 // at http://rethinkdb.com/api
 package gorethink
diff --git a/encoding/encoder_test.go b/encoding/encoder_test.go
index 560a042..cbce0d0 100644
--- a/encoding/encoder_test.go
+++ b/encoding/encoder_test.go
@@ -324,26 +324,3 @@ func TestReferenceFieldInvalid(t *testing.T) {
 		t.Errorf("expected non-nil error but got nil")
 	}
 }
-
-type RefE struct {
-	ID   string  `gorethink:"id,omitempty"`
-	FIDs *[]RefF `gorethink:"f_ids,reference" gorethink_ref:"id"`
-}
-
-type RefF struct {
-	ID   string `gorethink:"id,omitempty"`
-	Name string `gorethink:"name"`
-}
-
-func TestReferenceFieldArray(t *testing.T) {
-	input := RefE{"1", &[]RefF{RefF{"2", "Name2"}, RefF{"3", "Name3"}}}
-	want := map[string]interface{}{"id": "1", "f_ids": []string{"2", "3"}}
-
-	out, err := Encode(input)
-	if err != nil {
-		t.Errorf("got error %v, expected nil", err)
-	}
-	if !jsonEqual(out, want) {
-		t.Errorf("got %q, want %q", out, want)
-	}
-}
diff --git a/encoding/encoder_types.go b/encoding/encoder_types.go
index bf5080e..8ef187b 100644
--- a/encoding/encoder_types.go
+++ b/encoding/encoder_types.go
@@ -49,12 +49,6 @@ func newTypeEncoder(t reflect.Type, allowAddr bool) encoderFunc {
 		return newArrayEncoder(t)
 	case reflect.Ptr:
 		return newPtrEncoder(t)
-	case reflect.Func:
-		// functions are a special case as they can be used internally for
-		// optional arguments. Just return the raw function, if somebody tries
-		// to pass a function to the database the JSON marshaller will catch this
-		// anyway.
-		return funcEncoder
 	default:
 		return unsupportedTypeEncoder
 	}
@@ -126,13 +120,6 @@ func interfaceEncoder(v reflect.Value) interface{} {
 	return encode(v.Elem())
 }
 
-func funcEncoder(v reflect.Value) interface{} {
-	if v.IsNil() {
-		return nil
-	}
-	return v.Interface()
-}
-
 func asStringEncoder(v reflect.Value) interface{} {
 	return fmt.Sprintf("%v", v.Interface())
 }
@@ -148,6 +135,7 @@ type structEncoder struct {
 
 func (se *structEncoder) encode(v reflect.Value) interface{} {
 	m := make(map[string]interface{})
+
 	for i, f := range se.fields {
 		fv := fieldByIndex(v, f.index)
 		if !fv.IsValid() || f.omitEmpty && se.isEmptyValue(fv) {
@@ -158,8 +146,27 @@ func (se *structEncoder) encode(v reflect.Value) interface{} {
 
 		// If this field is a referenced field then attempt to extract the value.
 		if f.reference {
+			refName := f.name
+			if f.refName != "" {
+				refName = f.refName
+			}
+
+			// referenced fields can only handle maps so return an error if the
+			// encoded field is of a different type
+			m, ok := encField.(map[string]interface{})
+			if !ok {
+				err := fmt.Errorf("Error referencing field %s in %s, expected object but got %t", refName, f.name, encField)
+				panic(&MarshalerError{v.Type(), err})
+			}
+
+			refVal, ok := m[refName]
+			if !ok {
+				err := fmt.Errorf("Error referencing field %s in %s, could not find referenced field", refName, f.name)
+				panic(&MarshalerError{v.Type(), err})
+			}
+
 			// Override the encoded field with the referenced field
-			encField = getReferenceField(f, v, encField)
+			encField = refVal
 		}
 
 		m[f.name] = encField
@@ -168,40 +175,6 @@ func (se *structEncoder) encode(v reflect.Value) interface{} {
 	return m
 }
 
-func getReferenceField(f field, v reflect.Value, encField interface{}) interface{} {
-	refName := f.name
-	if f.refName != "" {
-		refName = f.refName
-	}
-
-	encFields, isArray := encField.([]interface{})
-	if isArray {
-		refVals := make([]interface{}, len(encFields))
-		for i, e := range encFields {
-			refVals[i] = extractValue(e, v, f.name, refName)
-		}
-		return refVals
-	}
-	refVal := extractValue(encField, v, f.name, refName)
-	return refVal
-}
-
-func extractValue(encField interface{}, v reflect.Value, name string, refName string) interface{} {
-	// referenced fields can only handle maps so return an error if the
-	// encoded field is of a different type
-	m, ok := encField.(map[string]interface{})
-	if !ok {
-		err := fmt.Errorf("Error refing field %s in %s, expected object but got %t", refName, name, encField)
-		panic(&MarshalerError{v.Type(), err})
-	}
-	refVal, ok := m[refName]
-	if !ok {
-		err := fmt.Errorf("Error refing field %s in %s, could not find referenced field", refName, name)
-		panic(&MarshalerError{v.Type(), err})
-	}
-	return refVal
-}
-
 func (se *structEncoder) isEmptyValue(v reflect.Value) bool {
 	if v.Type() == timeType {
 		return v.Interface().(time.Time) == time.Time{}
diff --git a/errors.go b/errors.go
index ded750d..9e0c40f 100644
--- a/errors.go
+++ b/errors.go
@@ -7,7 +7,7 @@ import (
 	"fmt"
 	"strings"
 
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 var (
diff --git a/example_query_aggregation_test.go b/example_query_aggregation_test.go
index 1e616c7..2206e7e 100644
--- a/example_query_aggregation_test.go
+++ b/example_query_aggregation_test.go
@@ -91,11 +91,11 @@ func ExampleTerm_Ungroup() {
 func ExampleTerm_Reduce() {
 	cur, err := DB("examples").Table("posts").
 		Map(func(doc Term) interface{} {
-			return 1
-		}).
+		return 1
+	}).
 		Reduce(func(left, right Term) interface{} {
-			return left.Add(right)
-		}).
+		return left.Add(right)
+	}).
 		Run(session)
 	if err != nil {
 		fmt.Print(err)
@@ -111,25 +111,3 @@ func ExampleTerm_Reduce() {
 
 	fmt.Print(res)
 }
-
-// Concatenate words from a list.
-func ExampleTerm_Fold() {
-	cur, err := Expr([]string{"a", "b", "c"}).Fold("", func(acc, word Term) Term {
-		return acc.Add(Branch(acc.Eq(""), "", ", ")).Add(word)
-	}).Run(session)
-	if err != nil {
-		fmt.Print(err)
-		return
-	}
-
-	var res string
-	err = cur.One(&res)
-	if err != nil {
-		fmt.Print(err)
-		return
-	}
-
-	fmt.Print(res)
-	// Output:
-	// a, b, c
-}
diff --git a/gorethink.go b/gorethink.go
index 15fe176..ed1b6e2 100644
--- a/gorethink.go
+++ b/gorethink.go
@@ -5,7 +5,7 @@ import (
 
 	"github.com/Sirupsen/logrus"
 
-	"gopkg.in/dancannon/gorethink.v2/encoding"
+	"gopkg.in/dancannon/gorethink.v1/encoding"
 )
 
 var (
diff --git a/gorethink_test.go b/gorethink_test.go
index e33a41c..58b1f19 100644
--- a/gorethink_test.go
+++ b/gorethink_test.go
@@ -48,6 +48,9 @@ func init() {
 	if db == "" {
 		db = "test"
 	}
+
+	// Needed for running tests for RethinkDB with a non-empty authkey
+	authKey = os.Getenv("RETHINKDB_AUTHKEY")
 }
 
 //
@@ -57,6 +60,7 @@ func testSetup(m *testing.M) {
 	var err error
 	session, err = Connect(ConnectOpts{
 		Address: url,
+		AuthKey: authKey,
 	})
 	if err != nil {
 		Log.Fatalln(err.Error())
diff --git a/node.go b/node.go
index b2a7637..7ff2f35 100644
--- a/node.go
+++ b/node.go
@@ -4,7 +4,7 @@ import (
 	"sync"
 
 	"github.com/hailocab/go-hostpool"
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Node represents a database server in the cluster
diff --git a/pseudotypes.go b/pseudotypes.go
index fc80cc7..39e1126 100644
--- a/pseudotypes.go
+++ b/pseudotypes.go
@@ -6,7 +6,7 @@ import (
 	"strconv"
 	"time"
 
-	"gopkg.in/dancannon/gorethink.v2/types"
+	"gopkg.in/dancannon/gorethink.v1/types"
 
 	"fmt"
 )
diff --git a/ql2/ql2.pb.go b/ql2/ql2.pb.go
index 759849f..2d575f5 100644
--- a/ql2/ql2.pb.go
+++ b/ql2/ql2.pb.go
@@ -38,7 +38,6 @@ const (
 	VersionDummy_V0_2 VersionDummy_Version = 1915781601
 	VersionDummy_V0_3 VersionDummy_Version = 1601562686
 	VersionDummy_V0_4 VersionDummy_Version = 1074539808
-	VersionDummy_V1_0 VersionDummy_Version = 885177795
 )
 
 var VersionDummy_Version_name = map[int32]string{
@@ -46,14 +45,12 @@ var VersionDummy_Version_name = map[int32]string{
 	1915781601: "V0_2",
 	1601562686: "V0_3",
 	1074539808: "V0_4",
-	885177795:  "V1_0",
 }
 var VersionDummy_Version_value = map[string]int32{
 	"V0_1": 1063369270,
 	"V0_2": 1915781601,
 	"V0_3": 1601562686,
 	"V0_4": 1074539808,
-	"V1_0": 885177795,
 }
 
 func (x VersionDummy_Version) Enum() *VersionDummy_Version {
@@ -271,7 +268,6 @@ const (
 	Response_OP_FAILED        Response_ErrorType = 4100000
 	Response_OP_INDETERMINATE Response_ErrorType = 4200000
 	Response_USER             Response_ErrorType = 5000000
-	Response_PERMISSION_ERROR Response_ErrorType = 6000000
 )
 
 var Response_ErrorType_name = map[int32]string{
@@ -282,7 +278,6 @@ var Response_ErrorType_name = map[int32]string{
 	4100000: "OP_FAILED",
 	4200000: "OP_INDETERMINATE",
 	5000000: "USER",
-	6000000: "PERMISSION_ERROR",
 }
 var Response_ErrorType_value = map[string]int32{
 	"INTERNAL":         1000000,
@@ -292,7 +287,6 @@ var Response_ErrorType_value = map[string]int32{
 	"OP_FAILED":        4100000,
 	"OP_INDETERMINATE": 4200000,
 	"USER":             5000000,
-	"PERMISSION_ERROR": 6000000,
 }
 
 func (x Response_ErrorType) Enum() *Response_ErrorType {
@@ -542,7 +536,6 @@ const (
 	Term_BETWEEN Term_TermType = 182
 	Term_REDUCE  Term_TermType = 37
 	Term_MAP     Term_TermType = 38
-	Term_FOLD    Term_TermType = 187
 	// Filter a sequence with either a function or a shortcut
 	// object (see API docs for details).  The body of FILTER is
 	// wrapped in an implicit `.default(false)`, and you can
@@ -663,8 +656,6 @@ const (
 	// Ensures that previously issued soft-durability writes are complete and
 	// written to disk.
 	Term_SYNC Term_TermType = 138
-	// Set global, database, or table-specific permissions
-	Term_GRANT Term_TermType = 188
 	// * Secondary indexes OPs
 	// Creates a new secondary index with a particular name and definition.
 	Term_INDEX_CREATE Term_TermType = 75
@@ -910,7 +901,6 @@ var Term_TermType_name = map[int32]string{
 	182: "BETWEEN",
 	37:  "REDUCE",
 	38:  "MAP",
-	187: "FOLD",
 	39:  "FILTER",
 	40:  "CONCAT_MAP",
 	41:  "ORDER_BY",
@@ -947,7 +937,6 @@ var Term_TermType_name = map[int32]string{
 	176: "RECONFIGURE",
 	179: "REBALANCE",
 	138: "SYNC",
-	188: "GRANT",
 	75:  "INDEX_CREATE",
 	76:  "INDEX_DROP",
 	77:  "INDEX_LIST",
@@ -1090,7 +1079,6 @@ var Term_TermType_value = map[string]int32{
 	"BETWEEN":            182,
 	"REDUCE":             37,
 	"MAP":                38,
-	"FOLD":               187,
 	"FILTER":             39,
 	"CONCAT_MAP":         40,
 	"ORDER_BY":           41,
@@ -1127,7 +1115,6 @@ var Term_TermType_value = map[string]int32{
 	"RECONFIGURE":        176,
 	"REBALANCE":          179,
 	"SYNC":               138,
-	"GRANT":              188,
 	"INDEX_CREATE":       75,
 	"INDEX_DROP":         76,
 	"INDEX_LIST":         77,
@@ -1405,7 +1392,7 @@ type Response struct {
 	Response []*Datum `protobuf:"bytes,3,rep,name=response" json:"response,omitempty"`
 	// If [type] is [CLIENT_ERROR], [TYPE_ERROR], or [RUNTIME_ERROR], then a
 	// backtrace will be provided.  The backtrace says where in the query the
-	// error occurred.  Ideally this information will be presented to the user as
+	// error occured.  Ideally this information will be presented to the user as
 	// a pretty-printed version of their query with the erroneous section
 	// underlined.  A backtrace is a series of 0 or more [Frame]s, each of which
 	// specifies either the index of a positional argument or the name of an
diff --git a/ql2/ql2.proto b/ql2/ql2.proto
index e40c5be..95e6d6a 100644
--- a/ql2/ql2.proto
+++ b/ql2/ql2.proto
@@ -48,7 +48,6 @@ message VersionDummy { // We need to wrap it like this for some
         V0_2      = 0x723081e1; // Authorization key during handshake
         V0_3      = 0x5f75e83e; // Authorization key and protocol during handshake
         V0_4      = 0x400c2d20; // Queries execute in parallel
-        V1_0      = 0x34c2bdc3; // Users and permissions
     }
 
     // The protocol to use after the handshake, specified in V0_3
@@ -99,8 +98,8 @@ message Query {
 // A backtrace frame (see `backtrace` in Response below)
 message Frame {
     enum FrameType {
-        POS = 1; // Error occurred in a positional argument.
-        OPT = 2; // Error occurred in an optional argument.
+        POS = 1; // Error occured in a positional argument.
+        OPT = 2; // Error occured in an optional argument.
     }
     optional FrameType type = 1;
     optional int64 pos = 2; // The index of the positional argument.
@@ -150,7 +149,6 @@ message Response {
         OP_FAILED = 4100000;
         OP_INDETERMINATE = 4200000;
         USER = 5000000;
-        PERMISSION_ERROR = 6000000;
     }
     optional ErrorType error_type = 7;
 
@@ -188,7 +186,7 @@ message Response {
 
     // If [type] is [CLIENT_ERROR], [TYPE_ERROR], or [RUNTIME_ERROR], then a
     // backtrace will be provided.  The backtrace says where in the query the
-    // error occurred.  Ideally this information will be presented to the user as
+    // error occured.  Ideally this information will be presented to the user as
     // a pretty-printed version of their query with the erroneous section
     // underlined.  A backtrace is a series of 0 or more [Frame]s, each of which
     // specifies either the index of a positional argument or the name of an
@@ -420,8 +418,6 @@ message Term {
                         // The arity of the function should be
                         // Sequence..., Function(sizeof...(Sequence)) -> Sequence
 
-        FOLD      = 187; // Sequence, Datum, Function(2), {Function(3), Function(1)
-
         // Filter a sequence with either a function or a shortcut
         // object (see API docs for details).  The body of FILTER is
         // wrapped in an implicit `.default(false)`, and you can
@@ -554,11 +550,6 @@ message Term {
         // written to disk.
         SYNC          = 138; // Table -> OBJECT
 
-        // Set global, database, or table-specific permissions
-        GRANT         = 188; //          -> OBJECT
-                             // Database -> OBJECT
-                             // Table    -> OBJECT
-
         // * Secondary indexes OPs
         // Creates a new secondary index with a particular name and definition.
         INDEX_CREATE = 75; // Table, STRING, Function(1), {multi:BOOL} -> OBJECT
diff --git a/query.go b/query.go
index 1bd88a3..d0edd5f 100644
--- a/query.go
+++ b/query.go
@@ -5,7 +5,7 @@ import (
 	"strconv"
 	"strings"
 
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // A Query represents a query ready to be sent to the database, A Query differs
@@ -206,7 +206,6 @@ type RunOpts struct {
 	DB             interface{} `gorethink:"db,omitempty"`
 	Db             interface{} `gorethink:"db,omitempty"` // Deprecated
 	Profile        interface{} `gorethink:"profile,omitempty"`
-	Durability     interface{} `gorethink:"durability,omitempty"`
 	UseOutdated    interface{} `gorethink:"use_outdated,omitempty"` // Deprecated
 	ArrayLimit     interface{} `gorethink:"array_limit,omitempty"`
 	TimeFormat     interface{} `gorethink:"time_format,omitempty"`
@@ -277,30 +276,6 @@ func (t Term) RunWrite(s *Session, optArgs ...RunOpts) (WriteResponse, error) {
 	return response, nil
 }
 
-// ReadOne is a shortcut method that runs the query on the given connection
-// and reads one response from the cursor before closing it.
-//
-// It returns any errors encountered from running the query or reading the response
-func (t Term) ReadOne(dest interface{}, s *Session, optArgs ...RunOpts) error {
-	res, err := t.Run(s, optArgs...)
-	if err != nil {
-		return err
-	}
-	return res.One(dest)
-}
-
-// ReadAll is a shortcut method that runs the query on the given connection
-// and reads all of the responses from the cursor before closing it.
-//
-// It returns any errors encountered from running the query or reading the responses
-func (t Term) ReadAll(dest interface{}, s *Session, optArgs ...RunOpts) error {
-	res, err := t.Run(s, optArgs...)
-	if err != nil {
-		return err
-	}
-	return res.All(dest)
-}
-
 // ExecOpts contains the optional arguments for the Exec function and  inherits
 // its options from RunOpts, the only difference is the addition of the NoReply
 // field.
@@ -311,7 +286,6 @@ type ExecOpts struct {
 	DB             interface{} `gorethink:"db,omitempty"`
 	Db             interface{} `gorethink:"db,omitempty"` // Deprecated
 	Profile        interface{} `gorethink:"profile,omitempty"`
-	Durability     interface{} `gorethink:"durability,omitempty"`
 	UseOutdated    interface{} `gorethink:"use_outdated,omitempty"` // Deprecated
 	ArrayLimit     interface{} `gorethink:"array_limit,omitempty"`
 	TimeFormat     interface{} `gorethink:"time_format,omitempty"`
diff --git a/query_admin.go b/query_admin.go
index 8c78c16..aa36526 100644
--- a/query_admin.go
+++ b/query_admin.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Config can be used to read and/or update the configurations for individual
@@ -20,7 +20,7 @@ func (t Term) Rebalance() Term {
 type ReconfigureOpts struct {
 	Shards               interface{} `gorethink:"shards,omitempty"`
 	Replicas             interface{} `gorethink:"replicas,omitempty"`
-	PrimaryTag           interface{} `gorethink:"primary_replica_tag,omitempty"`
+	PrimaryTag           interface{} `gorethink:"primary_replicas_tag,omitempty"`
 	DryRun               interface{} `gorethink:"dry_run,omitempty"`
 	EmergencyRepair      interface{} `gorethink:"emergency_repair,omitempty"`
 	NonVotingReplicaTags interface{} `gorethink:"nonvoting_replica_tags,omitempty"`
@@ -53,8 +53,6 @@ func (o *WaitOpts) toMap() map[string]interface{} {
 // Wait for a table or all the tables in a database to be ready. A table may be
 // temporarily unavailable after creation, rebalancing or reconfiguring. The
 // wait command blocks until the given table (or database) is fully up to date.
-//
-// Deprecated: This function is not supported by RethinkDB 2.3 and above.
 func Wait(optArgs ...WaitOpts) Term {
 	opts := map[string]interface{}{}
 	if len(optArgs) >= 1 {
@@ -73,9 +71,3 @@ func (t Term) Wait(optArgs ...WaitOpts) Term {
 	}
 	return constructMethodTerm(t, "Wait", p.Term_WAIT, []interface{}{}, opts)
 }
-
-// Grant modifies access permissions for a user account, globally or on a
-// per-database or per-table basis.
-func (t Term) Grant(args ...interface{}) Term {
-	return constructMethodTerm(t, "Grant", p.Term_GRANT, args, map[string]interface{}{})
-}
diff --git a/query_admin_test.go b/query_admin_test.go
index 507f06b..9c99d13 100644
--- a/query_admin_test.go
+++ b/query_admin_test.go
@@ -56,6 +56,23 @@ func (s *RethinkSuite) TestAdminTableStatus(c *test.C) {
 	c.Assert(response["status"], test.NotNil)
 }
 
+func (s *RethinkSuite) TestAdminWait(c *test.C) {
+	DB("test").TableDrop("test").Exec(session)
+	DB("test").TableCreate("test").Exec(session)
+
+	// Test index rename
+	query := Wait()
+
+	res, err := query.Run(session)
+	c.Assert(err, test.IsNil)
+
+	var response map[string]interface{}
+	err = res.One(&response)
+	c.Assert(err, test.IsNil)
+
+	c.Assert(response["ready"].(float64) > 0, test.Equals, true)
+}
+
 func (s *RethinkSuite) TestAdminWaitOpts(c *test.C) {
 	DB("test").TableDrop("test").Exec(session)
 	DB("test").TableCreate("test").Exec(session)
@@ -91,18 +108,3 @@ func (s *RethinkSuite) TestAdminStatus(c *test.C) {
 
 	c.Assert(response["ready"], test.Equals, float64(1))
 }
-
-func (s *RethinkSuite) TestAdminGrantDatabase(c *test.C) {
-	DB("rethinkdb").Table("users").Insert(map[string]string{
-		"id":       "test_user",
-		"password": "password",
-	}).Exec(session)
-
-	DB("test").TableDrop("test_grant").Exec(session)
-	DB("test").TableCreate("test_grant").Exec(session)
-
-	err := DB("test").Table("test_grant").Grant("test_user", map[string]bool{
-		"read": true, "write": true, "config": true,
-	}).Exec(session)
-	c.Assert(err, test.IsNil)
-}
diff --git a/query_aggregation.go b/query_aggregation.go
index ec81c58..5387d39 100644
--- a/query_aggregation.go
+++ b/query_aggregation.go
@@ -1,6 +1,8 @@
 package gorethink
 
-import p "gopkg.in/dancannon/gorethink.v2/ql2"
+import (
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
+)
 
 // Aggregation
 // These commands are used to compute smaller values from large sequences.
@@ -165,43 +167,3 @@ func (t Term) MaxIndex(index interface{}, args ...interface{}) Term {
 		"index": index,
 	})
 }
-
-// FoldOpts contains the optional arguments for the Fold term
-type FoldOpts struct {
-	Emit      interface{} `gorethink:"emit,omitempty"`
-	FinalEmit interface{} `gorethink:"finalEmit,omitempty"`
-}
-
-func (o *FoldOpts) toMap() map[string]interface{} {
-	return optArgsToMap(o)
-}
-
-// Fold applies a function to a sequence in order, maintaining state via an
-// accumulator. The Fold command returns either a single value or a new sequence.
-//
-// In its first form, Fold operates like Reduce, returning a value by applying a
-// combining function to each element in a sequence, passing the current element
-// and the previous reduction result to the function. However, Fold has the
-// following differences from Reduce:
-//  - it is guaranteed to proceed through the sequence from first element to last.
-//  - it passes an initial base value to the function with the first element in
-//    place of the previous reduction result.
-//
-// In its second form, Fold operates like ConcatMap, returning a new sequence
-// rather than a single value. When an emit function is provided, Fold will:
-//  - proceed through the sequence in order and take an initial base value, as above.
-//  - for each element in the sequence, call both the combining function and a
-//    separate emitting function with the current element and previous reduction result.
-//  - optionally pass the result of the combining function to the emitting function.
-//
-// If provided, the emitting function must return a list.
-func (t Term) Fold(base, fn interface{}, optArgs ...FoldOpts) Term {
-	opts := map[string]interface{}{}
-	if len(optArgs) >= 1 {
-		opts = optArgs[0].toMap()
-	}
-
-	args := []interface{}{base, funcWrap(fn)}
-
-	return constructMethodTerm(t, "Fold", p.Term_FOLD, args, opts)
-}
diff --git a/query_aggregation_test.go b/query_aggregation_test.go
index abf84e0..77e7a9f 100644
--- a/query_aggregation_test.go
+++ b/query_aggregation_test.go
@@ -1,6 +1,8 @@
 package gorethink
 
-import test "gopkg.in/check.v1"
+import (
+	test "gopkg.in/check.v1"
+)
 
 func (s *RethinkSuite) TestAggregationReduce(c *test.C) {
 	var response int
@@ -318,40 +320,3 @@ func (s *RethinkSuite) TestAggregationContains(c *test.C) {
 	c.Assert(err, test.IsNil)
 	c.Assert(response, test.Equals, true)
 }
-
-func (s *RethinkSuite) TestAggregationFold(c *test.C) {
-	var response int
-	query := Expr(arr).Reduce(func(acc, val Term) Term {
-		return acc.Add(val)
-	})
-	res, err := query.Run(session)
-	c.Assert(err, test.IsNil)
-
-	err = res.One(&response)
-	c.Assert(err, test.IsNil)
-	c.Assert(response, test.Equals, 45)
-}
-
-func (s *RethinkSuite) TestAggregationFoldEmit(c *test.C) {
-	var response []interface{}
-	query := Expr(objList).Fold(0, func(acc, row Term) Term {
-		return acc.Add(1)
-	}, FoldOpts{
-		Emit: func(acc, row, cur Term) Term {
-			return Branch(acc.Mod(2).Eq(0), []interface{}{row}, []interface{}{})
-		},
-	})
-	res, err := query.Run(session)
-	c.Assert(err, test.IsNil)
-
-	err = res.All(&response)
-
-	c.Assert(err, test.IsNil)
-	c.Assert(response, jsonEquals, []interface{}{
-		map[string]interface{}{"id": 1, "g1": 1, "g2": 1, "num": 0},
-		map[string]interface{}{"id": 3, "g1": 3, "g2": 2, "num": 10},
-		map[string]interface{}{"id": 5, "g1": 2, "g2": 3, "num": 100},
-		map[string]interface{}{"id": 7, "g1": 1, "g2": 2, "num": 0},
-		map[string]interface{}{"id": 9, "g1": 2, "g2": 3, "num": 25},
-	})
-}
diff --git a/query_control.go b/query_control.go
index f02aa79..faf72c0 100644
--- a/query_control.go
+++ b/query_control.go
@@ -6,7 +6,7 @@ import (
 
 	"reflect"
 
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Expr converts any value to an expression and is also used by many other terms
diff --git a/query_db.go b/query_db.go
index 0fd21c8..7d33530 100644
--- a/query_db.go
+++ b/query_db.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // DBCreate creates a database. A RethinkDB database is a collection of tables,
diff --git a/query_geospatial.go b/query_geospatial.go
index ba928d7..69823c2 100644
--- a/query_geospatial.go
+++ b/query_geospatial.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // CircleOpts contains the optional arguments for the Circle term.
diff --git a/query_geospatial_test.go b/query_geospatial_test.go
index ed0b784..f12da5e 100644
--- a/query_geospatial_test.go
+++ b/query_geospatial_test.go
@@ -3,7 +3,7 @@ package gorethink
 import (
 	test "gopkg.in/check.v1"
 
-	"gopkg.in/dancannon/gorethink.v2/types"
+	"gopkg.in/dancannon/gorethink.v1/types"
 )
 
 func (s *RethinkSuite) TestGeospatialDecodeGeometryPseudoType(c *test.C) {
diff --git a/query_join.go b/query_join.go
index 93fa704..5f2af6f 100644
--- a/query_join.go
+++ b/query_join.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // InnerJoin returns the inner product of two sequences (e.g. a table, a filter result)
@@ -21,8 +21,7 @@ func (t Term) OuterJoin(args ...interface{}) Term {
 
 // EqJoinOpts contains the optional arguments for the EqJoin term.
 type EqJoinOpts struct {
-	Index   interface{} `gorethink:"index,omitempty"`
-	Ordered interface{} `gorethink:"ordered,omitempty"`
+	Index interface{} `gorethink:"index,omitempty"`
 }
 
 func (o *EqJoinOpts) toMap() map[string]interface{} {
diff --git a/query_join_test.go b/query_join_test.go
index dff3d23..11a470e 100644
--- a/query_join_test.go
+++ b/query_join_test.go
@@ -102,9 +102,7 @@ func (s *RethinkSuite) TestJoinEqJoinZip(c *test.C) {
 
 	// Test query
 	var response []interface{}
-	query := DB("test").Table("Join1").EqJoin("id", DB("test").Table("Join2"), EqJoinOpts{
-		Ordered: true,
-	}).Zip()
+	query := DB("test").Table("Join1").EqJoin("id", DB("test").Table("Join2")).Zip()
 	res, err := query.Run(session)
 	c.Assert(err, test.IsNil)
 
@@ -135,8 +133,7 @@ func (s *RethinkSuite) TestJoinEqJoinDiffIdsZip(c *test.C) {
 	// Test query
 	var response []interface{}
 	query := DB("test").Table("Join1").EqJoin("id", DB("test").Table("Join3"), EqJoinOpts{
-		Index:   "it",
-		Ordered: true,
+		Index: "it",
 	}).Zip()
 	res, err := query.Run(session)
 	c.Assert(err, test.IsNil)
diff --git a/query_manipulation.go b/query_manipulation.go
index 62d0ffb..081d673 100644
--- a/query_manipulation.go
+++ b/query_manipulation.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Row returns the currently visited document. Note that Row does not work within
diff --git a/query_math.go b/query_math.go
index b16ffab..3e3cfe0 100644
--- a/query_math.go
+++ b/query_math.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 var (
diff --git a/query_select.go b/query_select.go
index c0589d2..e1058a6 100644
--- a/query_select.go
+++ b/query_select.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // DB references a database.
diff --git a/query_select_test.go b/query_select_test.go
index 2190e5b..d93cb8d 100644
--- a/query_select_test.go
+++ b/query_select_test.go
@@ -35,6 +35,7 @@ func (s *RethinkSuite) TestSelectGet(c *test.C) {
 func (s *RethinkSuite) TestSelectJSONNumbers(c *test.C) {
 	session, err := Connect(ConnectOpts{
 		Address:       url,
+		AuthKey:       authKey,
 		UseJSONNumber: true,
 	})
 	c.Assert(err, test.IsNil)
@@ -376,6 +377,7 @@ func (s *RethinkSuite) TestConcurrentSelectManyWorkers(c *test.C) {
 	rand.Seed(time.Now().UnixNano())
 	sess, _ := Connect(ConnectOpts{
 		Address: url,
+		AuthKey: authKey,
 		MaxOpen: 200,
 		MaxIdle: 200,
 	})
@@ -493,28 +495,28 @@ func (s *RethinkSuite) TestConcurrentSelectManyRows(c *test.C) {
 	waitChannel := make(chan error, attempts)
 
 	for i := 0; i < attempts; i++ {
-		go func(i int, ch chan error) {
+		go func(i int, c chan error) {
 			res, err := DB("test").Table("TestMany").Run(session)
 			if err != nil {
-				ch <- err
+				c <- err
 				return
 			}
 
 			var response []map[string]interface{}
 			err = res.All(&response)
 			if err != nil {
-				ch <- err
+				c <- err
 				return
 			}
 
 			if len(response) != 100 {
-				ch <- fmt.Errorf("expected response length 100, received %d", len(response))
+				c <- fmt.Errorf("expected response length 100, received %d", len(response))
 				return
 			}
 
 			res.Close()
 
-			ch <- nil
+			c <- nil
 		}(i, waitChannel)
 	}
 
diff --git a/query_string.go b/query_string.go
index 12ca222..5917e67 100644
--- a/query_string.go
+++ b/query_string.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Match matches against a regular expression. If no match is found, returns
diff --git a/query_table.go b/query_table.go
index e9a7df5..ef399aa 100644
--- a/query_table.go
+++ b/query_table.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // TableCreateOpts contains the optional arguments for the TableCreate term
@@ -152,8 +152,6 @@ type ChangesOpts struct {
 	Squash              interface{} `gorethink:"squash,omitempty"`
 	IncludeInitial      interface{} `gorethink:"include_initial,omitempty"`
 	IncludeStates       interface{} `gorethink:"include_states,omitempty"`
-	IncludeOffsets      interface{} `gorethink:"include_offsets,omitempty"`
-	IncludeTypes        interface{} `gorethink:"include_types,omitempty"`
 	ChangefeedQueueSize interface{} `gorethink:"changefeed_queue_size,omitempty"`
 }
 
diff --git a/query_table_test.go b/query_table_test.go
index dc16e6f..54c7711 100644
--- a/query_table_test.go
+++ b/query_table_test.go
@@ -21,6 +21,7 @@ func (s *RethinkSuite) TestTableCreate(c *test.C) {
 func (s *RethinkSuite) TestTableCreateSessionDatabase(c *test.C) {
 	session, err := Connect(ConnectOpts{
 		Address: url,
+		AuthKey: authKey,
 	})
 	c.Assert(err, test.IsNil)
 	TableDrop("test").Exec(session)
diff --git a/query_test.go b/query_test.go
index 486be13..3d38fe5 100644
--- a/query_test.go
+++ b/query_test.go
@@ -14,23 +14,6 @@ func (s *RethinkSuite) TestQueryRun(c *test.C) {
 	c.Assert(response, test.Equals, "Test")
 }
 
-func (s *RethinkSuite) TestQueryReadOne(c *test.C) {
-	var response string
-
-	err := Expr("Test").ReadOne(&response, session)
-	c.Assert(err, test.IsNil)
-	c.Assert(response, test.Equals, "Test")
-}
-
-func (s *RethinkSuite) TestQueryReadAll(c *test.C) {
-	var response []int
-
-	err := Expr([]int{1, 2, 3}).ReadAll(&response, session)
-	c.Assert(err, test.IsNil)
-	c.Assert(response, test.HasLen, 3)
-	c.Assert(response, test.DeepEquals, []int{1, 2, 3})
-}
-
 func (s *RethinkSuite) TestQueryExec(c *test.C) {
 	err := Expr("Test").Exec(session)
 	c.Assert(err, test.IsNil)
diff --git a/query_time.go b/query_time.go
index 1205da4..15a51b1 100644
--- a/query_time.go
+++ b/query_time.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Now returns a time object representing the current time in UTC
diff --git a/query_transformation.go b/query_transformation.go
index 56ebe2e..fb38869 100644
--- a/query_transformation.go
+++ b/query_transformation.go
@@ -1,6 +1,6 @@
 package gorethink
 
-import p "gopkg.in/dancannon/gorethink.v2/ql2"
+import p "gopkg.in/dancannon/gorethink.v1/ql2"
 
 // Map transform each element of the sequence by applying the given mapping
 // function. It takes two arguments, a sequence and a function of type
@@ -151,15 +151,6 @@ func (t Term) IsEmpty(args ...interface{}) Term {
 	return constructMethodTerm(t, "IsEmpty", p.Term_IS_EMPTY, args, map[string]interface{}{})
 }
 
-// UnionOpts contains the optional arguments for the Slice term
-type UnionOpts struct {
-	Interleave interface{} `gorethink:"interleave,omitempty"`
-}
-
-func (o *UnionOpts) toMap() map[string]interface{} {
-	return optArgsToMap(o)
-}
-
 // Union concatenates two sequences.
 func Union(args ...interface{}) Term {
 	return constructRootTerm("Union", p.Term_UNION, args, map[string]interface{}{})
@@ -170,18 +161,6 @@ func (t Term) Union(args ...interface{}) Term {
 	return constructMethodTerm(t, "Union", p.Term_UNION, args, map[string]interface{}{})
 }
 
-// UnionWithOpts like Union concatenates two sequences however allows for optional
-// arguments to be passed.
-func UnionWithOpts(optArgs UnionOpts, args ...interface{}) Term {
-	return constructRootTerm("Union", p.Term_UNION, args, optArgs.toMap())
-}
-
-// UnionWithOpts like Union concatenates two sequences however allows for optional
-// arguments to be passed.
-func (t Term) UnionWithOpts(optArgs UnionOpts, args ...interface{}) Term {
-	return constructMethodTerm(t, "Union", p.Term_UNION, args, optArgs.toMap())
-}
-
 // Sample selects a given number of elements from a sequence with uniform random
 // distribution. Selection is done without replacement.
 func (t Term) Sample(args ...interface{}) Term {
diff --git a/query_write.go b/query_write.go
index 1adb779..d02fdef 100644
--- a/query_write.go
+++ b/query_write.go
@@ -1,7 +1,7 @@
 package gorethink
 
 import (
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // InsertOpts contains the optional arguments for the Insert term
@@ -30,7 +30,6 @@ type UpdateOpts struct {
 	Durability    interface{} `gorethink:"durability,omitempty"`
 	ReturnChanges interface{} `gorethink:"return_changes,omitempty"`
 	NotAtomic     interface{} `gorethink:"non_atomic,omitempty"`
-	Conflict      interface{} `gorethink:"conflict,omitempty"`
 }
 
 func (o *UpdateOpts) toMap() map[string]interface{} {
diff --git a/session.go b/session.go
index 63ab60d..8d509e9 100644
--- a/session.go
+++ b/session.go
@@ -5,7 +5,7 @@ import (
 	"sync"
 	"time"
 
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // A Session represents a connection to a RethinkDB cluster and should be used
@@ -24,16 +24,13 @@ type ConnectOpts struct {
 	Address      string        `gorethink:"address,omitempty"`
 	Addresses    []string      `gorethink:"addresses,omitempty"`
 	Database     string        `gorethink:"database,omitempty"`
-	Username     string        `gorethink:"username,omitempty"`
-	Password     string        `gorethink:"password,omitempty"`
-	AuthKey      string        `gorethink:"authkey,omitempty"` // Deprecated
+	AuthKey      string        `gorethink:"authkey,omitempty"`
 	Timeout      time.Duration `gorethink:"timeout,omitempty"`
 	WriteTimeout time.Duration `gorethink:"write_timeout,omitempty"`
 	ReadTimeout  time.Duration `gorethink:"read_timeout,omitempty"`
 	// The duration in which a connection should send a keep-alive.
-	KeepAlivePeriod  time.Duration    `gorethink:"keep_alive_timeout,omitempty"`
-	TLSConfig        *tls.Config      `gorethink:"tlsconfig,omitempty"`
-	HandshakeVersion HandshakeVersion `gorethink:"handshake_version,omitempty"`
+	KeepAlivePeriod time.Duration `gorethink:"keep_alive_timeout,omitempty"`
+	TLSConfig       *tls.Config   `gorethink:"tlsconfig,omitempty"`
 
 	MaxIdle int `gorethink:"max_idle,omitempty"`
 	// By default a maximum of 2 connections are opened per host.
diff --git a/session_test.go b/session_test.go
index 53b27de..ae925fe 100644
--- a/session_test.go
+++ b/session_test.go
@@ -10,38 +10,7 @@ import (
 func (s *RethinkSuite) TestSessionConnect(c *test.C) {
 	session, err := Connect(ConnectOpts{
 		Address: url,
-	})
-	c.Assert(err, test.IsNil)
-
-	row, err := Expr("Hello World").Run(session)
-	c.Assert(err, test.IsNil)
-
-	var response string
-	err = row.One(&response)
-	c.Assert(err, test.IsNil)
-	c.Assert(response, test.Equals, "Hello World")
-}
-
-func (s *RethinkSuite) TestSessionConnectHandshakeV1_0(c *test.C) {
-	session, err := Connect(ConnectOpts{
-		Address:          url,
-		HandshakeVersion: HandshakeV1_0,
-	})
-	c.Assert(err, test.IsNil)
-
-	row, err := Expr("Hello World").Run(session)
-	c.Assert(err, test.IsNil)
-
-	var response string
-	err = row.One(&response)
-	c.Assert(err, test.IsNil)
-	c.Assert(response, test.Equals, "Hello World")
-}
-
-func (s *RethinkSuite) TestSessionConnectHandshakeV0_4(c *test.C) {
-	session, err := Connect(ConnectOpts{
-		Address:          url,
-		HandshakeVersion: HandshakeV0_4,
+		AuthKey: os.Getenv("RETHINKDB_AUTHKEY"),
 	})
 	c.Assert(err, test.IsNil)
 
@@ -57,6 +26,7 @@ func (s *RethinkSuite) TestSessionConnectHandshakeV0_4(c *test.C) {
 func (s *RethinkSuite) TestSessionReconnect(c *test.C) {
 	session, err := Connect(ConnectOpts{
 		Address: url,
+		AuthKey: os.Getenv("RETHINKDB_AUTHKEY"),
 	})
 	c.Assert(err, test.IsNil)
 
@@ -91,6 +61,7 @@ func (s *RethinkSuite) TestSessionConnectError(c *test.C) {
 func (s *RethinkSuite) TestSessionClose(c *test.C) {
 	session, err := Connect(ConnectOpts{
 		Address: url,
+		AuthKey: os.Getenv("RETHINKDB_AUTHKEY"),
 	})
 	c.Assert(err, test.IsNil)
 
@@ -107,6 +78,7 @@ func (s *RethinkSuite) TestSessionClose(c *test.C) {
 func (s *RethinkSuite) TestSessionServer(c *test.C) {
 	session, err := Connect(ConnectOpts{
 		Address: url,
+		AuthKey: os.Getenv("RETHINKDB_AUTHKEY"),
 	})
 	c.Assert(err, test.IsNil)
 
@@ -129,25 +101,3 @@ func (s *RethinkSuite) TestSessionConnectDatabase(c *test.C) {
 	c.Assert(err, test.NotNil)
 	c.Assert(err.Error(), test.Equals, "gorethink: Database `test2` does not exist. in: \nr.Table(\"test2\")")
 }
-
-func (s *RethinkSuite) TestSessionConnectUsername(c *test.C) {
-	session, err := Connect(ConnectOpts{
-		Address: url,
-	})
-	c.Assert(err, test.IsNil)
-
-	DB("rethinkdb").Table("users").Insert(map[string]string{
-		"id":       "gorethink_test",
-		"password": "password",
-	}).Exec(session)
-
-	session, err = Connect(ConnectOpts{
-		Address:  url,
-		Username: "gorethink_test",
-		Password: "password",
-	})
-	c.Assert(err, test.IsNil)
-
-	_, err = Expr("Hello World").Run(session)
-	c.Assert(err, test.IsNil)
-}
diff --git a/utils.go b/utils.go
index 03c1e2d..160c20b 100644
--- a/utils.go
+++ b/utils.go
@@ -6,8 +6,9 @@ import (
 	"strings"
 	"sync/atomic"
 
-	"gopkg.in/dancannon/gorethink.v2/encoding"
-	p "gopkg.in/dancannon/gorethink.v2/ql2"
+	"gopkg.in/dancannon/gorethink.v1/encoding"
+
+	p "gopkg.in/dancannon/gorethink.v1/ql2"
 )
 
 // Helper functions for constructing terms
-- 
2.9.3

From e2c0c65ed43c8971edd5039d36e7b79a41783d6d Mon Sep 17 00:00:00 2001
From: Guillem Jover <gjover@sipwise.com>
Date: Mon, 17 Oct 2016 13:46:32 +0200
Subject: [PATCH 2/2] Update packaging

---
 debian/changelog                                     | 13 +++++++++++--
 debian/control                                       |  5 ++---
 debian/copyright                                     |  4 ++--
 debian/golang-gopkg-dancannon-gorethink.v1-dev.links |  1 -
 debian/rules                                         |  5 +----
 5 files changed, 16 insertions(+), 12 deletions(-)
 delete mode 100644 debian/golang-gopkg-dancannon-gorethink.v1-dev.links

diff --git a/debian/changelog b/debian/changelog
index c03adf9..dec30d8 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,14 @@
-I have opened a removal request for this package:
- - https://bugs.debian.org/829277
+golang-gopkg-dancannon-gorethink.v1 (1.4.1-2) UNRELEASED; urgency=medium
+
+  * Reintroduce in Debian. (Closes: #NNNNNN)
+  * Use https in debian/copyright Format field.
+  * Rename XS-Go-Import-Path value to the correct name.
+  * Remove unused misc:Built-Using field.
+  * Remove unused links file.
+  * Use _build as build directory.
+  * Bump Standards-Version to 3.9.8 (no changes needed).
+
+ -- Guillem Jover <gjover@sipwise.com>  Fri, 07 Oct 2016 13:15:57 +0200
 
 golang-gopkg-dancannon-gorethink.v1 (1.4.1-1) unstable; urgency=medium
 
diff --git a/debian/control b/debian/control
index 3b9f044..abd79b1 100644
--- a/debian/control
+++ b/debian/control
@@ -11,11 +11,11 @@ Build-Depends: debhelper (>= 9),
                golang-goprotobuf-dev,
                golang-github-hailocab-go-hostpool-dev,
                golang-gopkg-fatih-pool.v2-dev
-Standards-Version: 3.9.6
+Standards-Version: 3.9.8
 Vcs-Git: https://anonscm.debian.org/git/pkg-go/packages/golang-gopkg-dancannon-gorethink.v1.git
 Vcs-Browser: https://anonscm.debian.org/cgit/pkg-go/packages/golang-gopkg-dancannon-gorethink.v1.git
 Homepage: https://github.com/dancannon/gorethink
-XS-Go-Import-Path: github.com/dancannon/gorethink
+XS-Go-Import-Path: gopkg.in/dancannon/gorethink.v1
 
 Package: golang-gopkg-dancannon-gorethink.v1-dev
 Architecture: all
@@ -25,7 +25,6 @@ Depends: ${misc:Depends},
          golang-goprotobuf-dev,
          golang-github-hailocab-go-hostpool-dev,
          golang-gopkg-fatih-pool.v2-dev
-Built-Using: ${misc:Built-Using}
 Description: RethinkDB driver for Go
  RethinkDB >= 2.0 compatible driver. The driver uses a connection
  pool at all times, by default it creates and frees connections
diff --git a/debian/copyright b/debian/copyright
index ea366eb..668a5bc 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,6 +1,6 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: gorethink
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Source: https://github.com/dancannon/gorethink
+Upstream-Name: gorethink
 
 Files: *
 Copyright: 2013 Daniel Cannon <daniel@danielcannon.co.uk>
diff --git a/debian/golang-gopkg-dancannon-gorethink.v1-dev.links b/debian/golang-gopkg-dancannon-gorethink.v1-dev.links
deleted file mode 100644
index f0aa102..0000000
--- a/debian/golang-gopkg-dancannon-gorethink.v1-dev.links
+++ /dev/null
@@ -1 +0,0 @@
-usr/share/gocode/src/github.com/dancannon/gorethink usr/share/gocode/src/gopkg.in/dancannon/gorethink.v1
diff --git a/debian/rules b/debian/rules
index 5620be0..ebe325b 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,10 +1,7 @@
 #!/usr/bin/make -f
-# -*- makefile -*-
-
-TMP     = $(CURDIR)/debian/$(PACKAGE)
 
 %:
-	dh $@ --buildsystem=golang --with=golang
+	dh $@ --buildsystem=golang --with=golang --builddirectory=_build
 
 override_dh_auto_test:
 	# Tests are disabled because most of them
-- 
2.9.3


Reply to: