diff --git a/README.md b/README.md index 57ba85b..3156e02 100644 --- a/README.md +++ b/README.md @@ -30,41 +30,53 @@ p := &Person{ // Insert { - q := Query(qb.Insert("person").Columns("first_name", "last_name", "email").ToCql()) - if err := q.BindStruct(p); err != nil { - t.Fatal("bind:", err) - } - mustExec(q.Query) + stmt, names := qb.Insert("person").Columns("first_name", "last_name", "email").ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + if err := q.BindStruct(p).Exec(); err != nil { + log.Fatal(err) + } +} + +// Insert with TTL +{ + stmt, names := qb.Insert("person").Columns("first_name", "last_name", "email").TTL().ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + if err := q.BindStructMap(p, qb.M{"_ttl": qb.TTL(86400 * time.Second)}).Exec(); err != nil { + log.Fatal(err) + } } // Update { - p.Email = append(p.Email, "patricia1.citzen@gocqlx_test.com") + p.Email = append(p.Email, "patricia1.citzen@gocqlx_test.com") - q := Query(qb.Update("person").Set("email").Where(qb.Eq("first_name"), qb.Eq("last_name")).ToCql()) - if err := q.BindStruct(p); err != nil { - t.Fatal("bind:", err) - } - mustExec(q.Query) + stmt, names := qb.Update("person").Set("email").Where(qb.Eq("first_name"), qb.Eq("last_name")).ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + if err := q.BindStruct(p).Exec(); err != nil { + log.Fatal(err) + } } // Select { - q := Query(qb.Select("person").Where(qb.In("first_name")).ToCql()) - m := map[string]interface{}{ - "first_name": []string{"Patricia", "John"}, - } - if err := q.BindMap(m); err != nil { - t.Fatal("bind:", err) - } + stmt, names := qb.Select("person").Where(qb.In("first_name")).ToCql() + q := gocqlx.Query(session.Query(stmt), names) - var people []Person - if err := gocqlx.Select(&people, q.Query); err != nil { - t.Fatal(err) - } - t.Log(people) + q.BindMap(qb.M{"first_name": []string{"Patricia", "John"}}) + if err := q.Err(); err != nil { + log.Fatal(err) + } - // [{Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com]} {John Doe [johndoeDNE@gmail.net]}] + var people []Person + if err := gocqlx.Select(&people, q.Query); err != nil { + log.Fatal("select:", err) + } + log.Println(people) + + // [{Patricia Citizen [patricia.citzen@com patricia1.citzen@com]} {John Doe [johndoeDNE@gmail.net]}] } ``` diff --git a/benchmark_test.go b/benchmark_test.go index 7852971..c61cd1b 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -102,13 +102,8 @@ func BenchmarkE2EGocqlxInsert(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - // prepare p := people[i%len(people)] - if err := q.BindStruct(p); err != nil { - b.Fatal("bind:", err) - } - // insert - if err := q.Exec(); err != nil { + if err := q.BindStruct(p).Exec(); err != nil { b.Fatal(err) } } @@ -229,10 +224,7 @@ func initTable(b *testing.B, session *gocql.Session, people []*benchPerson) { q := gocqlx.Query(session.Query(stmt), names) for _, p := range people { - if err := q.BindStruct(p); err != nil { - b.Fatal(err) - } - if err := q.Exec(); err != nil { + if err := q.BindStruct(p).Exec(); err != nil { b.Fatal(err) } } diff --git a/example_test.go b/example_test.go index 9aede55..4eba8aa 100644 --- a/example_test.go +++ b/example_test.go @@ -117,9 +117,6 @@ func TestExample(t *testing.T) { // Query builder, using DSL to build queries, using `:name` as the bindvar. { - // helper function for creating session queries - Query := gocqlx.SessionQuery(session) - p := &Person{ "Patricia", "Citizen", @@ -128,43 +125,44 @@ func TestExample(t *testing.T) { // Insert { - q := Query(qb.Insert("gocqlx_test.person").Columns("first_name", "last_name", "email").ToCql()) - if err := q.BindStruct(p); err != nil { - t.Fatal("bind:", err) + stmt, names := qb.Insert("gocqlx_test.person").Columns("first_name", "last_name", "email").ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + if err := q.BindStruct(p).Exec(); err != nil { + t.Fatal(err) } - mustExec(q.Query) } // Insert with TTL { - q := Query(qb.Insert("gocqlx_test.person").Columns("first_name", "last_name", "email").TTL().ToCql()) - if err := q.BindStructMap(p, map[string]interface{}{ - "_ttl": qb.TTL(86400 * time.Second), - }); err != nil { - t.Fatal("bind:", err) + stmt, names := qb.Insert("gocqlx_test.person").Columns("first_name", "last_name", "email").TTL().ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + if err := q.BindStructMap(p, qb.M{"_ttl": qb.TTL(86400 * time.Second)}).Exec(); err != nil { + t.Fatal(err) } - mustExec(q.Query) } // Update { p.Email = append(p.Email, "patricia1.citzen@gocqlx_test.com") - q := Query(qb.Update("gocqlx_test.person").Set("email").Where(qb.Eq("first_name"), qb.Eq("last_name")).ToCql()) - if err := q.BindStruct(p); err != nil { - t.Fatal("bind:", err) + stmt, names := qb.Update("gocqlx_test.person").Set("email").Where(qb.Eq("first_name"), qb.Eq("last_name")).ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + if err := q.BindStruct(p).Exec(); err != nil { + t.Fatal(err) } - mustExec(q.Query) } // Select { - q := Query(qb.Select("gocqlx_test.person").Where(qb.In("first_name")).ToCql()) - m := map[string]interface{}{ - "first_name": []string{"Patricia", "John"}, - } - if err := q.BindMap(m); err != nil { - t.Fatal("bind:", err) + stmt, names := qb.Select("gocqlx_test.person").Where(qb.In("first_name")).ToCql() + q := gocqlx.Query(session.Query(stmt), names) + + q.BindMap(qb.M{"first_name": []string{"Patricia", "John"}}) + if err := q.Err(); err != nil { + t.Fatal(err) } var people []Person @@ -194,10 +192,9 @@ func TestExample(t *testing.T) { []string{"jane.citzen@gocqlx_test.com"}, } - if err := q.BindStruct(p); err != nil { - t.Fatal("bind:", err) + if err := q.BindStruct(p).Exec(); err != nil { + t.Fatal(err) } - mustExec(q.Query) } // bind named parameters from a map @@ -208,10 +205,9 @@ func TestExample(t *testing.T) { "email": []string{"bensmith@allblacks.nz"}, } - if err := q.BindMap(m); err != nil { - t.Fatal("bind:", err) + if err := q.BindMap(m).Exec(); err != nil { + t.Fatal(err) } - mustExec(q.Query) } } } diff --git a/qb/qb.go b/qb/qb.go index ed05c7c..fb3eea6 100644 --- a/qb/qb.go +++ b/qb/qb.go @@ -5,3 +5,6 @@ type Builder interface { // ToCql builds the query into a CQL string and named args. ToCql() (stmt string, names []string) } + +// M is a map. +type M map[string]interface{} diff --git a/queryx.go b/queryx.go index f26392e..09518b5 100644 --- a/queryx.go +++ b/queryx.go @@ -80,6 +80,7 @@ type Queryx struct { *gocql.Query Names []string Mapper *reflectx.Mapper + err error } // Query creates a new Queryx from gocql.Query using a default mapper. @@ -93,29 +94,31 @@ func Query(q *gocql.Query, names []string) Queryx { // BindStruct binds query named parameters to values from arg using mapper. If // value cannot be found error is reported. -func (q Queryx) BindStruct(arg interface{}) error { +func (q *Queryx) BindStruct(arg interface{}) *Queryx { arglist, err := bindStructArgs(q.Names, arg, nil, q.Mapper) if err != nil { - return err + q.err = fmt.Errorf("bind error: %s", err) + } else { + q.err = nil + q.Bind(arglist...) } - q.Bind(arglist...) - - return nil + return q } // BindStructMap binds query named parameters to values from arg0 and arg1 // using a mapper. If value cannot be found in arg0 it's looked up in arg1 // before reporting an error. -func (q Queryx) BindStructMap(arg0 interface{}, arg1 map[string]interface{}) error { +func (q *Queryx) BindStructMap(arg0 interface{}, arg1 map[string]interface{}) *Queryx { arglist, err := bindStructArgs(q.Names, arg0, arg1, q.Mapper) if err != nil { - return err + q.err = fmt.Errorf("bind error: %s", err) + } else { + q.err = nil + q.Bind(arglist...) } - q.Bind(arglist...) - - return nil + return q } func bindStructArgs(names []string, arg0 interface{}, arg1 map[string]interface{}, m *reflectx.Mapper) ([]interface{}, error) { @@ -145,15 +148,16 @@ func bindStructArgs(names []string, arg0 interface{}, arg1 map[string]interface{ } // BindMap binds query named parameters using map. -func (q Queryx) BindMap(arg map[string]interface{}) error { +func (q *Queryx) BindMap(arg map[string]interface{}) *Queryx { arglist, err := bindMapArgs(q.Names, arg) if err != nil { - return err + q.err = fmt.Errorf("bind error: %s", err) + } else { + q.err = nil + q.Bind(arglist...) } - q.Bind(arglist...) - - return nil + return q } func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, error) { @@ -169,6 +173,19 @@ func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, err return arglist, nil } +// Err returns any binding errors. +func (q *Queryx) Err() error { + return q.err +} + +// Exec executes the query without returning any rows. +func (q *Queryx) Exec() error { + if q.err != nil { + return q.err + } + return q.Query.Exec() +} + // QueryFunc creates Queryx from qb.Builder.ToCql() output. type QueryFunc func(stmt string, names []string) Queryx