diff --git a/qb/cmp.go b/qb/cmp.go index ba59617..0d95ac5 100644 --- a/qb/cmp.go +++ b/qb/cmp.go @@ -28,49 +28,8 @@ const ( type Cmp struct { op op column string - fn string - names []string -} - -// Func wraps comparator value with a custom function, fn is a function name, -// names are function arguments' bind names. For instance function: -// -// CREATE FUNCTION somefunction(somearg int, anotherarg text) -// -// can be used like this: -// -// stmt, names := qb.Select("table"). -// Where(qb.Eq("t").Func("somefunction", "somearg", "anotherarg")). -// ToCql() -// -// q := gocqlx.Query(session.Query(stmt), names).BindMap(qb.M{ -// "somearg": 1, -// "anotherarg": "text", -// }) -func (c Cmp) Func(fn string, names ...string) Cmp { - c.fn = fn - c.names = names - return c -} - -// MinTimeuuid sets minTimeuuid(?) compare value. -func (c Cmp) MinTimeuuid(name string) Cmp { - return c.Func("minTimeuuid", name) -} - -// MaxTimeuuid sets maxTimeuuid(?) compare value. -func (c Cmp) MaxTimeuuid(name string) Cmp { - return c.Func("maxTimeuuid", name) -} - -// Now sets now() compare value. -func (c Cmp) Now() Cmp { - return c.Func("now") -} - -// Token sets Token(?,?...) compare value. -func (c Cmp) Token(names ...string) Cmp { - return c.Func("token", names...) + name string + fn *Func } func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) { @@ -94,19 +53,15 @@ func (c Cmp) writeCql(cql *bytes.Buffer) (names []string) { cql.WriteString(" CONTAINS ") } - if c.fn == "" { + if c.fn == nil { cql.WriteByte('?') - if c.names == nil { + if c.name == "" { names = append(names, c.column) } else { - names = append(names, c.names...) + names = append(names, c.name) } } else { - cql.WriteString(c.fn) - cql.WriteByte('(') - placeholders(cql, len(c.names)) - cql.WriteByte(')') - names = append(names, c.names...) + names = append(names, c.fn.writeCql(cql)...) } return @@ -125,7 +80,16 @@ func EqNamed(column, name string) Cmp { return Cmp{ op: eq, column: column, - names: []string{name}, + name: name, + } +} + +// EqFunc produces column=someFunc(?...). +func EqFunc(column string, fn *Func) Cmp { + return Cmp{ + op: eq, + column: column, + fn: fn, } } @@ -142,7 +106,16 @@ func LtNamed(column, name string) Cmp { return Cmp{ op: lt, column: column, - names: []string{name}, + name: name, + } +} + +// LtFunc produces columnsomeFunc(?...). +func GtFunc(column string, fn *Func) Cmp { + return Cmp{ + op: gt, + column: column, + fn: fn, } } @@ -193,7 +184,16 @@ func GtOrEqNamed(column, name string) Cmp { return Cmp{ op: geq, column: column, - names: []string{name}, + name: name, + } +} + +// GtFunc produces column>=someFunc(?...). +func GtOrEqFunc(column string, fn *Func) Cmp { + return Cmp{ + op: geq, + column: column, + fn: fn, } } @@ -210,7 +210,7 @@ func InNamed(column, name string) Cmp { return Cmp{ op: in, column: column, - names: []string{name}, + name: name, } } @@ -227,7 +227,7 @@ func ContainsNamed(column, name string) Cmp { return Cmp{ op: cnt, column: column, - names: []string{name}, + name: name, } } diff --git a/qb/cmp_test.go b/qb/cmp_test.go index 28a5912..464d765 100644 --- a/qb/cmp_test.go +++ b/qb/cmp_test.go @@ -93,29 +93,24 @@ func TestCmp(t *testing.T) { // Functions { - C: Eq("eq").Func("fn", "arg0", "arg1"), + C: EqFunc("eq", Fn("fn", "arg0", "arg1")), S: "eq=fn(?,?)", N: []string{"arg0", "arg1"}, }, { - C: Eq("eq").MaxTimeuuid("arg0"), + C: EqFunc("eq", MaxTimeuuid("arg0")), S: "eq=maxTimeuuid(?)", N: []string{"arg0"}, }, { - C: Eq("eq").MinTimeuuid("arg0"), + C: EqFunc("eq", MinTimeuuid("arg0")), S: "eq=minTimeuuid(?)", N: []string{"arg0"}, }, { - C: Eq("eq").Now(), + C: EqFunc("eq", Now()), S: "eq=now()", }, - { - C: Eq("eq").Token("arg0", "arg1"), - S: "eq=token(?,?)", - N: []string{"arg0", "arg1"}, - }, } buf := bytes.Buffer{} diff --git a/qb/func.go b/qb/func.go new file mode 100644 index 0000000..d3ff29a --- /dev/null +++ b/qb/func.go @@ -0,0 +1,51 @@ +// 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" + +// Functions reference: +// https://cassandra.apache.org/doc/latest/cql/functions.html + +// Func is a custom database function invocation that can be use in a comparator +// or update statement. +type Func struct { + // function name + Name string + // name of the function parameters + ParamNames []string +} + +func (f *Func) writeCql(cql *bytes.Buffer) (names []string) { + cql.WriteString(f.Name) + cql.WriteByte('(') + placeholders(cql, len(f.ParamNames)) + cql.WriteByte(')') + names = append(names, f.ParamNames...) + return +} + +// Fn creates Func. +func Fn(name string, paramNames ...string) *Func { + return &Func{ + Name: name, + ParamNames: paramNames, + } +} + +// MinTimeuuid produces minTimeuuid(?). +func MinTimeuuid(name string) *Func { + return Fn("minTimeuuid", name) +} + +// MaxTimeuuid produces maxTimeuuid(?). +func MaxTimeuuid(name string) *Func { + return Fn("maxTimeuuid", name) +} + +// Now produces now(). +func Now() *Func { + return Fn("now") +} diff --git a/qb/token.go b/qb/token.go index 566b06c..acfd4f4 100644 --- a/qb/token.go +++ b/qb/token.go @@ -9,110 +9,72 @@ import ( "strings" ) +// TokenBuilder helps implement pagination using token function. +type TokenBuilder []string + // Token creates a new TokenBuilder. func Token(columns ...string) TokenBuilder { return TokenBuilder(columns) } -// TokenBuilder helps implement pagination using token function. -type TokenBuilder []string - // Eq produces token(column)=token(?). func (t TokenBuilder) Eq() Cmp { - return Cmp{ - op: eq, - fn: "token", - column: fmt.Sprint("token(", strings.Join(t, ","), ")"), - names: t, - } + return t.cmp(eq, nil) } // EqNamed produces token(column)=token(?) with a custom parameter name. func (t TokenBuilder) EqNamed(names ...string) Cmp { - return Cmp{ - op: eq, - fn: "token", - column: fmt.Sprint("token(", strings.Join(t, ","), ")"), - names: names, - } + return t.cmp(eq, names) } // Lt produces token(column)token(?). func (t TokenBuilder) Gt() Cmp { - return Cmp{ - op: gt, - fn: "token", - column: fmt.Sprint("token(", strings.Join(t, ","), ")"), - names: t, - } + return t.cmp(gt, nil) } // GtNamed produces token(column)>token(?) with a custom parameter name. func (t TokenBuilder) GtNamed(names ...string) Cmp { - return Cmp{ - op: gt, - fn: "token", - column: fmt.Sprint("token(", strings.Join(t, ","), ")"), - names: names, - } + return t.cmp(gt, names) } // GtOrEq produces token(column)>=token(?). func (t TokenBuilder) GtOrEq() Cmp { - return Cmp{ - op: geq, - fn: "token", - column: fmt.Sprint("token(", strings.Join(t, ","), ")"), - names: t, - } + return t.cmp(geq, nil) } // GtOrEqNamed produces token(column)>=token(?) with a custom parameter name. func (t TokenBuilder) GtOrEqNamed(names ...string) Cmp { + return t.cmp(geq, names) +} + +func (t TokenBuilder) cmp(op op, names []string) Cmp { + s := names + if s == nil { + s = t + } return Cmp{ - op: geq, - fn: "token", + op: op, column: fmt.Sprint("token(", strings.Join(t, ","), ")"), - names: names, + fn: Fn("token", s...), } }