From 906f9433fe0e149c72ab3d39d4601fbdbf61499c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Matczuk?= Date: Tue, 1 Aug 2017 12:44:10 +0200 Subject: [PATCH] qb: TTL and Timestamp named parameters --- qb/delete.go | 8 +++----- qb/delete_test.go | 7 +++---- qb/expr.go | 30 +++++++++++++----------------- qb/insert.go | 14 +++++++------- qb/insert_test.go | 13 ++++++------- qb/update.go | 11 +++++------ qb/update_test.go | 13 ++++++------- qb/utils.go | 11 +++++++++++ qb/utils_test.go | 18 ++++++++++++++++++ 9 files changed, 72 insertions(+), 53 deletions(-) create mode 100644 qb/utils_test.go diff --git a/qb/delete.go b/qb/delete.go index 21c92e1..f5b4bd4 100644 --- a/qb/delete.go +++ b/qb/delete.go @@ -5,7 +5,6 @@ package qb import ( "bytes" - "time" ) // DeleteBuilder builds CQL DELETE statements. @@ -38,8 +37,7 @@ func (b *DeleteBuilder) ToCql() (stmt string, names []string) { cql.WriteString(b.table) cql.WriteByte(' ') - b.using.writeCql(&cql) - + names = append(names, b.using.writeCql(&cql)...) names = append(names, b.where.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. -func (b *DeleteBuilder) Timestamp(t time.Time) *DeleteBuilder { - b.using.timestamp = t +func (b *DeleteBuilder) Timestamp() *DeleteBuilder { + b.using.timestamp = true return b } diff --git a/qb/delete_test.go b/qb/delete_test.go index db01ca1..01d6bf2 100644 --- a/qb/delete_test.go +++ b/qb/delete_test.go @@ -2,7 +2,6 @@ package qb import ( "testing" - "time" "github.com/google/go-cmp/cmp" ) @@ -47,9 +46,9 @@ func TestDeleteBuilder(t *testing.T) { }, // Add TIMESTAMP { - B: Delete("cycling.cyclist_name").Where(w).Timestamp(time.Unix(0, 0).Add(time.Microsecond * 123456789)), - S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP 123456789 WHERE id=? ", - N: []string{"expr"}, + B: Delete("cycling.cyclist_name").Where(w).Timestamp(), + S: "DELETE FROM cycling.cyclist_name USING TIMESTAMP ? WHERE id=? ", + N: []string{"_ts", "expr"}, }, // Add IF EXISTS { diff --git a/qb/expr.go b/qb/expr.go index e9d98b4..18069be 100644 --- a/qb/expr.go +++ b/qb/expr.go @@ -2,8 +2,6 @@ package qb import ( "bytes" - "fmt" - "time" ) type columns []string @@ -18,28 +16,26 @@ func (cols columns) writeCql(cql *bytes.Buffer) { } type using struct { - timestamp time.Time - ttl time.Duration + timestamp bool + ttl bool } -func (u using) writeCql(cql *bytes.Buffer) { - ts := !u.timestamp.IsZero() - - if ts { - cql.WriteString("USING TIMESTAMP ") - cql.WriteString(fmt.Sprint(u.timestamp.UnixNano() / 1000)) - cql.WriteByte(' ') +func (u using) writeCql(cql *bytes.Buffer) (names []string) { + if u.timestamp { + cql.WriteString("USING TIMESTAMP ? ") + names = append(names, "_ts") } - if u.ttl != 0 { - if ts { - cql.WriteString("AND TTL ") + if u.ttl { + if u.timestamp { + cql.WriteString("AND TTL ? ") } else { - cql.WriteString("USING TTL ") + cql.WriteString("USING TTL ? ") } - cql.WriteString(fmt.Sprint(int(u.ttl.Seconds()))) - cql.WriteByte(' ') + names = append(names, "_ttl") } + + return } type where cmps diff --git a/qb/insert.go b/qb/insert.go index 86a98a3..384ce92 100644 --- a/qb/insert.go +++ b/qb/insert.go @@ -5,7 +5,6 @@ package qb import ( "bytes" - "time" ) // InsertBuilder builds CQL INSERT statements. @@ -35,19 +34,20 @@ func (b *InsertBuilder) ToCql() (stmt string, names []string) { cql.WriteByte('(') b.columns.writeCql(&cql) + names = append(names, b.columns...) cql.WriteString(") ") cql.WriteString("VALUES (") placeholders(&cql, len(b.columns)) cql.WriteString(") ") - b.using.writeCql(&cql) + names = append(names, b.using.writeCql(&cql)...) if b.unique { cql.WriteString("IF NOT EXISTS ") } - stmt, names = cql.String(), b.columns + stmt = cql.String() return } @@ -70,13 +70,13 @@ func (b *InsertBuilder) Unique() *InsertBuilder { } // Timestamp sets a USING TIMESTAMP clause on the query. -func (b *InsertBuilder) Timestamp(t time.Time) *InsertBuilder { - b.using.timestamp = t +func (b *InsertBuilder) Timestamp() *InsertBuilder { + b.using.timestamp = true return b } // TTL sets a USING TTL clause on the query. -func (b *InsertBuilder) TTL(d time.Duration) *InsertBuilder { - b.using.ttl = d +func (b *InsertBuilder) TTL() *InsertBuilder { + b.using.ttl = true return b } diff --git a/qb/insert_test.go b/qb/insert_test.go index 02299eb..7a4d600 100644 --- a/qb/insert_test.go +++ b/qb/insert_test.go @@ -2,7 +2,6 @@ package qb import ( "testing" - "time" "github.com/google/go-cmp/cmp" ) @@ -34,15 +33,15 @@ func TestInsertBuilder(t *testing.T) { }, // Add TTL { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(time.Second * 86400), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TTL 86400 ", - N: []string{"id", "user_uuid", "firstname"}, + B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").TTL(), + S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TTL ? ", + N: []string{"id", "user_uuid", "firstname", "_ttl"}, }, // Add TIMESTAMP { - B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(time.Unix(0, 0).Add(time.Microsecond * 123456789)), - S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP 123456789 ", - N: []string{"id", "user_uuid", "firstname"}, + B: Insert("cycling.cyclist_name").Columns("id", "user_uuid", "firstname").Timestamp(), + S: "INSERT INTO cycling.cyclist_name (id,user_uuid,firstname) VALUES (?,?,?) USING TIMESTAMP ? ", + N: []string{"id", "user_uuid", "firstname", "_ts"}, }, // Add IF NOT EXISTS { diff --git a/qb/update.go b/qb/update.go index 4fd433c..1a5b802 100644 --- a/qb/update.go +++ b/qb/update.go @@ -5,7 +5,6 @@ package qb import ( "bytes" - "time" ) // UpdateBuilder builds CQL UPDATE statements. @@ -33,7 +32,7 @@ func (b *UpdateBuilder) ToCql() (stmt string, names []string) { cql.WriteString(b.table) cql.WriteByte(' ') - b.using.writeCql(&cql) + names = append(names, b.using.writeCql(&cql)...) cql.WriteString("SET ") 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. -func (b *UpdateBuilder) Timestamp(t time.Time) *UpdateBuilder { - b.using.timestamp = t +func (b *UpdateBuilder) Timestamp() *UpdateBuilder { + b.using.timestamp = true return b } // TTL sets a USING TTL clause on the query. -func (b *UpdateBuilder) TTL(d time.Duration) *UpdateBuilder { - b.using.ttl = d +func (b *UpdateBuilder) TTL() *UpdateBuilder { + b.using.ttl = true return b } diff --git a/qb/update_test.go b/qb/update_test.go index ba77154..2a2447f 100644 --- a/qb/update_test.go +++ b/qb/update_test.go @@ -2,7 +2,6 @@ package qb import ( "testing" - "time" "github.com/google/go-cmp/cmp" ) @@ -47,15 +46,15 @@ func TestUpdateBuilder(t *testing.T) { }, // Add TTL { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TTL(time.Second * 86400), - S: "UPDATE cycling.cyclist_name USING TTL 86400 SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, + B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).TTL(), + S: "UPDATE cycling.cyclist_name USING TTL ? SET id=?,user_uuid=?,firstname=? WHERE id=? ", + N: []string{"_ttl", "id", "user_uuid", "firstname", "expr"}, }, // Add TIMESTAMP { - B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timestamp(time.Unix(0, 0).Add(time.Microsecond * 123456789)), - S: "UPDATE cycling.cyclist_name USING TIMESTAMP 123456789 SET id=?,user_uuid=?,firstname=? WHERE id=? ", - N: []string{"id", "user_uuid", "firstname", "expr"}, + B: Update("cycling.cyclist_name").Set("id", "user_uuid", "firstname").Where(w).Timestamp(), + S: "UPDATE cycling.cyclist_name USING TIMESTAMP ? SET id=?,user_uuid=?,firstname=? WHERE id=? ", + N: []string{"_ts", "id", "user_uuid", "firstname", "expr"}, }, // Add IF EXISTS { diff --git a/qb/utils.go b/qb/utils.go index c89dc5e..5a83081 100644 --- a/qb/utils.go +++ b/qb/utils.go @@ -2,6 +2,7 @@ package qb import ( "bytes" + "time" ) // placeholders returns a string with count ? placeholders joined with commas. @@ -16,3 +17,13 @@ func placeholders(cql *bytes.Buffer, count int) { } 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 +} diff --git a/qb/utils_test.go b/qb/utils_test.go new file mode 100644 index 0000000..6d47701 --- /dev/null +++ b/qb/utils_test.go @@ -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") + } +}