Files
gocqlx/qb/update.go
Gian Lorenzo Meocci 9239d9c4b4 add UseColums function to avoid extra allocation performed by Colums function
fix name

tidy

adding SetWhere

adding SetWhere

fix go mod

fix comment style

revert go mod

Avoid to append if no needed

fix git ignore

revert change in go.sum/go.mod

adding specific benchmark
2019-12-16 11:14:11 +01:00

239 lines
6.2 KiB
Go

// 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
// UPDATE reference:
// https://cassandra.apache.org/doc/latest/cql/dml.html#update
import (
"bytes"
"time"
)
// assignment specifies an assignment in a set operation.
type assignment struct {
column string
value value
valuePrefix string // Tbe value prefix to use for add/remove operations.
}
func (a assignment) writeCql(cql *bytes.Buffer) (names []string) {
cql.WriteString(a.column)
cql.WriteByte('=')
cql.WriteString(a.valuePrefix)
return a.value.writeCql(cql)
}
// UpdateBuilder builds CQL UPDATE statements.
type UpdateBuilder struct {
table string
using using
assignments []assignment
where where
_if _if
exists bool
}
// Update returns a new UpdateBuilder with the given table name.
func Update(table string) *UpdateBuilder {
return &UpdateBuilder{
table: table,
}
}
// ToCql builds the query into a CQL string and named args.
func (b *UpdateBuilder) ToCql() (stmt string, names []string) {
cql := bytes.Buffer{}
cql.WriteString("UPDATE ")
cql.WriteString(b.table)
cql.WriteByte(' ')
names = append(names, b.using.writeCql(&cql)...)
cql.WriteString("SET ")
for i, a := range b.assignments {
names = append(names, a.writeCql(&cql)...)
if i < len(b.assignments)-1 {
cql.WriteByte(',')
}
}
cql.WriteByte(' ')
names = append(names, b.where.writeCql(&cql)...)
names = append(names, b._if.writeCql(&cql)...)
if b.exists {
cql.WriteString("IF EXISTS ")
}
stmt = cql.String()
return
}
// Table sets the table to be updated.
func (b *UpdateBuilder) Table(table string) *UpdateBuilder {
b.table = table
return b
}
// TTL adds USING TTL clause to the query.
func (b *UpdateBuilder) TTL(d time.Duration) *UpdateBuilder {
b.using.TTL(d)
return b
}
// TTLNamed adds USING TTL clause to the query with a custom parameter name.
func (b *UpdateBuilder) TTLNamed(name string) *UpdateBuilder {
b.using.TTLNamed(name)
return b
}
// Timestamp adds USING TIMESTAMP clause to the query.
func (b *UpdateBuilder) Timestamp(t time.Time) *UpdateBuilder {
b.using.Timestamp(t)
return b
}
// TimestampNamed adds a USING TIMESTAMP clause to the query with a custom
// parameter name.
func (b *UpdateBuilder) TimestampNamed(name string) *UpdateBuilder {
b.using.TimestampNamed(name)
return b
}
// Set adds SET clauses to the query.
// To set a tuple column use SetTuple instead.
func (b *UpdateBuilder) Set(columns ...string) *UpdateBuilder {
for _, c := range columns {
b.assignments = append(b.assignments, assignment{
column: c,
value: param(c),
})
}
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.
func (b *UpdateBuilder) SetFunc(column string, fn *Func) *UpdateBuilder {
b.assignments = append(b.assignments, assignment{column: column, value: fn})
return b
}
// SetTuple adds a SET clause for a tuple to the query.
func (b *UpdateBuilder) SetTuple(column string, count int) *UpdateBuilder {
b.assignments = append(b.assignments, assignment{
column: column,
value: tupleParam{
param: param(column),
count: count,
},
})
return b
}
// Add adds SET column=column+? clauses to the query.
func (b *UpdateBuilder) Add(column string) *UpdateBuilder {
return b.addValue(column, param(column))
}
// AddNamed adds SET column=column+? clauses to the query with a custom
// parameter name.
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{
column: column,
value: value,
valuePrefix: column + "+",
})
return b
}
// Remove adds SET column=column-? clauses to the query.
func (b *UpdateBuilder) Remove(column string) *UpdateBuilder {
return b.removeValue(column, param(column))
}
// RemoveNamed adds SET column=column-? clauses to the query with a custom
// parameter name.
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{
column: column,
value: value,
valuePrefix: column + "-",
})
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 {
if len(b.where) == 0 {
b.where = w
} else {
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 {
if len(b._if) == 0 {
b._if = w
} else {
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
}