From 8b6f083cdc7cd91a46a27752c5a5cd2a7a6e1a30 Mon Sep 17 00:00:00 2001 From: Henrik Johansson Date: Fri, 31 May 2019 09:15:02 +0200 Subject: [PATCH] iterx: paging iteration working We used to rely upon NumRows to determine if there are new pages available. This is not correct since the server is allowed to return empty pages with has_more_data flag set and the needed data to do this is not exposed by the gocql driver. We simply remove these checks and let the driver decide when to stop reading. Co-authored-by: Henrik Johansson Co-authored-by: Piotr Sarna --- iterx.go | 17 +---------------- iterx_test.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/iterx.go b/iterx.go index 0fc76bd..6c5ac8e 100644 --- a/iterx.go +++ b/iterx.go @@ -80,11 +80,6 @@ func (iter *Iterx) scanAny(dest interface{}, structOnly bool) bool { return false } - // no results or query error - if iter.Iter.NumRows() == 0 { - return false - } - base := reflectx.Deref(value.Type()) scannable := isScannable(base) @@ -132,11 +127,6 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) bool { return false } - // no results or query error - if iter.Iter.NumRows() == 0 { - return false - } - slice, err := baseType(value.Type(), reflect.Slice) if err != nil { iter.err = err @@ -180,7 +170,7 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) bool { // allocate memory for the page data if !alloc { - v = reflect.MakeSlice(slice, 0, iter.Iter.NumRows()) + v = reflect.MakeSlice(slice, 0, iter.NumRows()) alloc = true } @@ -212,11 +202,6 @@ func (iter *Iterx) StructScan(dest interface{}) bool { return false } - // no results or query error - if iter.Iter.NumRows() == 0 { - return false - } - if !iter.started { columns := columnNames(iter.Iter.Columns()) m := iter.Mapper diff --git a/iterx_test.go b/iterx_test.go index 4d71394..a587951 100644 --- a/iterx_test.go +++ b/iterx_test.go @@ -16,6 +16,7 @@ import ( "github.com/gocql/gocql" "github.com/scylladb/gocqlx" . "github.com/scylladb/gocqlx/gocqlxtest" + "github.com/scylladb/gocqlx/qb" "gopkg.in/inf.v0" ) @@ -327,3 +328,46 @@ func TestNotFound(t *testing.T) { } }) } + +func TestPaging(t *testing.T) { + session := CreateSession(t) + defer session.Close() + if err := ExecStmt(session, `CREATE TABLE gocqlx_test.paging_table (id int PRIMARY KEY, val int)`); err != nil { + t.Fatal("create table:", err) + } + if err := ExecStmt(session, `CREATE INDEX id_val_index ON gocqlx_test.paging_table (val)`); err != nil { + t.Fatal("create index:", err) + } + stmt, names := qb.Insert("gocqlx_test.paging_table").Columns("id", "val").ToCql() + q := gocqlx.Query(session.Query(stmt), names) + for i := 0; i < 5000; i++ { + if err := q.Bind(i, i).Exec(); err != nil { + t.Fatal(err) + } + } + + type Paging struct { + ID int + Val int + } + + t.Run("iter", func(t *testing.T) { + stmt, names := qb.Select("gocqlx_test.paging_table"). + Where(qb.Lt("val")). + AllowFiltering(). + Columns("id", "val").ToCql() + it := gocqlx.Query(session.Query(stmt, 100).PageSize(10), names).Iter() + defer it.Close() + var cnt int + for { + p := &Paging{} + if !it.StructScan(p) { + break + } + cnt++ + } + if cnt != 100 { + t.Fatal("expected 100", "got", cnt) + } + }) +}