Support for literals in INSERT and UPDATE and comparisons
The 'value' interface represents a CQL value for use in a comparison, update, or intitialization operation. A consistent interface for this allows us to easily support specifying default-named, custom-named, literal, and evaluated-function values in all these contexts. Parameters to Func should probably also be values to support full composition, but that would be a breaking change because Func's properties are exposed. The value interface could itself be exposed if we wanted to allow clients to pass their own values to SetValue, etc, but for now it is a package-internal abstraction. BLA
This commit is contained in:
committed by
Michał Matczuk
parent
9fa5432a65
commit
12d360a0c3
114
qb/cmp.go
114
qb/cmp.go
@@ -4,9 +4,6 @@
|
|||||||
|
|
||||||
package qb
|
package qb
|
||||||
|
|
||||||
// Functions reference:
|
|
||||||
// http://cassandra.apache.org/doc/latest/cql/functions.html
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
)
|
)
|
||||||
@@ -28,8 +25,7 @@ const (
|
|||||||
type Cmp struct {
|
type Cmp struct {
|
||||||
op op
|
op op
|
||||||
column string
|
column string
|
||||||
name string
|
value value
|
||||||
fn *Func
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) {
|
func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) {
|
||||||
@@ -52,19 +48,7 @@ func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) {
|
|||||||
case cnt:
|
case cnt:
|
||||||
cql.WriteString(" CONTAINS ")
|
cql.WriteString(" CONTAINS ")
|
||||||
}
|
}
|
||||||
|
return c.value.writeCql(cql)
|
||||||
if c.fn != nil {
|
|
||||||
names = append(names, c.fn.writeCql(cql)...)
|
|
||||||
} else {
|
|
||||||
cql.WriteByte('?')
|
|
||||||
if c.name == "" {
|
|
||||||
names = append(names, c.column)
|
|
||||||
} else {
|
|
||||||
names = append(names, c.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eq produces column=?.
|
// Eq produces column=?.
|
||||||
@@ -72,6 +56,7 @@ func Eq(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: eq,
|
op: eq,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +65,16 @@ func EqNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: eq,
|
op: eq,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EqLit produces column=literal and does not add a parameter to the query.
|
||||||
|
func EqLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: eq,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +83,7 @@ func EqFunc(column string, fn *Func) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: eq,
|
op: eq,
|
||||||
column: column,
|
column: column,
|
||||||
fn: fn,
|
value: fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,6 +92,7 @@ func Lt(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: lt,
|
op: lt,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +101,16 @@ func LtNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: lt,
|
op: lt,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LtLit produces column<literal and does not add a parameter to the query.
|
||||||
|
func LtLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: lt,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +119,7 @@ func LtFunc(column string, fn *Func) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: lt,
|
op: lt,
|
||||||
column: column,
|
column: column,
|
||||||
fn: fn,
|
value: fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,6 +128,7 @@ func LtOrEq(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: leq,
|
op: leq,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,7 +137,16 @@ func LtOrEqNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: leq,
|
op: leq,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// LtOrEqLit produces column<=literal and does not add a parameter to the query.
|
||||||
|
func LtOrEqLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: leq,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +155,7 @@ func LtOrEqFunc(column string, fn *Func) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: leq,
|
op: leq,
|
||||||
column: column,
|
column: column,
|
||||||
fn: fn,
|
value: fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,6 +164,7 @@ func Gt(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: gt,
|
op: gt,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +173,16 @@ func GtNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: gt,
|
op: gt,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GtLit produces column>literal and does not add a parameter to the query.
|
||||||
|
func GtLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: gt,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +191,7 @@ func GtFunc(column string, fn *Func) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: gt,
|
op: gt,
|
||||||
column: column,
|
column: column,
|
||||||
fn: fn,
|
value: fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,6 +200,7 @@ func GtOrEq(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: geq,
|
op: geq,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,7 +209,16 @@ func GtOrEqNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: geq,
|
op: geq,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GtOrEqLit produces column>=literal and does not add a parameter to the query.
|
||||||
|
func GtOrEqLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: geq,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +227,7 @@ func GtOrEqFunc(column string, fn *Func) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: geq,
|
op: geq,
|
||||||
column: column,
|
column: column,
|
||||||
fn: fn,
|
value: fn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +236,7 @@ func In(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: in,
|
op: in,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,7 +245,16 @@ func InNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: in,
|
op: in,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InLit produces column IN literal and does not add a parameter to the query.
|
||||||
|
func InLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: in,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,6 +263,7 @@ func Contains(column string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: cnt,
|
op: cnt,
|
||||||
column: column,
|
column: column,
|
||||||
|
value: param(column),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +272,16 @@ func ContainsNamed(column, name string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: cnt,
|
op: cnt,
|
||||||
column: column,
|
column: column,
|
||||||
name: name,
|
value: param(name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainsLit produces column CONTAINS literal and does not add a parameter to the query.
|
||||||
|
func ContainsLit(column, literal string) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: cnt,
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,36 @@ func TestCmp(t *testing.T) {
|
|||||||
N: []string{"name"},
|
N: []string{"name"},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Literals
|
||||||
|
{
|
||||||
|
C: EqLit("eq", "litval"),
|
||||||
|
S: "eq=litval",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
C: LtLit("lt", "litval"),
|
||||||
|
S: "lt<litval",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
C: LtOrEqLit("lt", "litval"),
|
||||||
|
S: "lt<=litval",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
C: GtLit("gt", "litval"),
|
||||||
|
S: "gt>litval",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
C: GtOrEqLit("gt", "litval"),
|
||||||
|
S: "gt>=litval",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
C: InLit("in", "litval"),
|
||||||
|
S: "in IN litval",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
C: ContainsLit("cnt", "litval"),
|
||||||
|
S: "cnt CONTAINS litval",
|
||||||
|
},
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
{
|
{
|
||||||
C: EqFunc("eq", Fn("fn", "arg0", "arg1")),
|
C: EqFunc("eq", Fn("fn", "arg0", "arg1")),
|
||||||
|
|||||||
57
qb/insert.go
57
qb/insert.go
@@ -11,10 +11,16 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// initializer specifies an value for a column in an insert operation.
|
||||||
|
type initializer struct {
|
||||||
|
column string
|
||||||
|
value value
|
||||||
|
}
|
||||||
|
|
||||||
// InsertBuilder builds CQL INSERT statements.
|
// InsertBuilder builds CQL INSERT statements.
|
||||||
type InsertBuilder struct {
|
type InsertBuilder struct {
|
||||||
table string
|
table string
|
||||||
columns columns
|
columns []initializer
|
||||||
unique bool
|
unique bool
|
||||||
using using
|
using using
|
||||||
}
|
}
|
||||||
@@ -37,12 +43,21 @@ func (b *InsertBuilder) ToCql() (stmt string, names []string) {
|
|||||||
cql.WriteByte(' ')
|
cql.WriteByte(' ')
|
||||||
|
|
||||||
cql.WriteByte('(')
|
cql.WriteByte('(')
|
||||||
b.columns.writeCql(&cql)
|
for i, c := range b.columns {
|
||||||
names = append(names, b.columns...)
|
cql.WriteString(c.column)
|
||||||
|
if i < len(b.columns)-1 {
|
||||||
|
cql.WriteByte(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
cql.WriteString(") ")
|
cql.WriteString(") ")
|
||||||
|
|
||||||
cql.WriteString("VALUES (")
|
cql.WriteString("VALUES (")
|
||||||
placeholders(&cql, len(b.columns))
|
for i, c := range b.columns {
|
||||||
|
names = append(names, c.value.writeCql(&cql)...)
|
||||||
|
if i < len(b.columns)-1 {
|
||||||
|
cql.WriteByte(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
cql.WriteString(") ")
|
cql.WriteString(") ")
|
||||||
|
|
||||||
if b.unique {
|
if b.unique {
|
||||||
@@ -62,7 +77,39 @@ func (b *InsertBuilder) Into(table string) *InsertBuilder {
|
|||||||
|
|
||||||
// Columns adds insert columns to the query.
|
// Columns adds insert columns to the query.
|
||||||
func (b *InsertBuilder) Columns(columns ...string) *InsertBuilder {
|
func (b *InsertBuilder) Columns(columns ...string) *InsertBuilder {
|
||||||
b.columns = append(b.columns, columns...)
|
for _, c := range columns {
|
||||||
|
b.columns = append(b.columns, initializer{
|
||||||
|
column: c,
|
||||||
|
value: param(c),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamedColumn adds an insert column with a custom parameter name.
|
||||||
|
func (b *InsertBuilder) NamedColumn(column, name string) *InsertBuilder {
|
||||||
|
b.columns = append(b.columns, initializer{
|
||||||
|
column: column,
|
||||||
|
value: param(name),
|
||||||
|
})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// LitColumn adds an insert column with a literal value to the query.
|
||||||
|
func (b *InsertBuilder) LitColumn(column, literal string) *InsertBuilder {
|
||||||
|
b.columns = append(b.columns, initializer{
|
||||||
|
column: column,
|
||||||
|
value: lit(literal),
|
||||||
|
})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// FuncColumn adds an insert column initialized by evaluating a CQL function.
|
||||||
|
func (b *InsertBuilder) FuncColumn(column string, fn *Func) *InsertBuilder {
|
||||||
|
b.columns = append(b.columns, initializer{
|
||||||
|
column: column,
|
||||||
|
value: fn,
|
||||||
|
})
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,18 @@ func TestInsertBuilder(t *testing.T) {
|
|||||||
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,?) ",
|
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,?) ",
|
||||||
N: []string{"id", "user_uuid", "firstname", "stars"},
|
N: []string{"id", "user_uuid", "firstname", "stars"},
|
||||||
},
|
},
|
||||||
|
// Add a named column
|
||||||
|
{
|
||||||
|
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").NamedColumn("stars", "stars_name"),
|
||||||
|
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,?) ",
|
||||||
|
N: []string{"id", "user_uuid", "firstname", "stars_name"},
|
||||||
|
},
|
||||||
|
// Add a literal column
|
||||||
|
{
|
||||||
|
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").LitColumn("stars", "stars_lit"),
|
||||||
|
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname,stars) VALUES (?,?,?,stars_lit) ",
|
||||||
|
N: []string{"id", "user_uuid", "firstname"},
|
||||||
|
},
|
||||||
// Add TTL
|
// Add TTL
|
||||||
{
|
{
|
||||||
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(),
|
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(),
|
||||||
|
|||||||
@@ -75,6 +75,6 @@ func (t TokenBuilder) cmp(op op, names []string) Cmp {
|
|||||||
return Cmp{
|
return Cmp{
|
||||||
op: op,
|
op: op,
|
||||||
column: fmt.Sprint("token(", strings.Join(t, ","), ")"),
|
column: fmt.Sprint("token(", strings.Join(t, ","), ")"),
|
||||||
fn: Fn("token", s...),
|
value: Fn("token", s...),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
81
qb/update.go
81
qb/update.go
@@ -9,31 +9,20 @@ package qb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// assignment specifies an assignment in a set operation.
|
// assignment specifies an assignment in a set operation.
|
||||||
type assignment struct {
|
type assignment struct {
|
||||||
column string
|
column string
|
||||||
name string
|
value value
|
||||||
expr bool
|
valuePrefix string // Tbe value prefix to use for add/remove operations.
|
||||||
fn *Func
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a assignment) writeCql(cql *bytes.Buffer) (names []string) {
|
func (a assignment) writeCql(cql *bytes.Buffer) (names []string) {
|
||||||
cql.WriteString(a.column)
|
cql.WriteString(a.column)
|
||||||
switch {
|
|
||||||
case a.expr:
|
|
||||||
names = append(names, a.name)
|
|
||||||
case a.fn != nil:
|
|
||||||
cql.WriteByte('=')
|
cql.WriteByte('=')
|
||||||
names = append(names, a.fn.writeCql(cql)...)
|
cql.WriteString(a.valuePrefix)
|
||||||
default:
|
return a.value.writeCql(cql)
|
||||||
cql.WriteByte('=')
|
|
||||||
cql.WriteByte('?')
|
|
||||||
names = append(names, a.name)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateBuilder builds CQL UPDATE statements.
|
// UpdateBuilder builds CQL UPDATE statements.
|
||||||
@@ -106,47 +95,89 @@ func (b *UpdateBuilder) Set(columns ...string) *UpdateBuilder {
|
|||||||
for _, c := range columns {
|
for _, c := range columns {
|
||||||
b.assignments = append(b.assignments, assignment{
|
b.assignments = append(b.assignments, assignment{
|
||||||
column: c,
|
column: c,
|
||||||
name: c,
|
value: param(c),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetNamed adds SET column=? clause to the query with a custom parameter name.
|
||||||
|
func (b *UpdateBuilder) SetNamed(column, name string) *UpdateBuilder {
|
||||||
|
b.assignments = append(
|
||||||
|
b.assignments, assignment{column: column, value: param(name)})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetLit adds SET column=literal clause to the query.
|
||||||
|
func (b *UpdateBuilder) SetLit(column, literal string) *UpdateBuilder {
|
||||||
|
b.assignments = append(
|
||||||
|
b.assignments, assignment{column: column, value: lit(literal)})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// SetFunc adds SET column=someFunc(?...) clause to the query.
|
// SetFunc adds SET column=someFunc(?...) clause to the query.
|
||||||
func (b *UpdateBuilder) SetFunc(column string, fn *Func) *UpdateBuilder {
|
func (b *UpdateBuilder) SetFunc(column string, fn *Func) *UpdateBuilder {
|
||||||
b.assignments = append(b.assignments, assignment{column: column, fn: fn})
|
b.assignments = append(b.assignments, assignment{column: column, value: fn})
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds SET column=column+? clauses to the query.
|
// Add adds SET column=column+? clauses to the query.
|
||||||
func (b *UpdateBuilder) Add(column string) *UpdateBuilder {
|
func (b *UpdateBuilder) Add(column string) *UpdateBuilder {
|
||||||
return b.AddNamed(column, column)
|
return b.addValue(column, param(column))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddNamed adds SET column=column+? clauses to the query with a custom
|
// AddNamed adds SET column=column+? clauses to the query with a custom
|
||||||
// parameter name.
|
// parameter name.
|
||||||
func (b *UpdateBuilder) AddNamed(column, name string) *UpdateBuilder {
|
func (b *UpdateBuilder) AddNamed(column, name string) *UpdateBuilder {
|
||||||
|
return b.addValue(column, param(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddLit adds SET column=column+literal clauses to the query.
|
||||||
|
func (b *UpdateBuilder) AddLit(column, literal string) *UpdateBuilder {
|
||||||
|
return b.addValue(column, lit(literal))
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddFunc adds SET column=column+someFunc(?...) clauses to the query.
|
||||||
|
func (b *UpdateBuilder) AddFunc(column string, fn *Func) *UpdateBuilder {
|
||||||
|
return b.addValue(column, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *UpdateBuilder) addValue(column string, value value) *UpdateBuilder {
|
||||||
b.assignments = append(b.assignments, assignment{
|
b.assignments = append(b.assignments, assignment{
|
||||||
column: fmt.Sprint(column, "=", column, "+?"),
|
column: column,
|
||||||
name: name,
|
value: value,
|
||||||
expr: true,
|
valuePrefix: column + "+",
|
||||||
})
|
})
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove adds SET column=column-? clauses to the query.
|
// Remove adds SET column=column-? clauses to the query.
|
||||||
func (b *UpdateBuilder) Remove(column string) *UpdateBuilder {
|
func (b *UpdateBuilder) Remove(column string) *UpdateBuilder {
|
||||||
return b.RemoveNamed(column, column)
|
return b.removeValue(column, param(column))
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveNamed adds SET column=column-? clauses to the query with a custom
|
// RemoveNamed adds SET column=column-? clauses to the query with a custom
|
||||||
// parameter name.
|
// parameter name.
|
||||||
func (b *UpdateBuilder) RemoveNamed(column, name string) *UpdateBuilder {
|
func (b *UpdateBuilder) RemoveNamed(column, name string) *UpdateBuilder {
|
||||||
|
return b.removeValue(column, param(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveLit adds SET column=column-literal clauses to the query.
|
||||||
|
func (b *UpdateBuilder) RemoveLit(column, literal string) *UpdateBuilder {
|
||||||
|
return b.removeValue(column, lit(literal))
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFunc adds SET column=column-someFunc(?...) clauses to the query.
|
||||||
|
func (b *UpdateBuilder) RemoveFunc(column string, fn *Func) *UpdateBuilder {
|
||||||
|
return b.removeValue(column, fn)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *UpdateBuilder) removeValue(column string, value value) *UpdateBuilder {
|
||||||
b.assignments = append(b.assignments, assignment{
|
b.assignments = append(b.assignments, assignment{
|
||||||
column: fmt.Sprint(column, "=", column, "-?"),
|
column: column,
|
||||||
name: name,
|
value: value,
|
||||||
expr: true,
|
valuePrefix: column + "-",
|
||||||
})
|
})
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,12 @@ func TestUpdateBuilder(t *testing.T) {
|
|||||||
S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=?,stars=? WHERE id=? ",
|
S: "UPDATE cycling.cyclist_name SET id=?,user_uuid=?,firstname=?,stars=? WHERE id=? ",
|
||||||
N: []string{"id", "user_uuid", "firstname", "stars", "expr"},
|
N: []string{"id", "user_uuid", "firstname", "stars", "expr"},
|
||||||
},
|
},
|
||||||
|
// Add SET literal
|
||||||
|
{
|
||||||
|
B: Update("cycling.cyclist_name").SetLit("user_uuid", "literal_uuid").Where(w).Set("stars"),
|
||||||
|
S: "UPDATE cycling.cyclist_name SET user_uuid=literal_uuid,stars=? WHERE id=? ",
|
||||||
|
N: []string{"stars", "expr"},
|
||||||
|
},
|
||||||
// Add SET SetFunc
|
// Add SET SetFunc
|
||||||
{
|
{
|
||||||
B: Update("cycling.cyclist_name").SetFunc("user_uuid", Fn("someFunc", "param_0", "param_1")).Where(w).Set("stars"),
|
B: Update("cycling.cyclist_name").SetFunc("user_uuid", Fn("someFunc", "param_0", "param_1")).Where(w).Set("stars"),
|
||||||
@@ -54,6 +60,12 @@ func TestUpdateBuilder(t *testing.T) {
|
|||||||
S: "UPDATE cycling.cyclist_name SET total=total+? WHERE id=? ",
|
S: "UPDATE cycling.cyclist_name SET total=total+? WHERE id=? ",
|
||||||
N: []string{"inc", "expr"},
|
N: []string{"inc", "expr"},
|
||||||
},
|
},
|
||||||
|
// Add SET AddLit
|
||||||
|
{
|
||||||
|
B: Update("cycling.cyclist_name").AddLit("total", "1").Where(w),
|
||||||
|
S: "UPDATE cycling.cyclist_name SET total=total+1 WHERE id=? ",
|
||||||
|
N: []string{"expr"},
|
||||||
|
},
|
||||||
// Add SET Remove
|
// Add SET Remove
|
||||||
{
|
{
|
||||||
B: Update("cycling.cyclist_name").Remove("total").Where(w),
|
B: Update("cycling.cyclist_name").Remove("total").Where(w),
|
||||||
@@ -66,6 +78,12 @@ func TestUpdateBuilder(t *testing.T) {
|
|||||||
S: "UPDATE cycling.cyclist_name SET total=total-? WHERE id=? ",
|
S: "UPDATE cycling.cyclist_name SET total=total-? WHERE id=? ",
|
||||||
N: []string{"dec", "expr"},
|
N: []string{"dec", "expr"},
|
||||||
},
|
},
|
||||||
|
// Add SET RemoveLit
|
||||||
|
{
|
||||||
|
B: Update("cycling.cyclist_name").RemoveLit("total", "1").Where(w),
|
||||||
|
S: "UPDATE cycling.cyclist_name SET total=total-1 WHERE id=? ",
|
||||||
|
N: []string{"expr"},
|
||||||
|
},
|
||||||
// Add WHERE
|
// Add WHERE
|
||||||
{
|
{
|
||||||
B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w, Gt("firstname")),
|
B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w, Gt("firstname")),
|
||||||
|
|||||||
31
qb/value.go
Normal file
31
qb/value.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (C) 2017 ScyllaDB
|
||||||
|
// Use of this source code is governed by a ALv2-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package qb
|
||||||
|
|
||||||
|
import "bytes"
|
||||||
|
|
||||||
|
// value is a CQL value expression for use in an initializer, assignment,
|
||||||
|
// or comparison.
|
||||||
|
type value interface {
|
||||||
|
// writeCql writes the bytes for this value to the buffer and returns the
|
||||||
|
// list of names of parameters which need substitution.
|
||||||
|
writeCql(cql *bytes.Buffer) (names []string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// param is a named CQL '?' parameter.
|
||||||
|
type param string
|
||||||
|
|
||||||
|
func (p param) writeCql(cql *bytes.Buffer) (names []string) {
|
||||||
|
cql.WriteByte('?')
|
||||||
|
return []string{string(p)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// lit is a literal CQL value.
|
||||||
|
type lit string
|
||||||
|
|
||||||
|
func (l lit) writeCql(cql *bytes.Buffer) (names []string) {
|
||||||
|
cql.WriteString(string(l))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user