qb: doc
This commit is contained in:
89
README.md
89
README.md
@@ -1,6 +1,7 @@
|
||||
# gocqlx [](http://godoc.org/github.com/scylladb/gocqlx) [](https://goreportcard.com/report/github.com/scylladb/gocqlx) [](https://travis-ci.org/scylladb/gocqlx)
|
||||
|
||||
Package `gocqlx` is a `gocql` extension, similar to what `sqlx` is to `database/sql`.
|
||||
Package `gocqlx` is a Scylla / Cassandra productivity toolkit for `gocql`, it's
|
||||
similar to what `sqlx` is to `database/sql`.
|
||||
|
||||
It contains wrappers over `gocql` types that provide convenience methods which
|
||||
are useful in the development of database driven applications. Under the
|
||||
@@ -12,43 +13,59 @@ hood it uses `sqlx/reflectx` package so `sqlx` models will also work with `gocql
|
||||
|
||||
## Features
|
||||
|
||||
Read all rows into a slice.
|
||||
Fast, boilerplate free and flexible `SELECTS`, `INSERTS`, `UPDATES` and `DELETES`.
|
||||
|
||||
```go
|
||||
var v []*Item
|
||||
if err := gocqlx.Select(&v, session.Query(`SELECT * FROM items WHERE id = ?`, id)); err != nil {
|
||||
log.Fatal("select failed", err)
|
||||
type Person struct {
|
||||
FirstName string // no need to add `db:"first_name"` etc.
|
||||
LastName string
|
||||
Email []string
|
||||
}
|
||||
|
||||
p := &Person{
|
||||
"Patricia",
|
||||
"Citizen",
|
||||
[]string{"patricia.citzen@gocqlx_test.com"},
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
var people []Person
|
||||
if err := gocqlx.Select(&people, q.Query); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(people)
|
||||
|
||||
// [{Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com]} {John Doe [johndoeDNE@gmail.net]}]
|
||||
}
|
||||
```
|
||||
|
||||
Read a single row into a struct.
|
||||
|
||||
```go
|
||||
var v Item
|
||||
if err := gocqlx.Get(&v, session.Query(`SELECT * FROM items WHERE id = ?`, id)); err != nil {
|
||||
log.Fatal("get failed", err)
|
||||
}
|
||||
```
|
||||
|
||||
Bind named query parameters from a struct or map.
|
||||
|
||||
```go
|
||||
stmt, names, err := gocqlx.CompileNamedQuery([]byte("INSERT INTO items (id, name) VALUES (:id, :name)"))
|
||||
if err != nil {
|
||||
t.Fatal("compile:", err)
|
||||
}
|
||||
q := gocqlx.Queryx{
|
||||
Query: session.Query(stmt),
|
||||
Names: names,
|
||||
}
|
||||
if err := q.BindStruct(&Item{"id", "name"}); err != nil {
|
||||
t.Fatal("bind:", err)
|
||||
}
|
||||
if err := q.Query.Exec(); err != nil {
|
||||
log.Fatal("get failed", err)
|
||||
}
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
See [example test](https://github.com/scylladb/gocqlx/blob/master/example_test.go).
|
||||
For more details see [example test](https://github.com/scylladb/gocqlx/blob/master/example_test.go).
|
||||
|
||||
35
doc.go
35
doc.go
@@ -1,38 +1,7 @@
|
||||
// Package gocqlx is a gocql extension, similar to what sqlx is to database/sql.
|
||||
// Package gocqlx is a Scylla / Cassandra productivity toolkit for `gocql`, it's
|
||||
// similar to what `sqlx` is to `database/sql`.
|
||||
//
|
||||
// It contains wrappers over gocql types that provide convenience methods which
|
||||
// are useful in the development of database driven applications. Under the
|
||||
// hood it uses sqlx/reflectx package so sqlx models will also work with gocqlx.
|
||||
//
|
||||
// Example, read all rows into a slice
|
||||
//
|
||||
// var v []*Item
|
||||
// if err := gocqlx.Select(&v, session.Query(`SELECT * FROM items WHERE id = ?`, id)); err != nil {
|
||||
// log.Fatal("select failed", err)
|
||||
// }
|
||||
//
|
||||
// Example, read a single row into a struct
|
||||
//
|
||||
// var v Item
|
||||
// if err := gocqlx.Get(&v, session.Query(`SELECT * FROM items WHERE id = ?`, id)); err != nil {
|
||||
// log.Fatal("get failed", err)
|
||||
// }
|
||||
//
|
||||
// Example, bind named query parameters from a struct or map
|
||||
//
|
||||
// stmt, names, err := gocqlx.CompileNamedQuery([]byte("INSERT INTO items (id, name) VALUES (:id, :name)"))
|
||||
// if err != nil {
|
||||
// t.Fatal("compile:", err)
|
||||
// }
|
||||
// q := gocqlx.Queryx{
|
||||
// Query: session.Query(stmt),
|
||||
// Names: names,
|
||||
// }
|
||||
// if err := q.BindStruct(&Item{"id", "name"}); err != nil {
|
||||
// t.Fatal("bind:", err)
|
||||
// }
|
||||
// if err := q.Query.Exec(); err != nil {
|
||||
// log.Fatal("get failed", err)
|
||||
// }
|
||||
//
|
||||
package gocqlx
|
||||
|
||||
141
example_test.go
141
example_test.go
@@ -3,11 +3,11 @@
|
||||
package gocqlx_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/gocql/gocql"
|
||||
"github.com/scylladb/gocqlx"
|
||||
"github.com/scylladb/gocqlx/qb"
|
||||
)
|
||||
|
||||
var personSchema = `
|
||||
@@ -27,7 +27,7 @@ CREATE TABLE gocqlx_test.place (
|
||||
)`
|
||||
|
||||
// Field names are converted to camel case by default, no need to add
|
||||
// `db:"first_name"`, if you want to disable a filed add `db:"-"` tag
|
||||
// `db:"first_name"`, if you want to disable a filed add `db:"-"` tag.
|
||||
type Person struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
@@ -46,13 +46,15 @@ func TestExample(t *testing.T) {
|
||||
|
||||
mustExec := func(q *gocql.Query) {
|
||||
if err := q.Exec(); err != nil {
|
||||
t.Fatal("insert:", q, err)
|
||||
t.Fatal("query:", q, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Fill person table
|
||||
// Fill person table.
|
||||
{
|
||||
mustExec(session.Query(personSchema))
|
||||
if err := createTable(session, personSchema); err != nil {
|
||||
t.Fatal("create table:", err)
|
||||
}
|
||||
|
||||
q := session.Query("INSERT INTO gocqlx_test.person (first_name, last_name, email) VALUES (?, ?, ?)")
|
||||
mustExec(q.Bind("Jason", "Moiron", []string{"jmoiron@jmoiron.net"}))
|
||||
@@ -60,9 +62,11 @@ func TestExample(t *testing.T) {
|
||||
q.Release()
|
||||
}
|
||||
|
||||
// Fill place table
|
||||
// Fill place table.
|
||||
{
|
||||
mustExec(session.Query(placeSchema))
|
||||
if err := createTable(session, placeSchema); err != nil {
|
||||
t.Fatal("create table:", err)
|
||||
}
|
||||
|
||||
q := session.Query("INSERT INTO gocqlx_test.place (country, city, code) VALUES (?, ?, ?)")
|
||||
mustExec(q.Bind("United States", "New York", 1))
|
||||
@@ -71,72 +75,131 @@ func TestExample(t *testing.T) {
|
||||
q.Release()
|
||||
}
|
||||
|
||||
// Query the database, storing results in a []Person (wrapped in []interface{})
|
||||
// Query the database, storing results in a []Person (wrapped in []interface{}).
|
||||
{
|
||||
people := []Person{}
|
||||
var people []Person
|
||||
if err := gocqlx.Select(&people, session.Query("SELECT * FROM person")); err != nil {
|
||||
t.Fatal("select:", err)
|
||||
}
|
||||
t.Log(people)
|
||||
|
||||
fmt.Printf("%#v\n%#v\n", people[0], people[1])
|
||||
// gocqlx_test.Person{FirstName:"John", LastName:"Doe", Email:[]string{"johndoeDNE@gmail.net"}}
|
||||
// gocqlx_test.Person{FirstName:"Jason", LastName:"Moiron", Email:[]string{"jmoiron@jmoiron.net"}}
|
||||
// [{John Doe [johndoeDNE@gmail.net]} {Jason Moiron [jmoiron@jmoiron.net]}]
|
||||
}
|
||||
|
||||
// Get a single result, a la QueryRow
|
||||
// Get a single result.
|
||||
{
|
||||
var jason Person
|
||||
if err := gocqlx.Get(&jason, session.Query("SELECT * FROM person WHERE first_name=?", "Jason")); err != nil {
|
||||
t.Fatal("get:", err)
|
||||
}
|
||||
fmt.Printf("%#v\n", jason)
|
||||
// gocqlx_test.Person{FirstName:"Jason", LastName:"Moiron", Email:[]string{"jmoiron@jmoiron.net"}}
|
||||
t.Log(jason)
|
||||
|
||||
// Jason Moiron [jmoiron@jmoiron.net]}
|
||||
}
|
||||
|
||||
// Loop through rows using only one struct
|
||||
// Loop through rows using only one struct.
|
||||
{
|
||||
var place Place
|
||||
iter := gocqlx.Iter(session.Query("SELECT * FROM place"))
|
||||
for iter.StructScan(&place) {
|
||||
fmt.Printf("%#v\n", place)
|
||||
t.Log(place)
|
||||
}
|
||||
if err := iter.Close(); err != nil {
|
||||
t.Fatal("iter:", err)
|
||||
}
|
||||
iter.ReleaseQuery()
|
||||
// gocqlx_test.Place{Country:"Hong Kong", City:"", TelCode:852}
|
||||
// gocqlx_test.Place{Country:"United States", City:"New York", TelCode:1}
|
||||
// gocqlx_test.Place{Country:"Singapore", City:"", TelCode:65}
|
||||
|
||||
// {Hong Kong 852}
|
||||
// {United States New York 1}
|
||||
// {Singapore 65}
|
||||
}
|
||||
|
||||
// Named queries, using `:name` as the bindvar
|
||||
// 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",
|
||||
[]string{"patricia.citzen@gocqlx_test.com"},
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Update
|
||||
{
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
var people []Person
|
||||
if err := gocqlx.Select(&people, q.Query); err != nil {
|
||||
t.Fatal("select:", err)
|
||||
}
|
||||
t.Log(people)
|
||||
|
||||
// [{Patricia Citizen [patricia.citzen@gocqlx_test.com patricia1.citzen@gocqlx_test.com]} {John Doe [johndoeDNE@gmail.net]}]
|
||||
}
|
||||
}
|
||||
|
||||
// Named queries, using `:name` as the bindvar.
|
||||
{
|
||||
// compile query to valid gocqlx query and list of named parameters
|
||||
stmt, names, err := gocqlx.CompileNamedQuery([]byte("INSERT INTO person (first_name, last_name, email) VALUES (:first_name, :last_name, :email)"))
|
||||
if err != nil {
|
||||
t.Fatal("compile:", err)
|
||||
}
|
||||
q := gocqlx.Query(session.Query(stmt), names)
|
||||
|
||||
q := gocqlx.Queryx{
|
||||
Query: session.Query(stmt),
|
||||
Names: names,
|
||||
// bind named parameters from a struct
|
||||
{
|
||||
p := &Person{
|
||||
"Jane",
|
||||
"Citizen",
|
||||
[]string{"jane.citzen@gocqlx_test.com"},
|
||||
}
|
||||
|
||||
if err := q.BindStruct(p); err != nil {
|
||||
t.Fatal("bind:", err)
|
||||
}
|
||||
mustExec(q.Query)
|
||||
}
|
||||
|
||||
if err := q.BindStruct(&Person{
|
||||
"Jane",
|
||||
"Citizen",
|
||||
[]string{"jane.citzen@gocqlx_test.com"},
|
||||
}); err != nil {
|
||||
t.Fatal("bind:", err)
|
||||
}
|
||||
mustExec(q.Query)
|
||||
// bind named parameters from a map
|
||||
{
|
||||
m := map[string]interface{}{
|
||||
"first_name": "Bin",
|
||||
"last_name": "Smuth",
|
||||
"email": []string{"bensmith@allblacks.nz"},
|
||||
}
|
||||
|
||||
if err := q.BindMap(map[string]interface{}{
|
||||
"first_name": "Bin",
|
||||
"last_name": "Smuth",
|
||||
"email": []string{"bensmith@allblacks.nz"},
|
||||
}); err != nil {
|
||||
t.Fatal("bind:", err)
|
||||
if err := q.BindMap(m); err != nil {
|
||||
t.Fatal("bind:", err)
|
||||
}
|
||||
mustExec(q.Query)
|
||||
}
|
||||
mustExec(q.Query)
|
||||
}
|
||||
}
|
||||
|
||||
16
qb/cmp.go
16
qb/cmp.go
@@ -2,6 +2,7 @@ package qb
|
||||
|
||||
import "bytes"
|
||||
|
||||
// op specifies Cmd operation type.
|
||||
type op byte
|
||||
|
||||
const (
|
||||
@@ -14,6 +15,7 @@ const (
|
||||
cnt
|
||||
)
|
||||
|
||||
// Cmp if a filtering comparator that is used in WHERE and IF clauses.
|
||||
type Cmp struct {
|
||||
op op
|
||||
column string
|
||||
@@ -45,6 +47,7 @@ func (cmp Cmp) writeCql(cql *bytes.Buffer) string {
|
||||
return cmp.name
|
||||
}
|
||||
|
||||
// Eq produces column=?.
|
||||
func Eq(column string) Cmp {
|
||||
return Cmp{
|
||||
op: eq,
|
||||
@@ -53,6 +56,7 @@ func Eq(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// EqNamed produces column=? with a custom parameter name.
|
||||
func EqNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: eq,
|
||||
@@ -61,6 +65,7 @@ func EqNamed(column, name string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// Lt produces column<?.
|
||||
func Lt(column string) Cmp {
|
||||
return Cmp{
|
||||
op: lt,
|
||||
@@ -69,6 +74,7 @@ func Lt(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// LtNamed produces column<? with a custom parameter name.
|
||||
func LtNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: lt,
|
||||
@@ -77,6 +83,7 @@ func LtNamed(column, name string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// LtOrEq produces column<=?.
|
||||
func LtOrEq(column string) Cmp {
|
||||
return Cmp{
|
||||
op: leq,
|
||||
@@ -85,6 +92,7 @@ func LtOrEq(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// LtOrEqNamed produces column<=? with a custom parameter name.
|
||||
func LtOrEqNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: leq,
|
||||
@@ -93,6 +101,7 @@ func LtOrEqNamed(column, name string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// Gt produces column>?.
|
||||
func Gt(column string) Cmp {
|
||||
return Cmp{
|
||||
op: gt,
|
||||
@@ -101,6 +110,7 @@ func Gt(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// GtNamed produces column>? with a custom parameter name.
|
||||
func GtNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: gt,
|
||||
@@ -109,6 +119,7 @@ func GtNamed(column, name string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// GtOrEq produces column>=?.
|
||||
func GtOrEq(column string) Cmp {
|
||||
return Cmp{
|
||||
op: geq,
|
||||
@@ -117,6 +128,7 @@ func GtOrEq(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// GtOrEqNamed produces column>=? with a custom parameter name.
|
||||
func GtOrEqNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: geq,
|
||||
@@ -125,6 +137,7 @@ func GtOrEqNamed(column, name string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// In produces column IN ?.
|
||||
func In(column string) Cmp {
|
||||
return Cmp{
|
||||
op: in,
|
||||
@@ -133,6 +146,7 @@ func In(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// InNamed produces column IN ? with a custom parameter name.
|
||||
func InNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: in,
|
||||
@@ -141,6 +155,7 @@ func InNamed(column, name string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// Contains produces column CONTAINS ?.
|
||||
func Contains(column string) Cmp {
|
||||
return Cmp{
|
||||
op: cnt,
|
||||
@@ -149,6 +164,7 @@ func Contains(column string) Cmp {
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsNamed produces column CONTAINS ? with a custom parameter name.
|
||||
func ContainsNamed(column, name string) Cmp {
|
||||
return Cmp{
|
||||
op: cnt,
|
||||
|
||||
10
qb/delete.go
10
qb/delete.go
@@ -1,13 +1,14 @@
|
||||
package qb
|
||||
|
||||
// DELETE reference:
|
||||
// http://docs.datastax.com/en/dse/5.1/cql/cql/cql_reference/cql_commands/cqlDelete.html
|
||||
// https://cassandra.apache.org/doc/latest/cql/dml.html#delete
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DeleteBuilder builds CQL DELETE statements.
|
||||
type DeleteBuilder struct {
|
||||
table string
|
||||
columns columns
|
||||
@@ -24,6 +25,7 @@ func Delete(table string) *DeleteBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// ToCql builds the query into a CQL string and named args.
|
||||
func (b *DeleteBuilder) ToCql() (stmt string, names []string) {
|
||||
cql := bytes.Buffer{}
|
||||
|
||||
@@ -61,21 +63,27 @@ func (b *DeleteBuilder) Columns(columns ...string) *DeleteBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// Timestamp sets a USING TIMESTAMP clause on the query.
|
||||
func (b *DeleteBuilder) Timestamp(t time.Time) *DeleteBuilder {
|
||||
b.using.timestamp = t
|
||||
return b
|
||||
}
|
||||
|
||||
// Where adds an expression to the WHERE clause of the query. Expressions are
|
||||
// ANDed together in the generated CQL.
|
||||
func (b *DeleteBuilder) Where(w ...Cmp) *DeleteBuilder {
|
||||
b.where = append(b.where, w...)
|
||||
return b
|
||||
}
|
||||
|
||||
// If adds an expression to the IF clause of the query. Expressions are ANDed
|
||||
// together in the generated CQL.
|
||||
func (b *DeleteBuilder) If(w ...Cmp) *DeleteBuilder {
|
||||
b._if = append(b._if, w...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Existing sets a IF EXISTS clause on the query.
|
||||
func (b *DeleteBuilder) Existing() *DeleteBuilder {
|
||||
b.exists = true
|
||||
return b
|
||||
|
||||
4
qb/doc.go
Normal file
4
qb/doc.go
Normal file
@@ -0,0 +1,4 @@
|
||||
// Package qb provides CQL (Scylla / Cassandra query language) query builders.
|
||||
// The builders create CQL statement and a list of named parameters that can
|
||||
// later be bound using github.com/scylladb/gocqlx.
|
||||
package qb
|
||||
@@ -1,13 +1,14 @@
|
||||
package qb
|
||||
|
||||
// INSERT reference:
|
||||
// http://docs.datastax.com/en/dse/5.1/cql/cql/cql_reference/cql_commands/cqlInsert.html
|
||||
// https://cassandra.apache.org/doc/latest/cql/dml.html#insert
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InsertBuilder builds CQL INSERT statements.
|
||||
type InsertBuilder struct {
|
||||
table string
|
||||
columns columns
|
||||
@@ -22,6 +23,7 @@ func Insert(table string) *InsertBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// ToCql builds the query into a CQL string and named args.
|
||||
func (b *InsertBuilder) ToCql() (stmt string, names []string) {
|
||||
cql := bytes.Buffer{}
|
||||
|
||||
@@ -49,26 +51,31 @@ func (b *InsertBuilder) ToCql() (stmt string, names []string) {
|
||||
return
|
||||
}
|
||||
|
||||
// Into sets the INTO clause of the query.
|
||||
func (b *InsertBuilder) Into(table string) *InsertBuilder {
|
||||
b.table = table
|
||||
return b
|
||||
}
|
||||
|
||||
// Columns adds insert columns to the query.
|
||||
func (b *InsertBuilder) Columns(columns ...string) *InsertBuilder {
|
||||
b.columns = append(b.columns, columns...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Unique sets a IF NOT EXISTS clause on the query.
|
||||
func (b *InsertBuilder) Unique() *InsertBuilder {
|
||||
b.unique = true
|
||||
return b
|
||||
}
|
||||
|
||||
// Timestamp sets a USING TIMESTAMP clause on the query.
|
||||
func (b *InsertBuilder) Timestamp(t time.Time) *InsertBuilder {
|
||||
b.using.timestamp = t
|
||||
return b
|
||||
}
|
||||
|
||||
// TTL sets a USING TTL clause on the query.
|
||||
func (b *InsertBuilder) TTL(d time.Duration) *InsertBuilder {
|
||||
b.using.ttl = d
|
||||
return b
|
||||
|
||||
23
qb/select.go
23
qb/select.go
@@ -1,20 +1,24 @@
|
||||
package qb
|
||||
|
||||
// SELECT reference:
|
||||
// http://docs.datastax.com/en/dse/5.1/cql/cql/cql_reference/cql_commands/cqlSelect.html
|
||||
// https://cassandra.apache.org/doc/latest/cql/dml.html#select
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Order specifies sorting order.
|
||||
type Order bool
|
||||
|
||||
const (
|
||||
ASC Order = true
|
||||
DESC = false
|
||||
// ASC is ascending order
|
||||
ASC Order = true
|
||||
// DESC is descending order
|
||||
DESC = false
|
||||
)
|
||||
|
||||
// SelectBuilder builds CQL SELECT statements.
|
||||
type SelectBuilder struct {
|
||||
table string
|
||||
columns columns
|
||||
@@ -35,6 +39,7 @@ func Select(table string) *SelectBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// ToCql builds the query into a CQL string and named args.
|
||||
func (b *SelectBuilder) ToCql() (stmt string, names []string) {
|
||||
cql := bytes.Buffer{}
|
||||
|
||||
@@ -100,16 +105,20 @@ func (b *SelectBuilder) From(table string) *SelectBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// Columns adds result columns to the query.
|
||||
func (b *SelectBuilder) Columns(columns ...string) *SelectBuilder {
|
||||
b.columns = append(b.columns, columns...)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *SelectBuilder) Distinct(columns... string) *SelectBuilder {
|
||||
// Distinct sets DISTINCT clause on the query.
|
||||
func (b *SelectBuilder) Distinct(columns ...string) *SelectBuilder {
|
||||
b.distinct = append(b.distinct, columns...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Where adds an expression to the WHERE clause of the query. Expressions are
|
||||
// ANDed together in the generated CQL.
|
||||
func (b *SelectBuilder) Where(w ...Cmp) *SelectBuilder {
|
||||
b.where = append(b.where, w...)
|
||||
return b
|
||||
@@ -117,26 +126,30 @@ func (b *SelectBuilder) Where(w ...Cmp) *SelectBuilder {
|
||||
|
||||
// GroupBy sets GROUP BY clause on the query. Columns must be a primary key,
|
||||
// this will automatically add the the columns as first selectors.
|
||||
func (b *SelectBuilder) GroupBy(columns... string) *SelectBuilder {
|
||||
func (b *SelectBuilder) GroupBy(columns ...string) *SelectBuilder {
|
||||
b.groupBy = append(b.groupBy, columns...)
|
||||
return b
|
||||
}
|
||||
|
||||
// OrderBy sets ORDER BY clause on the query.
|
||||
func (b *SelectBuilder) OrderBy(column string, o Order) *SelectBuilder {
|
||||
b.orderBy, b.order = column, o
|
||||
return b
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b *SelectBuilder) Limit(limit uint) *SelectBuilder {
|
||||
b.limit = limit
|
||||
return b
|
||||
}
|
||||
|
||||
// LimitPerPartition sets a PER PARTITION LIMIT clause on the query.
|
||||
func (b *SelectBuilder) LimitPerPartition(limit uint) *SelectBuilder {
|
||||
b.limitPerPartition = limit
|
||||
return b
|
||||
}
|
||||
|
||||
// AllowFiltering sets a ALLOW FILTERING clause on the query.
|
||||
func (b *SelectBuilder) AllowFiltering() *SelectBuilder {
|
||||
b.allowFiltering = true
|
||||
return b
|
||||
|
||||
19
qb/update.go
19
qb/update.go
@@ -1,16 +1,14 @@
|
||||
package qb
|
||||
|
||||
// UPDATE reference:
|
||||
// https://cassandra.apache.org/doc/latest/cql/dml.html#update
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
// UPDATE reference:
|
||||
// http://docs.datastax.com/en/dse/5.1/cql/cql/cql_reference/cql_commands/cqlUpdate.html
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// UpdateBuilder builds CQL UPDATE statements.
|
||||
type UpdateBuilder struct {
|
||||
table string
|
||||
using using
|
||||
@@ -27,6 +25,7 @@ func Update(table string) *UpdateBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
// ToCql builds the query into a CQL string and named args.
|
||||
func (b *UpdateBuilder) ToCql() (stmt string, names []string) {
|
||||
cql := bytes.Buffer{}
|
||||
|
||||
@@ -64,31 +63,39 @@ func (b *UpdateBuilder) Table(table string) *UpdateBuilder {
|
||||
return b
|
||||
}
|
||||
|
||||
// Timestamp sets a USING TIMESTAMP clause on the query.
|
||||
func (b *UpdateBuilder) Timestamp(t time.Time) *UpdateBuilder {
|
||||
b.using.timestamp = t
|
||||
return b
|
||||
}
|
||||
|
||||
// TTL sets a USING TTL clause on the query.
|
||||
func (b *UpdateBuilder) TTL(d time.Duration) *UpdateBuilder {
|
||||
b.using.ttl = d
|
||||
return b
|
||||
}
|
||||
|
||||
// Set adds SET clauses to the query.
|
||||
func (b *UpdateBuilder) Set(columns ...string) *UpdateBuilder {
|
||||
b.columns = append(b.columns, columns...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Where adds an expression to the WHERE clause of the query. Expressions are
|
||||
// ANDed together in the generated CQL.
|
||||
func (b *UpdateBuilder) Where(w ...Cmp) *UpdateBuilder {
|
||||
b.where = append(b.where, w...)
|
||||
return b
|
||||
}
|
||||
|
||||
// If adds an expression to the IF clause of the query. Expressions are ANDed
|
||||
// together in the generated CQL.
|
||||
func (b *UpdateBuilder) If(w ...Cmp) *UpdateBuilder {
|
||||
b._if = append(b._if, w...)
|
||||
return b
|
||||
}
|
||||
|
||||
// Existing sets a IF EXISTS clause on the query.
|
||||
func (b *UpdateBuilder) Existing() *UpdateBuilder {
|
||||
b.exists = true
|
||||
return b
|
||||
|
||||
26
queryx.go
26
queryx.go
@@ -82,14 +82,18 @@ type Queryx struct {
|
||||
Mapper *reflectx.Mapper
|
||||
}
|
||||
|
||||
// Query creates a new Queryx from gocql.Query using a default mapper.
|
||||
func Query(q *gocql.Query, names []string) Queryx {
|
||||
return Queryx{
|
||||
Query: q,
|
||||
Names: names,
|
||||
Mapper: DefaultMapper,
|
||||
}
|
||||
}
|
||||
|
||||
// BindStruct binds query named parameters using mapper.
|
||||
func (q Queryx) BindStruct(arg interface{}) error {
|
||||
m := q.Mapper
|
||||
if m == nil {
|
||||
m = DefaultMapper
|
||||
}
|
||||
|
||||
arglist, err := bindStructArgs(q.Names, arg, m)
|
||||
arglist, err := bindStructArgs(q.Names, arg, q.Mapper)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -144,3 +148,13 @@ func bindMapArgs(names []string, arg map[string]interface{}) ([]interface{}, err
|
||||
}
|
||||
return arglist, nil
|
||||
}
|
||||
|
||||
// QueryFunc creates Queryx from qb.Builder.ToCql() output.
|
||||
type QueryFunc func(stmt string, names []string) Queryx
|
||||
|
||||
// SessionQuery creates QueryFunc that's session aware.
|
||||
func SessionQuery(session *gocql.Session) QueryFunc {
|
||||
return func(stmt string, names []string) Queryx {
|
||||
return Query(session.Query(stmt), names)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +101,7 @@ func TestBindStruct(t *testing.T) {
|
||||
}
|
||||
|
||||
func BenchmarkBindStruct(b *testing.B) {
|
||||
q := Queryx{
|
||||
Query: &gocql.Query{},
|
||||
Names: []string{"name", "age", "first", "last"},
|
||||
}
|
||||
q := Query(&gocql.Query{}, []string{"name", "age", "first", "last"})
|
||||
type t struct {
|
||||
Name string
|
||||
Age int
|
||||
|
||||
Reference in New Issue
Block a user