release query

This commit is contained in:
Michał Matczuk
2017-07-25 09:13:47 +02:00
parent 6a6b1c8801
commit 51c33ef077
2 changed files with 31 additions and 9 deletions

View File

@@ -89,10 +89,10 @@ func TestExample(t *testing.T) {
for iter.StructScan(&place) { for iter.StructScan(&place) {
fmt.Printf("%#v\n", place) fmt.Printf("%#v\n", place)
} }
iter.Close() if err := iter.Close(); err != nil {
if err := iter.Err(); err != nil {
t.Fatal("iter:", err) t.Fatal("iter:", err)
} }
iter.ReleaseQuery()
// gocqlx_test.Place{Country:"Hong Kong", City:"", TelCode:852} // gocqlx_test.Place{Country:"Hong Kong", City:"", TelCode:852}
// gocqlx_test.Place{Country:"United States", City:"New York", TelCode:1} // gocqlx_test.Place{Country:"United States", City:"New York", TelCode:1}
// gocqlx_test.Place{Country:"Singapore", City:"", TelCode:65} // gocqlx_test.Place{Country:"Singapore", City:"", TelCode:65}

View File

@@ -29,19 +29,22 @@ func Select(dest interface{}, q *gocql.Query) error {
// Iterx is a wrapper around gocql.Iter which adds struct scanning capabilities. // Iterx is a wrapper around gocql.Iter which adds struct scanning capabilities.
type Iterx struct { type Iterx struct {
*gocql.Iter *gocql.Iter
query *gocql.Query
err error
unsafe bool unsafe bool
Mapper *reflectx.Mapper Mapper *reflectx.Mapper
// these fields cache memory use for a rows during iteration w/ structScan // these fields cache memory use for a rows during iteration w/ structScan
started bool started bool
fields [][]int fields [][]int
values []interface{} values []interface{}
err error
} }
// Iter creates a new Iterx from gocql.Query using a default mapper. // Iter creates a new Iterx from gocql.Query using a default mapper.
func Iter(q *gocql.Query) *Iterx { func Iter(q *gocql.Query) *Iterx {
return &Iterx{ return &Iterx{
Iter: q.Iter(), Iter: q.Iter(),
query: q,
Mapper: DefaultMapper, Mapper: DefaultMapper,
} }
} }
@@ -51,11 +54,16 @@ func Iter(q *gocql.Query) *Iterx {
// destination is some other type, then the row must only have one column which // destination is some other type, then the row must only have one column which
// can scan into that type. // can scan into that type.
func (iter *Iterx) Get(dest interface{}) error { func (iter *Iterx) Get(dest interface{}) error {
if iter.query == nil {
return errors.New("using released query")
}
if err := iter.scanAny(dest, false); err != nil { if err := iter.scanAny(dest, false); err != nil {
iter.err = err iter.err = err
} }
iter.Close() iter.Close()
iter.ReleaseQuery()
return iter.err return iter.err
} }
@@ -86,7 +94,7 @@ func (iter *Iterx) scanAny(dest interface{}, structOnly bool) error {
iter.Scan(dest) iter.Scan(dest)
} }
return nil return iter.err
} }
// Select scans all rows into a destination, which must be a slice of any type // Select scans all rows into a destination, which must be a slice of any type
@@ -94,11 +102,16 @@ func (iter *Iterx) scanAny(dest interface{}, structOnly bool) error {
// StructScan will be used on each row. If the destination is some other type, // StructScan will be used on each row. If the destination is some other type,
// then each row must only have one column which can scan into that type. // then each row must only have one column which can scan into that type.
func (iter *Iterx) Select(dest interface{}) error { func (iter *Iterx) Select(dest interface{}) error {
if iter.query == nil {
return errors.New("using released query")
}
if err := iter.scanAll(dest, false); err != nil { if err := iter.scanAll(dest, false); err != nil {
iter.err = err iter.err = err
} }
iter.Close() iter.Close()
iter.ReleaseQuery()
return iter.err return iter.err
} }
@@ -167,7 +180,7 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) error {
} }
} }
return iter.Err() return iter.err
} }
// StructScan is like gocql.Scan, but scans a single row into a single Struct. // StructScan is like gocql.Scan, but scans a single row into a single Struct.
@@ -177,6 +190,11 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) error {
// safe to run StructScan on the same Iterx instance with different struct // safe to run StructScan on the same Iterx instance with different struct
// types. // types.
func (iter *Iterx) StructScan(dest interface{}) bool { func (iter *Iterx) StructScan(dest interface{}) bool {
if iter.query == nil {
iter.err = errors.New("using released query")
return false
}
v := reflect.ValueOf(dest) v := reflect.ValueOf(dest)
if v.Kind() != reflect.Ptr { if v.Kind() != reflect.Ptr {
iter.err = errors.New("must pass a pointer, not a value, to StructScan destination") iter.err = errors.New("must pass a pointer, not a value, to StructScan destination")
@@ -221,12 +239,16 @@ func (iter *Iterx) Close() error {
if err != nil && iter.err == nil { if err != nil && iter.err == nil {
iter.err = err iter.err = err
} }
return err return iter.err
} }
// Err returns the error encountered while scanning. // ReleaseQuery releases underling query back into a pool of queries. Note that
func (iter *Iterx) Err() error { // the iterator needs to be closed first.
return iter.err func (iter *Iterx) ReleaseQuery() {
if iter.query != nil {
iter.query.Release()
iter.query = nil
}
} }
// structOnlyError returns an error appropriate for type when a non-scannable // structOnlyError returns an error appropriate for type when a non-scannable