qb: tuple support
This commit is contained in:
committed by
Michal Matczuk
parent
31ae81aba6
commit
219bceab51
108
qb/cmp.go
108
qb/cmp.go
@@ -66,6 +66,18 @@ func Eq(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EqTuple produces column=(?,?,...) with count number of placeholders.
|
||||||
|
func EqTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: eq,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// EqNamed produces column=? with a custom parameter name.
|
// EqNamed produces column=? with a custom parameter name.
|
||||||
func EqNamed(column, name string) Cmp {
|
func EqNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -102,6 +114,18 @@ func Lt(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LtTuple produces column<(?,?,...) with count placeholders.
|
||||||
|
func LtTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: lt,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LtNamed produces column<? with a custom parameter name.
|
// LtNamed produces column<? with a custom parameter name.
|
||||||
func LtNamed(column, name string) Cmp {
|
func LtNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -138,6 +162,18 @@ func LtOrEq(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LtOrEqTuple produces column<=(?,?,...) with count placeholders.
|
||||||
|
func LtOrEqTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: leq,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LtOrEqNamed produces column<=? with a custom parameter name.
|
// LtOrEqNamed produces column<=? with a custom parameter name.
|
||||||
func LtOrEqNamed(column, name string) Cmp {
|
func LtOrEqNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -174,6 +210,18 @@ func Gt(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GtTuple produces column>(?,?,...) with count placeholders.
|
||||||
|
func GtTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: gt,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GtNamed produces column>? with a custom parameter name.
|
// GtNamed produces column>? with a custom parameter name.
|
||||||
func GtNamed(column, name string) Cmp {
|
func GtNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -210,6 +258,18 @@ func GtOrEq(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GtOrEqTuple produces column>=(?,?,...) with count placeholders.
|
||||||
|
func GtOrEqTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: geq,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GtOrEqNamed produces column>=? with a custom parameter name.
|
// GtOrEqNamed produces column>=? with a custom parameter name.
|
||||||
func GtOrEqNamed(column, name string) Cmp {
|
func GtOrEqNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -246,6 +306,18 @@ func In(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InTuple produces column IN ?.
|
||||||
|
func InTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: in,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// InNamed produces column IN ? with a custom parameter name.
|
// InNamed produces column IN ? with a custom parameter name.
|
||||||
func InNamed(column, name string) Cmp {
|
func InNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -273,6 +345,18 @@ func Contains(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainsTuple produces column CONTAINS (?,?,...) with count placeholders.
|
||||||
|
func ContainsTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: cnt,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ContainsKey produces column CONTAINS KEY ?.
|
// ContainsKey produces column CONTAINS KEY ?.
|
||||||
func ContainsKey(column string) Cmp {
|
func ContainsKey(column string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -282,6 +366,18 @@ func ContainsKey(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ContainsKeyTuple produces column CONTAINS KEY (?,?,...) with count placehplders.
|
||||||
|
func ContainsKeyTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: cntKey,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ContainsNamed produces column CONTAINS ? with a custom parameter name.
|
// ContainsNamed produces column CONTAINS ? with a custom parameter name.
|
||||||
func ContainsNamed(column, name string) Cmp {
|
func ContainsNamed(column, name string) Cmp {
|
||||||
return Cmp{
|
return Cmp{
|
||||||
@@ -318,6 +414,18 @@ func Like(column string) Cmp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LikeTuple produces column LIKE (?,?,...) with count placeholders.
|
||||||
|
func LikeTuple(column string, count int) Cmp {
|
||||||
|
return Cmp{
|
||||||
|
op: like,
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type cmps []Cmp
|
type cmps []Cmp
|
||||||
|
|
||||||
func (cs cmps) writeCql(cql *bytes.Buffer) (names []string) {
|
func (cs cmps) writeCql(cql *bytes.Buffer) (names []string) {
|
||||||
|
|||||||
@@ -28,41 +28,81 @@ func TestCmp(t *testing.T) {
|
|||||||
S: "lt<?",
|
S: "lt<?",
|
||||||
N: []string{"lt"},
|
N: []string{"lt"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: LtTuple("lt", 2),
|
||||||
|
S: "lt<(?,?)",
|
||||||
|
N: []string{"lt"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: LtOrEq("lt"),
|
C: LtOrEq("lt"),
|
||||||
S: "lt<=?",
|
S: "lt<=?",
|
||||||
N: []string{"lt"},
|
N: []string{"lt"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: LtOrEqTuple("lt", 2),
|
||||||
|
S: "lt<=(?,?)",
|
||||||
|
N: []string{"lt"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: Gt("gt"),
|
C: Gt("gt"),
|
||||||
S: "gt>?",
|
S: "gt>?",
|
||||||
N: []string{"gt"},
|
N: []string{"gt"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: GtTuple("gt", 2),
|
||||||
|
S: "gt>(?,?)",
|
||||||
|
N: []string{"gt"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: GtOrEq("gt"),
|
C: GtOrEq("gt"),
|
||||||
S: "gt>=?",
|
S: "gt>=?",
|
||||||
N: []string{"gt"},
|
N: []string{"gt"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: GtOrEqTuple("gt", 2),
|
||||||
|
S: "gt>=(?,?)",
|
||||||
|
N: []string{"gt"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: In("in"),
|
C: In("in"),
|
||||||
S: "in IN ?",
|
S: "in IN ?",
|
||||||
N: []string{"in"},
|
N: []string{"in"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: InTuple("in", 2),
|
||||||
|
S: "in IN (?,?)",
|
||||||
|
N: []string{"in"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: Contains("cnt"),
|
C: Contains("cnt"),
|
||||||
S: "cnt CONTAINS ?",
|
S: "cnt CONTAINS ?",
|
||||||
N: []string{"cnt"},
|
N: []string{"cnt"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: ContainsTuple("cnt", 2),
|
||||||
|
S: "cnt CONTAINS (?,?)",
|
||||||
|
N: []string{"cnt"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: ContainsKey("cntKey"),
|
C: ContainsKey("cntKey"),
|
||||||
S: "cntKey CONTAINS KEY ?",
|
S: "cntKey CONTAINS KEY ?",
|
||||||
N: []string{"cntKey"},
|
N: []string{"cntKey"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: ContainsKeyTuple("cntKey", 2),
|
||||||
|
S: "cntKey CONTAINS KEY (?,?)",
|
||||||
|
N: []string{"cntKey"},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
C: Like("like"),
|
C: Like("like"),
|
||||||
S: "like LIKE ?",
|
S: "like LIKE ?",
|
||||||
N: []string{"like"},
|
N: []string{"like"},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
C: LikeTuple("like", 2),
|
||||||
|
S: "like LIKE (?,?)",
|
||||||
|
N: []string{"like"},
|
||||||
|
},
|
||||||
|
|
||||||
// Custom bind names
|
// Custom bind names
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -43,6 +43,24 @@ func TestDeleteBuilder(t *testing.T) {
|
|||||||
S: "DELETE FROM cycling.cyclist_name WHERE id=? AND firstname>? ",
|
S: "DELETE FROM cycling.cyclist_name WHERE id=? AND firstname>? ",
|
||||||
N: []string{"expr", "firstname"},
|
N: []string{"expr", "firstname"},
|
||||||
},
|
},
|
||||||
|
// Add a tuple column
|
||||||
|
{
|
||||||
|
B: Delete("cycling.cyclist_name").Where(EqTuple("id", 2)).Columns("stars"),
|
||||||
|
S: "DELETE stars FROM cycling.cyclist_name WHERE id=(?,?) ",
|
||||||
|
N: []string{"id"},
|
||||||
|
},
|
||||||
|
// Add WHERE for tuple column
|
||||||
|
{
|
||||||
|
B: Delete("cycling.cyclist_name").Where(w, GtTuple("firstname", 2)),
|
||||||
|
S: "DELETE FROM cycling.cyclist_name WHERE id=? AND firstname>(?,?) ",
|
||||||
|
N: []string{"expr", "firstname"},
|
||||||
|
},
|
||||||
|
// Add WHERE for all tuple columns
|
||||||
|
{
|
||||||
|
B: Delete("cycling.cyclist_name").Where(EqTuple("id", 2), GtTuple("firstname", 2)),
|
||||||
|
S: "DELETE FROM cycling.cyclist_name WHERE id=(?,?) AND firstname>(?,?) ",
|
||||||
|
N: []string{"id", "firstname"},
|
||||||
|
},
|
||||||
// Add IF
|
// Add IF
|
||||||
{
|
{
|
||||||
B: Delete("cycling.cyclist_name").Where(w).If(Gt("firstname")),
|
B: Delete("cycling.cyclist_name").Where(w).If(Gt("firstname")),
|
||||||
|
|||||||
12
qb/insert.go
12
qb/insert.go
@@ -128,6 +128,18 @@ func (b *InsertBuilder) FuncColumn(column string, fn *Func) *InsertBuilder {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TupleColumn adds an insert column for a tuple value to the query.
|
||||||
|
func (b *InsertBuilder) TupleColumn(column string, count int) *InsertBuilder {
|
||||||
|
b.columns = append(b.columns, initializer{
|
||||||
|
column: column,
|
||||||
|
value: tupleParam{
|
||||||
|
param: param(column),
|
||||||
|
count: count,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
// Unique sets a IF NOT EXISTS clause on the query.
|
// Unique sets a IF NOT EXISTS clause on the query.
|
||||||
func (b *InsertBuilder) Unique() *InsertBuilder {
|
func (b *InsertBuilder) Unique() *InsertBuilder {
|
||||||
b.unique = true
|
b.unique = true
|
||||||
|
|||||||
@@ -76,6 +76,17 @@ func TestInsertBuilder(t *testing.T) {
|
|||||||
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ",
|
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ",
|
||||||
N: []string{"id", "user_uuid", "firstname", "ts"},
|
N: []string{"id", "user_uuid", "firstname", "ts"},
|
||||||
},
|
},
|
||||||
|
// Add TupleColumn
|
||||||
|
{
|
||||||
|
B: Insert("cycling.cyclist_name").TupleColumn("id", 2),
|
||||||
|
S: "INSERT INTO cycling.cyclist_name (id) VALUES ((?,?)) ",
|
||||||
|
N: []string{"id"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
B: Insert("cycling.cyclist_name").TupleColumn("id", 2).Columns("user_uuid"),
|
||||||
|
S: "INSERT INTO cycling.cyclist_name (id,user_uuid) VALUES ((?,?),?) ",
|
||||||
|
N: []string{"id", "user_uuid"},
|
||||||
|
},
|
||||||
// Add IF NOT EXISTS
|
// Add IF NOT EXISTS
|
||||||
{
|
{
|
||||||
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Unique(),
|
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Unique(),
|
||||||
|
|||||||
@@ -65,6 +65,18 @@ func TestSelectBuilder(t *testing.T) {
|
|||||||
S: "SELECT * FROM cycling.cyclist_name WHERE id=? AND firstname>? ",
|
S: "SELECT * FROM cycling.cyclist_name WHERE id=? AND firstname>? ",
|
||||||
N: []string{"expr", "firstname"},
|
N: []string{"expr", "firstname"},
|
||||||
},
|
},
|
||||||
|
// Add WHERE with tuple
|
||||||
|
{
|
||||||
|
B: Select("cycling.cyclist_name").Where(EqTuple("id", 2), Gt("firstname")),
|
||||||
|
S: "SELECT * FROM cycling.cyclist_name WHERE id=(?,?) AND firstname>? ",
|
||||||
|
N: []string{"id", "firstname"},
|
||||||
|
},
|
||||||
|
// Add WHERE with only tuples
|
||||||
|
{
|
||||||
|
B: Select("cycling.cyclist_name").Where(EqTuple("id", 2), GtTuple("firstname", 2)),
|
||||||
|
S: "SELECT * FROM cycling.cyclist_name WHERE id=(?,?) AND firstname>(?,?) ",
|
||||||
|
N: []string{"id", "firstname"},
|
||||||
|
},
|
||||||
// Add GROUP BY
|
// Add GROUP BY
|
||||||
{
|
{
|
||||||
B: Select("cycling.cyclist_name").Columns("MAX(stars) as max_stars").GroupBy("id"),
|
B: Select("cycling.cyclist_name").Columns("MAX(stars) as max_stars").GroupBy("id"),
|
||||||
|
|||||||
13
qb/update.go
13
qb/update.go
@@ -105,6 +105,7 @@ func (b *UpdateBuilder) TimestampNamed(name string) *UpdateBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set adds SET clauses to the query.
|
// Set adds SET clauses to the query.
|
||||||
|
// To set a tuple column use SetTuple instead.
|
||||||
func (b *UpdateBuilder) Set(columns ...string) *UpdateBuilder {
|
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{
|
||||||
@@ -136,6 +137,18 @@ func (b *UpdateBuilder) SetFunc(column string, fn *Func) *UpdateBuilder {
|
|||||||
return b
|
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.
|
// 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.addValue(column, param(column))
|
return b.addValue(column, param(column))
|
||||||
|
|||||||
@@ -43,6 +43,13 @@ func TestUpdateBuilder(t *testing.T) {
|
|||||||
S: "UPDATE cycling.cyclist_name SET user_uuid=literal_uuid,stars=? WHERE id=? ",
|
S: "UPDATE cycling.cyclist_name SET user_uuid=literal_uuid,stars=? WHERE id=? ",
|
||||||
N: []string{"stars", "expr"},
|
N: []string{"stars", "expr"},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Add SET tuple
|
||||||
|
{
|
||||||
|
B: Update("cycling.cyclist_name").SetTuple("id", 2).Set("user_uuid", "firstname").Where(EqTuple("id", 2)),
|
||||||
|
S: "UPDATE cycling.cyclist_name SET id=(?,?),user_uuid=?,firstname=? WHERE id=(?,?) ",
|
||||||
|
N: []string{"id", "user_uuid", "firstname", "id"},
|
||||||
|
},
|
||||||
// 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"),
|
||||||
|
|||||||
17
qb/value.go
17
qb/value.go
@@ -22,6 +22,23 @@ func (p param) writeCql(cql *bytes.Buffer) (names []string) {
|
|||||||
return []string{string(p)}
|
return []string{string(p)}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// param is a named CQL tuple '?' parameter.
|
||||||
|
type tupleParam struct {
|
||||||
|
param param
|
||||||
|
count int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t tupleParam) writeCql(cql *bytes.Buffer) (names []string) {
|
||||||
|
cql.WriteByte('(')
|
||||||
|
for i := 0; i < t.count-1; i++ {
|
||||||
|
cql.WriteByte('?')
|
||||||
|
cql.WriteByte(',')
|
||||||
|
}
|
||||||
|
cql.WriteByte('?')
|
||||||
|
cql.WriteByte(')')
|
||||||
|
return []string{string(t.param)}
|
||||||
|
}
|
||||||
|
|
||||||
// lit is a literal CQL value.
|
// lit is a literal CQL value.
|
||||||
type lit string
|
type lit string
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user