Skip to content

Commit 285d251

Browse files
authored
Merge pull request #1 from riptano/prototype
Prototype
2 parents 7fd3560 + 7920db0 commit 285d251

26 files changed

+2832
-21
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
.idea
2+
.DS_Store
3+
14
# Binaries for programs and plugins
25
*.exe
36
*.exe~
47
*.dll
58
*.so
69
*.dylib
10+
data-endpoints
711

812
# Test binary, built with `go test -c`
913
*.test

README.md

Whitespace-only changes.

config/naming.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package config
2+
3+
import "github.com/iancoleman/strcase"
4+
5+
type NamingConvention interface {
6+
// ToCQLColumn converts a GraphQL/REST name to a CQL column name.
7+
ToCQLColumn(name string) string
8+
9+
// ToCQLColumn converts a GraphQL/REST name to a CQL table name.
10+
ToCQLTable(name string) string
11+
12+
// ToGraphQLField converts a CQL name (typically a column name) to a GraphQL field name.
13+
ToGraphQLField(name string) string
14+
15+
// ToGraphQLOperation converts a CQL name (typically a table name) to a GraphQL operation name.
16+
ToGraphQLOperation(prefix string, name string) string
17+
18+
// ToGraphQLType converts a CQL name (typically a table name) to a GraphQL type name.
19+
ToGraphQLType(name string) string
20+
21+
// ToGraphQLEnumValue converts a CQL name to a GraphQL enumeration value name.
22+
ToGraphQLEnumValue(name string) string
23+
}
24+
25+
type defaultNaming struct{}
26+
27+
// Default naming implementation.
28+
var DefaultNaming = &defaultNaming{}
29+
30+
func (n *defaultNaming) ToCQLColumn(name string) string {
31+
// TODO: Fix numbers: "Table2" or "table2" --> "table_2"
32+
return strcase.ToSnake(name)
33+
}
34+
35+
func (n *defaultNaming) ToCQLTable(name string) string {
36+
// TODO: Fix numbers: "Table2" or "table2" --> "table_2"
37+
return strcase.ToSnake(name)
38+
}
39+
40+
func (n *defaultNaming) ToGraphQLField(name string) string {
41+
return strcase.ToLowerCamel(name)
42+
}
43+
44+
func (n *defaultNaming) ToGraphQLOperation(prefix string, name string) string {
45+
if prefix == "" {
46+
return strcase.ToLowerCamel(name)
47+
} else {
48+
return strcase.ToLowerCamel(prefix) + strcase.ToCamel(name)
49+
}
50+
}
51+
52+
func (n *defaultNaming) ToGraphQLType(name string) string {
53+
return strcase.ToCamel(name)
54+
}
55+
56+
func (n *defaultNaming) ToGraphQLEnumValue(name string) string {
57+
return strcase.ToCamel(name)
58+
}

data.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"1": {
3+
"id": "1",
4+
"name": "Dan"
5+
},
6+
"2": {
7+
"id": "2",
8+
"name": "Lee"
9+
},
10+
"3": {
11+
"id": "3",
12+
"name": "Nick"
13+
}
14+
}

db/db.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package db
2+
3+
import (
4+
"github.com/gocql/gocql"
5+
)
6+
7+
// Db represents a connection to a db
8+
type Db struct {
9+
session DbSession
10+
}
11+
12+
// NewDb Gets a pointer to a db
13+
func NewDb(username string, password string, hosts ...string) (*Db, error) {
14+
cluster := gocql.NewCluster(hosts...)
15+
16+
if username != "" && password != "" {
17+
cluster.Authenticator = gocql.PasswordAuthenticator{
18+
Username: username,
19+
Password: password,
20+
}
21+
}
22+
23+
var (
24+
session *gocql.Session
25+
err error
26+
)
27+
28+
if session, err = cluster.CreateSession(); err != nil {
29+
return nil, err
30+
}
31+
32+
return &Db{
33+
session: &GoCqlSession{ref: session},
34+
}, nil
35+
}
36+
37+
// Keyspace Retrieves a keyspace
38+
func (db *Db) Keyspace(keyspace string) (*gocql.KeyspaceMetadata, error) {
39+
// We expose gocql types for now, we should wrap them in the future instead
40+
return db.session.KeyspaceMetadata(keyspace)
41+
}
42+
43+
// Keyspaces Retrieves all the keyspace names
44+
func (db *Db) Keyspaces() ([]string, error) {
45+
iter, err := db.session.ExecuteIter("SELECT keyspace_name FROM system_schema.keyspaces", nil)
46+
if err != nil {
47+
return nil, err
48+
}
49+
50+
var keyspaces []string
51+
for _, row := range iter.Values() {
52+
keyspaces = append(keyspaces, *row["keyspace_name"].(*string))
53+
}
54+
55+
return keyspaces, nil
56+
}

db/db_session.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package db
2+
3+
import (
4+
"encoding/hex"
5+
"github.com/gocql/gocql"
6+
)
7+
8+
type QueryOptions struct {
9+
UserOrRole string
10+
Consistency gocql.Consistency
11+
}
12+
13+
func NewQueryOptions() *QueryOptions {
14+
return &QueryOptions{
15+
Consistency: gocql.LocalOne,
16+
}
17+
}
18+
19+
func (q *QueryOptions) WithUserOrRole(userOrRole string) *QueryOptions {
20+
q.UserOrRole = userOrRole
21+
return q
22+
}
23+
24+
func (q *QueryOptions) WithConsistency(userOrRole string) *QueryOptions {
25+
q.UserOrRole = userOrRole
26+
return q
27+
}
28+
29+
type DbSession interface {
30+
// Execute executes a statement without returning row results
31+
Execute(query string, options *QueryOptions, values ...interface{}) error
32+
33+
// ExecuteIterSimple executes a statement and returns iterator to the result set
34+
ExecuteIter(query string, options *QueryOptions, values ...interface{}) (ResultSet, error)
35+
36+
//TODO: Extract metadata methods from interface into another interface
37+
KeyspaceMetadata(keyspaceName string) (*gocql.KeyspaceMetadata, error)
38+
}
39+
40+
type ResultSet interface {
41+
PageState() string
42+
Values() []map[string]interface{}
43+
}
44+
45+
func (r *goCqlResultIterator) PageState() string {
46+
return hex.EncodeToString(r.pageState)
47+
}
48+
49+
func (r *goCqlResultIterator) Values() []map[string]interface{} {
50+
return r.values
51+
}
52+
53+
type goCqlResultIterator struct {
54+
pageState []byte
55+
values []map[string]interface{}
56+
}
57+
58+
func newResultIterator(iter *gocql.Iter) (*goCqlResultIterator, error) {
59+
columns := iter.Columns()
60+
scanner := iter.Scanner()
61+
62+
items := make([]map[string]interface{}, 0)
63+
64+
for scanner.Next() {
65+
row, err := mapScan(scanner, columns)
66+
if err != nil {
67+
return nil, err
68+
}
69+
items = append(items, row)
70+
}
71+
72+
if err := iter.Close(); err != nil {
73+
return nil, err
74+
}
75+
76+
return &goCqlResultIterator{
77+
pageState: iter.PageState(),
78+
values: items,
79+
}, nil
80+
}
81+
82+
type GoCqlSession struct {
83+
ref *gocql.Session
84+
}
85+
86+
func (db *Db) Execute(query string, options *QueryOptions, values ...interface{}) (ResultSet, error) {
87+
return db.session.ExecuteIter(query, options, values...)
88+
}
89+
90+
func (db *Db) ExecuteNoResult(query string, options *QueryOptions, values ...interface{}) error {
91+
return db.session.Execute(query, options, values)
92+
}
93+
94+
func (session *GoCqlSession) Execute(query string, options *QueryOptions, values ...interface{}) error {
95+
_, err := session.ExecuteIter(query, options, values...)
96+
return err
97+
}
98+
99+
func (session *GoCqlSession) ExecuteIter(query string, options *QueryOptions, values ...interface{}) (ResultSet, error) {
100+
q := session.ref.Query(query, values...)
101+
if options != nil {
102+
q.Consistency(options.Consistency)
103+
if options.UserOrRole != "" {
104+
q.CustomPayload(map[string][]byte{
105+
"ProxyExecute": []byte(options.UserOrRole),
106+
})
107+
}
108+
}
109+
return newResultIterator(q.Iter())
110+
}
111+
112+
func (session *GoCqlSession) KeyspaceMetadata(keyspaceName string) (*gocql.KeyspaceMetadata, error) {
113+
return session.ref.KeyspaceMetadata(keyspaceName)
114+
}

db/keyspace.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package db
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
func (db *Db) CreateKeyspace(name string, dcReplicas map[string]int, options *QueryOptions) (bool, error) {
8+
// TODO: Escape keyspace datacenter names?
9+
dcs := ""
10+
for name, replicas := range dcReplicas {
11+
comma := ""
12+
if len(dcs) > 0 {
13+
comma = " ,"
14+
}
15+
dcs += fmt.Sprintf("%s'%s': %d", comma, name, replicas)
16+
}
17+
18+
query := fmt.Sprintf("CREATE KEYSPACE %s WITH REPLICATION = { 'class': 'NetworkTopologyStrategy', %s }", name, dcs)
19+
20+
err := db.session.Execute(query, options)
21+
22+
return err == nil, err
23+
}
24+
25+
func (db *Db) DropKeyspace(name string, options *QueryOptions) (bool, error) {
26+
// TODO: Escape keyspace name?
27+
query := fmt.Sprintf("DROP KEYSPACE %s", name)
28+
err := db.session.Execute(query, options)
29+
30+
return err == nil, err
31+
}

0 commit comments

Comments
 (0)