diff --git a/README.md b/README.md index c2cedeb..e1d6045 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ type Person struct { Email []string } -// Insert with query parameters bound from struct. +// Bind query parameters from a struct. { - p := &Person{ + p := Person{ "Patricia", "Citizen", []string{"patricia.citzen@gocqlx_test.com"}, @@ -41,49 +41,42 @@ type Person struct { Columns("first_name", "last_name", "email"). ToCql() - q := gocqlx.Query(session.Query(stmt), names).BindStruct(p) - - if err := q.ExecRelease(); err != nil { + err := gocqlx.Query(session.Query(stmt), names).BindStruct(&p).ExecRelease() + if err != nil { t.Fatal(err) } } -// Get the first result into a struct. +// Load the first result into a struct. { stmt, names := qb.Select("gocqlx_test.person"). Where(qb.Eq("first_name")). ToCql() + var p Person + q := gocqlx.Query(session.Query(stmt), names).BindMap(qb.M{ "first_name": "Patricia", }) - - var p Person - if err := gocqlx.Get(&p, q.Query); err != nil { - t.Fatal("get:", err) + if err := q.GetRelease(&p); err != nil { + t.Fatal(err) } - - t.Log(p) - // {Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com]} } -// Select, load all the results into a slice. +// Load all the results into a slice. { stmt, names := qb.Select("gocqlx_test.person"). Where(qb.In("first_name")). ToCql() + var people []Person + q := gocqlx.Query(session.Query(stmt), names).BindMap(qb.M{ "first_name": []string{"Patricia", "Igy", "Ian"}, }) - - var people []Person - if err := gocqlx.Select(&people, q.Query); err != nil { - t.Fatal("select:", err) + if err := q.SelectRelease(&people); err != nil { + t.Fatal(err) } - - t.Log(people) - // [{Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com]} {Igy Citizen [igy.citzen@gocqlx_test.com]} {Ian Citizen [ian.citzen@gocqlx_test.com]}] } ``` diff --git a/example_test.go b/example_test.go index 50ca51e..ab4df81 100644 --- a/example_test.go +++ b/example_test.go @@ -38,26 +38,25 @@ func TestExample(t *testing.T) { t.Fatal("create table:", err) } - p := &Person{ + p := Person{ "Patricia", "Citizen", []string{"patricia.citzen@gocqlx_test.com"}, } - // Insert with query parameters bound from struct. + // Bind query parameters from struct. { stmt, names := qb.Insert("gocqlx_test.person"). Columns("first_name", "last_name", "email"). ToCql() - q := gocqlx.Query(session.Query(stmt), names).BindStruct(p) - - if err := q.ExecRelease(); err != nil { + err := gocqlx.Query(session.Query(stmt), names).BindStruct(&p).ExecRelease() + if err != nil { t.Fatal(err) } } - // Insert with query parameters bound from struct extended with a map. + // Bind query parameters from struct and map. { stmt, names := qb.Insert("gocqlx_test.person"). Columns("first_name", "last_name", "email"). @@ -67,13 +66,12 @@ func TestExample(t *testing.T) { q := gocqlx.Query(session.Query(stmt), names).BindStructMap(p, qb.M{ "_ttl": qb.TTL(86400 * time.Second), }) - if err := q.ExecRelease(); err != nil { t.Fatal(err) } } - // Easy update with all parameters bound from struct. + // Update with query parameters from struct. { p.Email = append(p.Email, "patricia1.citzen@gocqlx_test.com") @@ -82,14 +80,13 @@ func TestExample(t *testing.T) { Where(qb.Eq("first_name"), qb.Eq("last_name")). ToCql() - q := gocqlx.Query(session.Query(stmt), names).BindStruct(p) - - if err := q.ExecRelease(); err != nil { + err := gocqlx.Query(session.Query(stmt), names).BindStruct(p).ExecRelease() + if err != nil { t.Fatal(err) } } - // Advanced update, adding and removing elements to collections and counters. + // Adding and removing elements to collections and counters. { stmt, names := qb.Update("gocqlx_test.person"). AddNamed("email", "new_email"). @@ -99,13 +96,12 @@ func TestExample(t *testing.T) { q := gocqlx.Query(session.Query(stmt), names).BindStructMap(p, qb.M{ "new_email": []string{"patricia2.citzen@gocqlx_test.com", "patricia3.citzen@gocqlx_test.com"}, }) - if err := q.ExecRelease(); err != nil { t.Fatal(err) } } - // Batch insert two rows in a single query, advanced struct binding. + // Batch insert two rows in a single query. { i := qb.Insert("gocqlx_test.person").Columns("first_name", "last_name", "email") @@ -130,54 +126,51 @@ func TestExample(t *testing.T) { }, } - q := gocqlx.Query(session.Query(stmt), names).BindStruct(&batch) - - if err := q.ExecRelease(); err != nil { + err := gocqlx.Query(session.Query(stmt), names).BindStruct(&batch).ExecRelease() + if err != nil { t.Fatal(err) } } - // Get the first result into a struct. + // Load the first result into a struct. { stmt, names := qb.Select("gocqlx_test.person"). Where(qb.Eq("first_name")). ToCql() + var p Person + q := gocqlx.Query(session.Query(stmt), names).BindMap(qb.M{ "first_name": "Patricia", }) - defer q.Release() - - var p Person - if err := gocqlx.Get(&p, q.Query); err != nil { - t.Fatal("get:", err) + if err := q.GetRelease(&p); err != nil { + t.Fatal(err) } t.Log(p) // {Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com patricia2.citzen@gocqlx_test.com patricia3.citzen@gocqlx_test.com]} } - // Select, load all the results into a slice. + // Load all the results into a slice. { stmt, names := qb.Select("gocqlx_test.person"). Where(qb.In("first_name")). ToCql() + var people []Person + q := gocqlx.Query(session.Query(stmt), names).BindMap(qb.M{ "first_name": []string{"Patricia", "Igy", "Ian"}, }) - defer q.Release() - - var people []Person - if err := gocqlx.Select(&people, q.Query); err != nil { - t.Fatal("select:", err) + if err := q.SelectRelease(&people); err != nil { + t.Fatal(err) } t.Log(people) // [{Ian Citizen [ian.citzen@gocqlx_test.com]} {Igy Citizen [igy.citzen@gocqlx_test.com]} {Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com patricia2.citzen@gocqlx_test.com patricia3.citzen@gocqlx_test.com]}] } - // Easy token based pagination. + // Token based pagination. { p := &Person{ "Ian", @@ -191,12 +184,11 @@ func TestExample(t *testing.T) { Limit(10). ToCql() - q := gocqlx.Query(session.Query(stmt), names).BindStruct(p) - defer q.Release() - var people []Person - if err := gocqlx.Select(&people, q.Query); err != nil { - t.Fatal("select:", err) + + err := gocqlx.Query(session.Query(stmt), names).BindStruct(p).SelectRelease(&people) + if err != nil { + t.Fatal(err) } t.Log(people) @@ -213,12 +205,11 @@ func TestExample(t *testing.T) { stmt, names, err := gocqlx.CompileNamedQuery([]byte("INSERT INTO gocqlx_test.person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)")) if err != nil { - t.Fatal("compile:", err) + t.Fatal(err) } - q := gocqlx.Query(session.Query(stmt), names).BindStruct(p) - - if err := q.ExecRelease(); err != nil { + err = gocqlx.Query(session.Query(stmt), names).BindStruct(p).ExecRelease() + if err != nil { t.Fatal(err) } } diff --git a/iterx.go b/iterx.go index 6594296..6ef52c0 100644 --- a/iterx.go +++ b/iterx.go @@ -14,11 +14,15 @@ import ( ) // Get is a convenience function for creating iterator and calling Get. +// +// DEPRECATED use Queryx.Get or Queryx.GetRelease. func Get(dest interface{}, q *gocql.Query) error { return Iter(q).Get(dest) } // Select is a convenience function for creating iterator and calling Select. +// +// DEPRECATED use Queryx.Select or Queryx.SelectRelease. func Select(dest interface{}, q *gocql.Query) error { return Iter(q).Select(dest) } @@ -53,9 +57,11 @@ func (iter *Iterx) Unsafe() *Iterx { } // Get scans first row into a destination and closes the iterator. If the -// destination type is a Struct, then StructScan will be used. If the -// destination is some other type, then the row must only have one column which -// can scan into that type. If no rows were selected, ErrNotFound is returned. +// destination type is a struct pointer, then StructScan will be used. +// If the destination is some other type, then the row must only have one column +// which can scan into that type. +// +// If no rows were selected, ErrNotFound is returned. func (iter *Iterx) Get(dest interface{}) error { iter.scanAny(dest, false) iter.Close() @@ -99,10 +105,13 @@ func (iter *Iterx) scanAny(dest interface{}, structOnly bool) bool { return iter.StructScan(dest) } -// Select scans all rows into a destination, which must be a slice of any type -// and closes the iterator. If the destination slice type is a Struct, then -// 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. +// Select scans all rows into a destination, which must be a pointer to slice +// of any type and closes the iterator. If the destination slice type is +// a struct, then 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. +// +// If no rows were selected, ErrNotFound is NOT returned. func (iter *Iterx) Select(dest interface{}) error { iter.scanAll(dest, false) iter.Close() @@ -191,7 +200,7 @@ func (iter *Iterx) scanAll(dest interface{}, structOnly bool) bool { } // StructScan is like gocql.Iter.Scan, but scans a single row into a single -// Struct. Use this and iterate manually when the memory load of Select() might +// struct. Use this and iterate manually when the memory load of Select() might // be prohibitive. StructScan caches the reflect work of matching up column // positions to fields to avoid that overhead per scan, which means it is not // safe to run StructScan on the same Iterx instance with different struct diff --git a/queryx.go b/queryx.go index 5d03691..e9fd4c7 100644 --- a/queryx.go +++ b/queryx.go @@ -191,9 +191,49 @@ func (q *Queryx) Exec() error { return q.Query.Exec() } -// ExecRelease performs exec and releases the query, a released query cannot be +// ExecRelease calls Exec and releases the query, a released query cannot be // reused. func (q *Queryx) ExecRelease() error { defer q.Release() return q.Exec() } + +// Get scans first row into a destination. If the destination type is a struct +// pointer, then Iter.StructScan will be used. If the destination is some +// other type, then the row must only have one column which can scan into that +// type. +// +// If no rows were selected, ErrNotFound is returned. +func (q *Queryx) Get(dest interface{}) error { + if q.err != nil { + return q.err + } + return Iter(q.Query).Get(dest) +} + +// GetRelease calls Get and releases the query, a released query cannot be +// reused. +func (q *Queryx) GetRelease(dest interface{}) error { + defer q.Release() + return q.Get(dest) +} + +// Select scans all rows into a destination, which must be a pointer to slice +// of any type. If the destination slice type is a struct, then Iter.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. +// +// If no rows were selected, ErrNotFound is NOT returned. +func (q *Queryx) Select(dest interface{}) error { + if q.err != nil { + return q.err + } + return Iter(q.Query).Select(dest) +} + +// SelectRelease calls Select and releases the query, a released query cannot be +// reused. +func (q *Queryx) SelectRelease(dest interface{}) error { + defer q.Release() + return q.Select(dest) +}