Skip to content
This repository has been archived by the owner on Sep 9, 2024. It is now read-only.

Commit

Permalink
Add an implementation of a DELETE statement
Browse files Browse the repository at this point in the history
  • Loading branch information
suhailpatel committed Nov 17, 2020
1 parent 3b7cc29 commit 5a69346
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 1 deletion.
65 changes: 64 additions & 1 deletion statement.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package gocassa

import "time"
import (
"fmt"
"strings"
"time"
)

type statement struct {
fieldNames []string
Expand Down Expand Up @@ -83,10 +87,69 @@ type DeleteStatement struct {
where []Relation // where filter clauses
}

// Query provides the CQL query string for a DELETE query
func (s DeleteStatement) Query() string {
query, _ := s.queryAndValues()
return query
}

// Values provide the binding values for a DELETE query
func (s DeleteStatement) Values() []interface{} {
_, values := s.queryAndValues()
return values
}

func (s DeleteStatement) queryAndValues() (string, []interface{}) {
whereCQL, whereValues := generateWhereCQL(s.where)
query := fmt.Sprintf("DELETE FROM %s.%s", s.keyspace, s.table)
if whereCQL != "" {
query += " WHERE " + whereCQL
}
return query, whereValues
}

// noOpStatement represents a statement that doesn't perform any specific
// query. It's used internally for testing, satisfies the Statement interface
type noOpStatement struct{}

func (_ noOpStatement) Query() string { return "" }

func (_ noOpStatement) Values() []interface{} { return []interface{}{} }

// generateWhereCQL takes a list of relations and generates the CQL for
// a WHERE clause
func generateWhereCQL(rs []Relation) (string, []interface{}) {
clauses, values := make([]string, 0, len(rs)), make([]interface{}, 0, len(rs))
for _, relation := range rs {
clause, bindValue := generateRelationCQL(relation)
clauses = append(clauses, clause)
values = append(values, bindValue)
}

if len(clauses) == 0 {
return "", []interface{}{}
}
return strings.Join(clauses, " AND "), values
}

func generateRelationCQL(rel Relation) (string, interface{}) {
field := strings.ToLower(rel.Field())
switch rel.Comparator() {
case CmpEquality:
return field + " = ?", rel.Terms()[0]
case CmpIn:
return field + " IN ?", rel.Terms()
case CmpGreaterThan:
return field + " > ?", rel.Terms()[0]
case CmpGreaterThanOrEquals:
return field + " >= ?", rel.Terms()[0]
case CmpLesserThan:
return field + " < ?", rel.Terms()[0]
case CmpLesserThanOrEquals:
return field + " <= ?", rel.Terms()[0]
default:
// This represents an invalid Comparator and would only manifest
// if we've initialised a Relation incorrectly within this package
panic(fmt.Sprintf("unknown comparator %v", rel.Comparator()))
}
}
69 changes: 69 additions & 0 deletions statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package gocassa

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestStatement(t *testing.T) {
Expand Down Expand Up @@ -41,3 +43,70 @@ func TestStatement(t *testing.T) {
t.Fatalf("expected 1 value, got %d values", len(stmtSelect.FieldNames()))
}
}

func TestDeleteStatement(t *testing.T) {
stmt := DeleteStatement{keyspace: "ks1", table: "tbl1"}
assert.Equal(t, "DELETE FROM ks1.tbl1", stmt.Query())

stmt.where = []Relation{
Eq("foo", "bar"),
}
assert.Equal(t, "DELETE FROM ks1.tbl1 WHERE foo = ?", stmt.Query())
assert.Equal(t, []interface{}{"bar"}, stmt.Values())

stmt.where = []Relation{
Eq("foo", "bar"),
In("baz", "a", "b", "c"),
}
assert.Equal(t, "DELETE FROM ks1.tbl1 WHERE foo = ? AND baz IN ?", stmt.Query())
assert.Equal(t, []interface{}{"bar", []interface{}{"a", "b", "c"}}, stmt.Values())
}

func TestGenerateWhereCQL(t *testing.T) {
stmt, values := generateWhereCQL([]Relation{
Eq("foo", "bar"),
})
assert.Equal(t, "foo = ?", stmt)
assert.Equal(t, []interface{}{"bar"}, values)

stmt, values = generateWhereCQL([]Relation{
Eq("foo", "bar"),
In("baz", "a", "b", "c"),
})
assert.Equal(t, "foo = ? AND baz IN ?", stmt)
assert.Equal(t, []interface{}{"bar", []interface{}{"a", "b", "c"}}, values)
}

func TestGenerateRelationCQL(t *testing.T) {
stmt, value := generateRelationCQL(Eq("foo", "bar"))
assert.Equal(t, "foo = ?", stmt)
assert.Equal(t, "bar", value)

stmt, value = generateRelationCQL(Eq("FoO", "BAR"))
assert.Equal(t, "foo = ?", stmt)
assert.Equal(t, "BAR", value)

stmt, value = generateRelationCQL(In("foo", "a", "b", "c"))
assert.Equal(t, "foo IN ?", stmt)
assert.Equal(t, []interface{}{"a", "b", "c"}, value)

stmt, value = generateRelationCQL(GT("foo", 1))
assert.Equal(t, "foo > ?", stmt)
assert.Equal(t, 1, value)

stmt, value = generateRelationCQL(GTE("foo", 1))
assert.Equal(t, "foo >= ?", stmt)
assert.Equal(t, 1, value)

stmt, value = generateRelationCQL(LT("foo", 1))
assert.Equal(t, "foo < ?", stmt)
assert.Equal(t, 1, value)

stmt, value = generateRelationCQL(LTE("foo", 1))
assert.Equal(t, "foo <= ?", stmt)
assert.Equal(t, 1, value)

assert.PanicsWithValue(t, "unknown comparator -1", func() {
stmt, value = generateRelationCQL(Relation{cmp: -1})
})
}

0 comments on commit 5a69346

Please sign in to comment.