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 SELECT statement
Browse files Browse the repository at this point in the history
  • Loading branch information
suhailpatel committed Nov 17, 2020
1 parent 0cad9fd commit 4f51dd6
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 2 deletions.
59 changes: 57 additions & 2 deletions statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,49 @@ type SelectStatement struct {
allowFiltering bool // whether we should allow filtering
}

// Query provides the CQL query string for an SELECT query
func (s SelectStatement) Query() string {
query, _ := s.queryAndValues()
return query
}

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

func (s SelectStatement) queryAndValues() (string, []interface{}) {
values := make([]interface{}, 0)
query := []string{
"SELECT",
strings.Join(s.fields, ", "),
fmt.Sprintf("FROM %s.%s", s.keyspace, s.table),
}

whereCQL, whereValues := generateWhereCQL(s.where)
if whereCQL != "" {
query = append(query, "WHERE", whereCQL)
values = append(values, whereValues...)
}

orderByCQL := generateOrderByCQL(s.order)
if orderByCQL != "" {
query = append(query, "ORDER BY", orderByCQL)
}

if s.limit > 0 {
query = append(query, "LIMIT ?")
values = append(values, s.limit)
}

if s.allowFiltering {
query = append(query, "ALLOW FILTERING")
}

return strings.Join(query, " "), values
}

// InsertStatement represents an INSERT query to write some data in C*
// It satisfies the Statement interface
type InsertStatement struct {
Expand All @@ -67,13 +110,13 @@ type InsertStatement struct {
ttl time.Duration // ttl of the row
}

// Query provides the CQL query string for an UPDATE query
// Query provides the CQL query string for an INSERT INTO query
func (s InsertStatement) Query() string {
query, _ := s.queryAndValues()
return query
}

// Values provide the binding values for an UPDATE query
// Values provide the binding values for an INSERT INTO query
func (s InsertStatement) Values() []interface{} {
_, values := s.queryAndValues()
return values
Expand Down Expand Up @@ -239,3 +282,15 @@ func generateRelationCQL(rel Relation) (string, interface{}) {
panic(fmt.Sprintf("unknown comparator %v", rel.Comparator()))
}
}

// generateOrderByCQL generates the CQL for the ORDER BY clause. An expected
// output might look like:
// - foo ASC
// - foo ASC, bar DESC
func generateOrderByCQL(order []ClusteringOrderColumn) string {
out := make([]string, 0, len(order))
for _, oc := range order {
out = append(out, oc.Column+" "+oc.Direction.String())
}
return strings.Join(out, ", ")
}
44 changes: 44 additions & 0 deletions statement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,34 @@ func TestStatement(t *testing.T) {
}
}

func TestSelectStatement(t *testing.T) {
stmt := SelectStatement{keyspace: "ks1", table: "tbl1"}
stmt.fields = []string{"a", "b", "c"}
assert.Equal(t, "SELECT a, b, c FROM ks1.tbl1", stmt.Query())
assert.Equal(t, []interface{}{}, stmt.Values())

stmt.limit = 10
assert.Equal(t, "SELECT a, b, c FROM ks1.tbl1 LIMIT ?", stmt.Query())
assert.Equal(t, []interface{}{10}, stmt.Values())

stmt.order = []ClusteringOrderColumn{
{Column: "a", Direction: ASC},
}
assert.Equal(t, "SELECT a, b, c FROM ks1.tbl1 ORDER BY a ASC LIMIT ?", stmt.Query())
assert.Equal(t, []interface{}{10}, stmt.Values())

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

stmt.allowFiltering = true
assert.Equal(t, "SELECT a, b, c FROM ks1.tbl1 WHERE foo = ? AND baz IN ? ORDER BY a ASC LIMIT ? ALLOW FILTERING", stmt.Query())
assert.Equal(t, []interface{}{"bar", []interface{}{"bing"}, 10}, stmt.Values())
}

func TestInsertStatement(t *testing.T) {
stmt := InsertStatement{keyspace: "ks1", table: "tbl1"}
stmt.fieldMap = map[string]interface{}{"a": "b"}
Expand Down Expand Up @@ -153,3 +181,19 @@ func TestGenerateRelationCQL(t *testing.T) {
stmt, value = generateRelationCQL(Relation{cmp: -1})
})
}

func TestGenerateOrderByCQL(t *testing.T) {
stmt := generateOrderByCQL([]ClusteringOrderColumn{})
assert.Equal(t, "", stmt)

stmt = generateOrderByCQL([]ClusteringOrderColumn{
{Column: "foo", Direction: ASC},
})
assert.Equal(t, "foo ASC", stmt)

stmt = generateOrderByCQL([]ClusteringOrderColumn{
{Column: "foo", Direction: ASC},
{Column: "bar", Direction: DESC},
})
assert.Equal(t, "foo ASC, bar DESC", stmt)
}

0 comments on commit 4f51dd6

Please sign in to comment.