-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Expose Query interface, needed for result pagination
Add WillSwitchPage and PageState to the Iterator, and an entire Query interface to support it. This allows using gockle for testing result pagination.
- Loading branch information
1 parent
d53e76c
commit 0ae8845
Showing
6 changed files
with
355 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
package gockle | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/gocql/gocql" | ||
"github.com/maraino/go-mock" | ||
) | ||
|
||
// Query represents a CQL query. | ||
type Query interface { | ||
// PageSize will tell the iterator to fetch the result in pages of size n. | ||
PageSize(n int) Query | ||
|
||
// WithContext will set the context to use during a query, it will be used | ||
// to timeout when waiting for responses from Cassandra. | ||
WithContext(ctx context.Context) Query | ||
|
||
// PageState sets the paging state for the query to resume paging from a | ||
// specific point in time. Setting this will disable to query paging for | ||
// this query, and must be used for all subsequent pages. | ||
PageState(state []byte) Query | ||
|
||
// Exec executes the query without returning any rows. | ||
Exec() error | ||
|
||
// Iter executes the query and returns an iterator capable of iterating | ||
// over all results. | ||
Iter() Iterator | ||
|
||
// MapScan executes the query, copies the columns of the first selected row | ||
// into the map pointed at by m and discards the rest. If no rows | ||
// were selected, ErrNotFound is returned. | ||
MapScan(m map[string]interface{}) error | ||
|
||
// Scan executes the query, copies the columns of the first selected row | ||
// into the values pointed at by dest and discards the rest. If no rows | ||
// were selected, ErrNotFound is returned. | ||
Scan(dest ...interface{}) error | ||
|
||
// Release releases a query back into a pool of queries. Released Queries | ||
// cannot be reused. | ||
Release() | ||
} | ||
|
||
var ( | ||
_ Query = QueryMock{} | ||
_ Query = query{} | ||
) | ||
|
||
// QueryMock is a mock Query. See github.com/maraino/go-mock. | ||
type QueryMock struct { | ||
mock.Mock | ||
} | ||
|
||
// PageSize implements Query. | ||
func (m QueryMock) PageSize(n int) Query { | ||
return m.Called(n).Get(0).(Query) | ||
} | ||
|
||
// WithContext implements Query. | ||
func (m QueryMock) WithContext(ctx context.Context) Query { | ||
return m.Called(ctx).Get(0).(Query) | ||
} | ||
|
||
// PageState implements Query. | ||
func (m QueryMock) PageState(state []byte) Query { | ||
return m.Called(state).Get(0).(Query) | ||
} | ||
|
||
// Exec implements Query. | ||
func (m QueryMock) Exec() error { | ||
return m.Called().Error(0) | ||
} | ||
|
||
// Iter implements Query. | ||
func (m QueryMock) Iter() Iterator { | ||
return m.Called().Get(0).(Iterator) | ||
} | ||
|
||
// MapScan implements Query. | ||
func (m QueryMock) MapScan(mm map[string]interface{}) error { | ||
return m.Called(mm).Error(0) | ||
} | ||
|
||
// Scan implements Query. | ||
func (m QueryMock) Scan(dest ...interface{}) error { | ||
return m.Called(dest).Error(0) | ||
} | ||
|
||
// Release implements Query. | ||
func (m QueryMock) Release() { | ||
m.Called() | ||
} | ||
|
||
type query struct { | ||
q *gocql.Query | ||
} | ||
|
||
func (q query) PageSize(n int) Query { | ||
return &query{q: q.q.PageSize(n)} | ||
} | ||
|
||
func (q query) WithContext(ctx context.Context) Query { | ||
return &query{q: q.q.WithContext(ctx)} | ||
} | ||
|
||
func (q query) PageState(state []byte) Query { | ||
return &query{q: q.q.PageState(state)} | ||
} | ||
|
||
func (q query) Exec() error { | ||
return q.q.Exec() | ||
} | ||
|
||
func (q query) Iter() Iterator { | ||
return &iterator{i: q.q.Iter()} | ||
} | ||
|
||
func (q query) MapScan(m map[string]interface{}) error { | ||
return q.q.MapScan(m) | ||
} | ||
|
||
func (q query) Scan(dest ...interface{}) error { | ||
return q.q.Scan(dest...) | ||
} | ||
|
||
func (q query) Release() { | ||
q.q.Release() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package gockle | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func TestQuery(t *testing.T) { | ||
var s = newSession(t) | ||
defer s.Close() | ||
var exec = func(q string) { | ||
if err := s.Exec(q); err != nil { | ||
t.Fatalf("Actual error %v, expected no error", err) | ||
} | ||
} | ||
exec(ksDropIf) | ||
exec(ksCreate) | ||
defer exec(ksDrop) | ||
exec(tabCreate) | ||
defer exec(tabDrop) | ||
exec(rowInsert) | ||
q := s.Query("select * from gockle_test.test"). | ||
PageSize(3). | ||
WithContext(context.Background()). | ||
PageState(nil) | ||
defer q.Release() | ||
if err := q.Exec(); err != nil { | ||
t.Fatalf("Actual error %v, expected no error", err) | ||
} | ||
// Scan | ||
var id, n int | ||
if err := q.Scan(&id, &n); err == nil { | ||
if id != 1 { | ||
t.Errorf("Actual id %v, expected 1", id) | ||
} | ||
if n != 2 { | ||
t.Errorf("Actual n %v, expected 2", n) | ||
} | ||
} else { | ||
t.Errorf("Actual error %v, expected no error", err) | ||
} | ||
// MapScan | ||
var actual = map[string]interface{}{} | ||
var expected = map[string]interface{}{"id": 1, "n": 2} | ||
if err := q.MapScan(actual); err == nil { | ||
if !reflect.DeepEqual(actual, expected) { | ||
t.Errorf("Actual map %v, expected %v", actual, expected) | ||
} | ||
} else { | ||
t.Errorf("Actual error %v, expected no error", err) | ||
} | ||
} | ||
|
||
func TestQueryMock(t *testing.T) { | ||
var m, e = &QueryMock{}, fmt.Errorf("e") | ||
ctx := context.Background() | ||
it := &IteratorMock{} | ||
testMock(t, m, &m.Mock, []struct { | ||
method string | ||
arguments []interface{} | ||
results []interface{} | ||
}{ | ||
{"PageSize", []interface{}{1}, []interface{}{m}}, | ||
{"WithContext", []interface{}{ctx}, []interface{}{m}}, | ||
{"PageState", []interface{}{[]byte{1}}, []interface{}{m}}, | ||
{"Scan", []interface{}{[]interface{}(nil)}, []interface{}{e}}, | ||
{"Scan", []interface{}{[]interface{}{1}}, []interface{}{nil}}, | ||
{"Exec", nil, []interface{}{e}}, | ||
{"Exec", nil, []interface{}{nil}}, | ||
{"Iter", nil, []interface{}{it}}, | ||
{"MapScan", []interface{}{map[string]interface{}(nil)}, []interface{}{nil}}, | ||
{"MapScan", []interface{}{map[string]interface{}{"a": 1}}, []interface{}{e}}, | ||
{"Release", nil, nil}, | ||
}) | ||
} |
Oops, something went wrong.