qb: TTL and Timestamp named parameters

This commit is contained in:
Michał Matczuk
2017-08-01 12:44:10 +02:00
parent ab0839a9d1
commit 906f9433fe
9 changed files with 72 additions and 53 deletions

View File

@@ -5,7 +5,6 @@ package qb
import ( import (
"bytes" "bytes"
"time"
) )
// DeleteBuilder builds CQL DELETE statements. // DeleteBuilder builds CQL DELETE statements.
@@ -38,8 +37,7 @@ func (b *DeleteBuilder) ToCql() (stmt string, names []string) {
cql.WriteString(b.table) cql.WriteString(b.table)
cql.WriteByte(' ') cql.WriteByte(' ')
b.using.writeCql(&cql) names = append(names, b.using.writeCql(&cql)...)
names = append(names, b.where.writeCql(&cql)...) names = append(names, b.where.writeCql(&cql)...)
names = append(names, b._if.writeCql(&cql)...) names = append(names, b._if.writeCql(&cql)...)
@@ -64,8 +62,8 @@ func (b *DeleteBuilder) Columns(columns ...string) *DeleteBuilder {
} }
// Timestamp sets a USING TIMESTAMP clause on the query. // Timestamp sets a USING TIMESTAMP clause on the query.
func (b *DeleteBuilder) Timestamp(t time.Time) *DeleteBuilder { func (b *DeleteBuilder) Timestamp() *DeleteBuilder {
b.using.timestamp = t b.using.timestamp = true
return b return b
} }

View File

@@ -2,7 +2,6 @@ package qb
import ( import (
"testing" "testing"
"time"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
@@ -47,9 +46,9 @@ func TestDeleteBuilder(t *testing.T) {
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Delete("cycling.cyclist_name").Where(w).Timestamp(time.Unix(0, 0).Add(time.Microsecond * 123456789)), B: Delete("cycling.cyclist_name").Where(w).Timestamp(),
S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP 123456789 WHERE id=? ", S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP ? WHERE id=? ",
N: []string{"expr"}, N: []string{"_ts", "expr"},
}, },
// Add IF EXISTS // Add IF EXISTS
{ {

View File

@@ -2,8 +2,6 @@ package qb
import ( import (
"bytes" "bytes"
"fmt"
"time"
) )
type columns []string type columns []string
@@ -18,28 +16,26 @@ func (cols columns) writeCql(cql *bytes.Buffer) {
} }
type using struct { type using struct {
timestamp time.Time timestamp bool
ttl time.Duration ttl bool
} }
func (u using) writeCql(cql *bytes.Buffer) { func (u using) writeCql(cql *bytes.Buffer) (names []string) {
ts := !u.timestamp.IsZero() if u.timestamp {
cql.WriteString("USING TIMESTAMP ? ")
if ts { names = append(names, "_ts")
cql.WriteString("USING TIMESTAMP ")
cql.WriteString(fmt.Sprint(u.timestamp.UnixNano() / 1000))
cql.WriteByte(' ')
} }
if u.ttl != 0 { if u.ttl {
if ts { if u.timestamp {
cql.WriteString("AND TTL ") cql.WriteString("AND TTL ? ")
} else { } else {
cql.WriteString("USING TTL ") cql.WriteString("USING TTL ? ")
} }
cql.WriteString(fmt.Sprint(int(u.ttl.Seconds()))) names = append(names, "_ttl")
cql.WriteByte(' ')
} }
return
} }
type where cmps type where cmps

View File

@@ -5,7 +5,6 @@ package qb
import ( import (
"bytes" "bytes"
"time"
) )
// InsertBuilder builds CQL INSERT statements. // InsertBuilder builds CQL INSERT statements.
@@ -35,19 +34,20 @@ func (b *InsertBuilder) ToCql() (stmt string, names []string) {
cql.WriteByte('(') cql.WriteByte('(')
b.columns.writeCql(&cql) b.columns.writeCql(&cql)
names = append(names, b.columns...)
cql.WriteString(") ") cql.WriteString(") ")
cql.WriteString("VALUES (") cql.WriteString("VALUES (")
placeholders(&cql, len(b.columns)) placeholders(&cql, len(b.columns))
cql.WriteString(") ") cql.WriteString(") ")
b.using.writeCql(&cql) names = append(names, b.using.writeCql(&cql)...)
if b.unique { if b.unique {
cql.WriteString("IF NOT EXISTS ") cql.WriteString("IF NOT EXISTS ")
} }
stmt, names = cql.String(), b.columns stmt = cql.String()
return return
} }
@@ -70,13 +70,13 @@ func (b *InsertBuilder) Unique() *InsertBuilder {
} }
// Timestamp sets a USING TIMESTAMP clause on the query. // Timestamp sets a USING TIMESTAMP clause on the query.
func (b *InsertBuilder) Timestamp(t time.Time) *InsertBuilder { func (b *InsertBuilder) Timestamp() *InsertBuilder {
b.using.timestamp = t b.using.timestamp = true
return b return b
} }
// TTL sets a USING TTL clause on the query. // TTL sets a USING TTL clause on the query.
func (b *InsertBuilder) TTL(d time.Duration) *InsertBuilder { func (b *InsertBuilder) TTL() *InsertBuilder {
b.using.ttl = d b.using.ttl = true
return b return b
} }

View File

@@ -2,7 +2,6 @@ package qb
import ( import (
"testing" "testing"
"time"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
@@ -34,15 +33,15 @@ func TestInsertBuilder(t *testing.T) {
}, },
// Add TTL // Add TTL
{ {
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(time.Second * 86400), B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(),
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TTL 86400 ", S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TTL ? ",
N: []string{"id", "user_uuid", "firstname"}, N: []string{"id", "user_uuid", "firstname", "_ttl"},
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Unix(0, 0).Add(time.Microsecond * 123456789)), B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(),
S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 123456789 ", S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ",
N: []string{"id", "user_uuid", "firstname"}, N: []string{"id", "user_uuid", "firstname", "_ts"},
}, },
// Add IF NOT EXISTS // Add IF NOT EXISTS
{ {

View File

@@ -5,7 +5,6 @@ package qb
import ( import (
"bytes" "bytes"
"time"
) )
// UpdateBuilder builds CQL UPDATE statements. // UpdateBuilder builds CQL UPDATE statements.
@@ -33,7 +32,7 @@ func (b *UpdateBuilder) ToCql() (stmt string, names []string) {
cql.WriteString(b.table) cql.WriteString(b.table)
cql.WriteByte(' ') cql.WriteByte(' ')
b.using.writeCql(&cql) names = append(names, b.using.writeCql(&cql)...)
cql.WriteString("SET ") cql.WriteString("SET ")
for i, c := range b.columns { for i, c := range b.columns {
@@ -64,14 +63,14 @@ func (b *UpdateBuilder) Table(table string) *UpdateBuilder {
} }
// Timestamp sets a USING TIMESTAMP clause on the query. // Timestamp sets a USING TIMESTAMP clause on the query.
func (b *UpdateBuilder) Timestamp(t time.Time) *UpdateBuilder { func (b *UpdateBuilder) Timestamp() *UpdateBuilder {
b.using.timestamp = t b.using.timestamp = true
return b return b
} }
// TTL sets a USING TTL clause on the query. // TTL sets a USING TTL clause on the query.
func (b *UpdateBuilder) TTL(d time.Duration) *UpdateBuilder { func (b *UpdateBuilder) TTL() *UpdateBuilder {
b.using.ttl = d b.using.ttl = true
return b return b
} }

View File

@@ -2,7 +2,6 @@ package qb
import ( import (
"testing" "testing"
"time"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
) )
@@ -47,15 +46,15 @@ func TestUpdateBuilder(t *testing.T) {
}, },
// Add TTL // Add TTL
{ {
B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TTL(time.Second * 86400), B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TTL(),
S: "UPDATE cycling.cyclist_name USING TTL 86400 SET id=?,user_uuid=?,firstname=? WHERE id=? ", S: "UPDATE cycling.cyclist_name USING TTL ? SET id=?,user_uuid=?,firstname=? WHERE id=? ",
N: []string{"id", "user_uuid", "firstname", "expr"}, N: []string{"_ttl", "id", "user_uuid", "firstname", "expr"},
}, },
// Add TIMESTAMP // Add TIMESTAMP
{ {
B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timestamp(time.Unix(0, 0).Add(time.Microsecond * 123456789)), B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timestamp(),
S: "UPDATE cycling.cyclist_name USING TIMESTAMP 123456789 SET id=?,user_uuid=?,firstname=? WHERE id=? ", S: "UPDATE cycling.cyclist_name USING TIMESTAMP ? SET id=?,user_uuid=?,firstname=? WHERE id=? ",
N: []string{"id", "user_uuid", "firstname", "expr"}, N: []string{"_ts", "id", "user_uuid", "firstname", "expr"},
}, },
// Add IF EXISTS // Add IF EXISTS
{ {

View File

@@ -2,6 +2,7 @@ package qb
import ( import (
"bytes" "bytes"
"time"
) )
// placeholders returns a string with count ? placeholders joined with commas. // placeholders returns a string with count ? placeholders joined with commas.
@@ -16,3 +17,13 @@ func placeholders(cql *bytes.Buffer, count int) {
} }
cql.WriteByte('?') cql.WriteByte('?')
} }
// TTL converts duration to format expected in USING TTL clause.
func TTL(d time.Duration) int64 {
return int64(d.Seconds())
}
// Timestamp converts time to format expected in USING TIMESTAMP clause.
func Timestamp(t time.Time) int64 {
return t.UnixNano() / 1000
}

18
qb/utils_test.go Normal file
View File

@@ -0,0 +1,18 @@
package qb
import (
"testing"
"time"
)
func TestTTL(t *testing.T) {
if TTL(time.Second*86400) != 86400 {
t.Fatal("wrong ttl")
}
}
func TestTimestamp(t *testing.T) {
if Timestamp(time.Unix(0, 0).Add(time.Microsecond*123456789)) != 123456789 {
t.Fatal("wrong timestamp")
}
}