Skip to content

Commit e2cef02

Browse files
committed
tMerge branch 'release/v1.3.0'
2 parents a124c96 + 0ca68dc commit e2cef02

9 files changed

+126
-151
lines changed

Diff for: CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## v1.3.0 - 2016-01-11
6+
7+
### Added
8+
- Added new error types, the following error types can now be returned: `RQLClientError`, `RQLCompileError`, `RQLDriverCompileError`, `RQLServerCompileError`, `RQLAuthError`, `RQLRuntimeError`, `RQLQueryLogicError`, `RQLNonExistenceError`, `RQLResourceLimitError`, `RQLUserError`, `RQLInternalError`, `RQLTimeoutError`, `RQLAvailabilityError`, `RQLOpFailedError`, `RQLOpIndeterminateError`, `RQLDriverError`, `RQLConnectionError`. Please note that some other errors can be returned.
9+
- Added `IsConnected` function to `Session`.
10+
11+
### Fixed
12+
- Fixed panic when scanning through results caused by incorrect queue implementation.
13+
514
## v1.2.0 - 2015-11-19
615
### Added
716
- Added `UUID` term

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
![GoRethink Logo](https://raw.github.com/wiki/dancannon/gorethink/gopher-and-thinker-s.png "Golang Gopher and RethinkDB Thinker")
1010

11-
Current version: v1.2.0 (RethinkDB v2.2)
11+
Current version: v1.3.0 (RethinkDB v2.2)
1212

1313
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).
1414

Diff for: connection.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const (
2121
type Response struct {
2222
Token int64
2323
Type p.Response_ResponseType `json:"t"`
24+
ErrorType p.Response_ErrorType `json:"e"`
2425
Notes []p.Response_ResponseNote `json:"n"`
2526
Responses []json.RawMessage `json:"r"`
2627
Backtrace []interface{} `json:"b"`
@@ -187,7 +188,7 @@ func (c *Connection) sendQuery(q Query) error {
187188
// Build query
188189
b, err := json.Marshal(q.build())
189190
if err != nil {
190-
return RQLDriverError{"Error building query"}
191+
return RQLDriverError{rqlError("Error building query")}
191192
}
192193

193194
// Set timeout
@@ -200,7 +201,7 @@ func (c *Connection) sendQuery(q Query) error {
200201
// Send the JSON encoding of the query itself.
201202
if err = c.writeQuery(q.Token, b); err != nil {
202203
c.bad = true
203-
return RQLConnectionError{err.Error()}
204+
return RQLConnectionError{rqlError(err.Error())}
204205
}
205206

206207
return nil
@@ -237,14 +238,14 @@ func (c *Connection) readResponse() (*Response, error) {
237238

238239
if _, err := c.read(b, int(messageLength)); err != nil {
239240
c.bad = true
240-
return nil, RQLConnectionError{err.Error()}
241+
return nil, RQLConnectionError{rqlError(err.Error())}
241242
}
242243

243244
// Decode the response
244245
var response = newCachedResponse()
245246
if err := json.Unmarshal(b, response); err != nil {
246247
c.bad = true
247-
return nil, RQLDriverError{err.Error()}
248+
return nil, RQLDriverError{rqlError(err.Error())}
248249
}
249250
response.Token = responseToken
250251

@@ -254,11 +255,11 @@ func (c *Connection) readResponse() (*Response, error) {
254255
func (c *Connection) processResponse(q Query, response *Response) (*Response, *Cursor, error) {
255256
switch response.Type {
256257
case p.Response_CLIENT_ERROR:
257-
return c.processErrorResponse(q, response, RQLClientError{rqlResponseError{response, q.Term}})
258+
return c.processErrorResponse(q, response, RQLClientError{rqlServerError{response, q.Term}})
258259
case p.Response_COMPILE_ERROR:
259-
return c.processErrorResponse(q, response, RQLCompileError{rqlResponseError{response, q.Term}})
260+
return c.processErrorResponse(q, response, RQLCompileError{rqlServerError{response, q.Term}})
260261
case p.Response_RUNTIME_ERROR:
261-
return c.processErrorResponse(q, response, RQLRuntimeError{rqlResponseError{response, q.Term}})
262+
return c.processErrorResponse(q, response, createRuntimeError(response.ErrorType, response, q.Term))
262263
case p.Response_SUCCESS_ATOM, p.Response_SERVER_INFO:
263264
return c.processAtomResponse(q, response)
264265
case p.Response_SUCCESS_PARTIAL:
@@ -269,7 +270,7 @@ func (c *Connection) processResponse(q Query, response *Response) (*Response, *C
269270
return c.processWaitResponse(q, response)
270271
default:
271272
putResponse(response)
272-
return nil, nil, RQLDriverError{"Unexpected response type"}
273+
return nil, nil, RQLDriverError{rqlError("Unexpected response type")}
273274
}
274275
}
275276

Diff for: connection_helper.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
func (c *Connection) writeData(data []byte) error {
1515
_, err := c.Conn.Write(data[:])
1616
if err != nil {
17-
return RQLConnectionError{err.Error()}
17+
return RQLConnectionError{rqlError(err.Error())}
1818
}
1919

2020
return nil
@@ -52,14 +52,14 @@ func (c *Connection) readHandshakeSuccess() error {
5252
if err == io.EOF {
5353
return fmt.Errorf("Unexpected EOF: %s", string(line))
5454
}
55-
return RQLConnectionError{err.Error()}
55+
return RQLConnectionError{rqlError(err.Error())}
5656
}
5757
// convert to string and remove trailing NUL byte
5858
response := string(line[:len(line)-1])
5959
if response != "SUCCESS" {
6060
response = strings.TrimSpace(response)
6161
// we failed authorization or something else terrible happened
62-
return RQLDriverError{fmt.Sprintf("Server dropped connection with message: \"%s\"", response)}
62+
return RQLDriverError{rqlError(fmt.Sprintf("Server dropped connection with message: \"%s\"", response))}
6363
}
6464

6565
return nil

Diff for: cursor.go

+44-106
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ func newCursor(conn *Connection, cursorType string, token int64, term *Term, opt
2626
cursorType: cursorType,
2727
term: term,
2828
opts: opts,
29+
buffer: make([]interface{}, 0),
30+
responses: make([]json.RawMessage, 0),
2931
}
3032

3133
return cursor
@@ -61,8 +63,8 @@ type Cursor struct {
6163
closed bool
6264
finished bool
6365
isAtom bool
64-
buffer queue
65-
responses queue
66+
buffer []interface{}
67+
responses []json.RawMessage
6668
profile interface{}
6769
}
6870

@@ -136,8 +138,8 @@ func (c *Cursor) Close() error {
136138

137139
c.closed = true
138140
c.conn = nil
139-
c.buffer.elems = nil
140-
c.responses.elems = nil
141+
c.buffer = nil
142+
c.responses = nil
141143

142144
return err
143145
}
@@ -183,11 +185,11 @@ func (c *Cursor) loadNextLocked(dest interface{}) (bool, error) {
183185
}
184186

185187
// Check if response is closed/finished
186-
if c.buffer.Len() == 0 && c.responses.Len() == 0 && c.closed {
188+
if len(c.buffer) == 0 && len(c.responses) == 0 && c.closed {
187189
return false, errCursorClosed
188190
}
189191

190-
if c.buffer.Len() == 0 && c.responses.Len() == 0 && !c.finished {
192+
if len(c.buffer) == 0 && len(c.responses) == 0 && !c.finished {
191193
c.mu.Unlock()
192194
err := c.fetchMore()
193195
c.mu.Lock()
@@ -196,42 +198,44 @@ func (c *Cursor) loadNextLocked(dest interface{}) (bool, error) {
196198
}
197199
}
198200

199-
if c.buffer.Len() == 0 && c.responses.Len() == 0 && c.finished {
201+
if len(c.buffer) == 0 && len(c.responses) == 0 && c.finished {
200202
return false, nil
201203
}
202204

203-
if c.buffer.Len() == 0 && c.responses.Len() > 0 {
204-
if response, ok := c.responses.Pop().(json.RawMessage); ok {
205-
var value interface{}
206-
decoder := json.NewDecoder(bytes.NewBuffer(response))
207-
if c.conn.opts.UseJSONNumber {
208-
decoder.UseNumber()
209-
}
210-
err := decoder.Decode(&value)
211-
if err != nil {
212-
return false, err
213-
}
205+
if len(c.buffer) == 0 && len(c.responses) > 0 {
206+
var response json.RawMessage
207+
response, c.responses = c.responses[0], c.responses[1:]
214208

215-
value, err = recursivelyConvertPseudotype(value, c.opts)
216-
if err != nil {
217-
return false, err
218-
}
209+
var value interface{}
210+
decoder := json.NewDecoder(bytes.NewBuffer(response))
211+
if c.conn.opts.UseJSONNumber {
212+
decoder.UseNumber()
213+
}
214+
err := decoder.Decode(&value)
215+
if err != nil {
216+
return false, err
217+
}
219218

220-
// If response is an ATOM then try and convert to an array
221-
if data, ok := value.([]interface{}); ok && c.isAtom {
222-
for _, v := range data {
223-
c.buffer.Push(v)
224-
}
225-
} else if value == nil {
226-
c.buffer.Push(nil)
227-
} else {
228-
c.buffer.Push(value)
219+
value, err = recursivelyConvertPseudotype(value, c.opts)
220+
if err != nil {
221+
return false, err
222+
}
223+
224+
// If response is an ATOM then try and convert to an array
225+
if data, ok := value.([]interface{}); ok && c.isAtom {
226+
for _, v := range data {
227+
c.buffer = append(c.buffer, v)
229228
}
229+
} else if value == nil {
230+
c.buffer = append(c.buffer, nil)
231+
} else {
232+
c.buffer = append(c.buffer, value)
230233
}
231234
}
232235

233-
if c.buffer.Len() > 0 {
234-
data := c.buffer.Pop()
236+
if len(c.buffer) > 0 {
237+
var data interface{}
238+
data, c.buffer = c.buffer[0], c.buffer[1:]
235239

236240
err := encoding.Decode(dest, data)
237241
if err != nil {
@@ -362,25 +366,23 @@ func (c *Cursor) IsNil() bool {
362366
c.mu.RLock()
363367
defer c.mu.RUnlock()
364368

365-
if c.buffer.Len() > 0 {
366-
bufferedItem := c.buffer.Peek()
369+
if len(c.buffer) > 0 {
370+
bufferedItem := c.buffer[0]
367371
if bufferedItem == nil {
368372
return true
369373
}
370374

371375
return false
372376
}
373377

374-
if c.responses.Len() > 0 {
375-
response := c.responses.Peek()
378+
if len(c.responses) > 0 {
379+
response := c.responses[0]
376380
if response == nil {
377381
return true
378382
}
379383

380-
if response, ok := response.(json.RawMessage); ok {
381-
if string(response) == "null" {
382-
return true
383-
}
384+
if string(response) == "null" {
385+
return true
384386
}
385387

386388
return false
@@ -447,7 +449,7 @@ func (c *Cursor) extend(response *Response) {
447449

448450
func (c *Cursor) extendLocked(response *Response) {
449451
for _, response := range response.Responses {
450-
c.responses.Push(response)
452+
c.responses = append(c.responses, response)
451453
}
452454

453455
c.finished = response.Type != p.Response_SUCCESS_PARTIAL
@@ -456,67 +458,3 @@ func (c *Cursor) extendLocked(response *Response) {
456458

457459
putResponse(response)
458460
}
459-
460-
// Queue structure used for storing responses
461-
462-
type queue struct {
463-
elems []interface{}
464-
nelems, popi, pushi int
465-
}
466-
467-
func (q *queue) Len() int {
468-
if len(q.elems) == 0 {
469-
return 0
470-
}
471-
472-
return q.nelems
473-
}
474-
func (q *queue) Push(elem interface{}) {
475-
if q.nelems == len(q.elems) {
476-
q.expand()
477-
}
478-
q.elems[q.pushi] = elem
479-
q.nelems++
480-
q.pushi = (q.pushi + 1) % len(q.elems)
481-
}
482-
func (q *queue) Pop() (elem interface{}) {
483-
if q.nelems == 0 {
484-
return nil
485-
}
486-
elem = q.elems[q.popi]
487-
q.elems[q.popi] = nil // Help GC.
488-
q.nelems--
489-
q.popi = (q.popi + 1) % len(q.elems)
490-
return elem
491-
}
492-
func (q *queue) Peek() (elem interface{}) {
493-
if q.nelems == 0 {
494-
return nil
495-
}
496-
return q.elems[q.popi]
497-
}
498-
func (q *queue) expand() {
499-
curcap := len(q.elems)
500-
var newcap int
501-
if curcap == 0 {
502-
newcap = 8
503-
} else if curcap < 1024 {
504-
newcap = curcap * 2
505-
} else {
506-
newcap = curcap + (curcap / 4)
507-
}
508-
elems := make([]interface{}, newcap)
509-
if q.popi == 0 {
510-
copy(elems, q.elems)
511-
q.pushi = curcap
512-
} else {
513-
newpopi := newcap - (curcap - q.popi)
514-
copy(elems, q.elems[:q.popi])
515-
copy(elems[newpopi:], q.elems[q.popi:])
516-
q.popi = newpopi
517-
}
518-
for i := range q.elems {
519-
q.elems[i] = nil // Help GC.
520-
}
521-
q.elems = elems
522-
}

Diff for: doc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Package gorethink implements a Go driver for RethinkDB
22
//
3-
// Current version: v1.2.0 (RethinkDB v2.2)
3+
// Current version: v1.3.0 (RethinkDB v2.2)
44
// For more in depth information on how to use RethinkDB check out the API docs
55
// at http://rethinkdb.com/api
66
package gorethink

0 commit comments

Comments
 (0)