Skip to content
This repository has been archived by the owner on Jun 12, 2020. It is now read-only.

Commit

Permalink
more composite work and testing
Browse files Browse the repository at this point in the history
  • Loading branch information
carloscm committed Mar 16, 2012
1 parent b46e8fa commit 506e19c
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 61 deletions.
4 changes: 2 additions & 2 deletions README.md
@@ -1,6 +1,6 @@
# About

Gossie is (for now) a Go library with a low level wrapper for the Cassandra 1.0 thrift bidings with with utilities for connection pooling, primitive type marshalling and easy query building (much easier to use than the generated thrift bindings). A higher level layer will be implemented on top of the current code to allow for struct marshalling into rows and composites, among other things.
Gossie is (for now) a Go library with a low level wrapper for the Cassandra 1.0 thrift bidings with with utilities for connection pooling, primitive type marshaling and easy query building (much easier to use than the generated thrift bindings). A higher level layer will be implemented on top of the current code to allow for struct marshalling into rows and composites, among other things.


# Requeriments
Expand Down Expand Up @@ -29,7 +29,7 @@ Launch a Cassandra instance in localhost:9160, create a keyspace named TestGossi

# Example

I will provide a full example once the higher level marshalling is implemented. For examples of the low level layer check src/gossie/query_test.go
I will provide a full example once the higher level marshaling is implemented. For examples of the low level layer check src/gossie/query_test.go


# License
Expand Down
35 changes: 23 additions & 12 deletions src/gossie/connection_test.go
Expand Up @@ -9,12 +9,14 @@ import (

func TestConnection(t *testing.T) {

c, err := newConnection("127.0.0.1:9999", "NotExists", 3000)
if err == nil {
t.Fatal("Invalid connection parameters did not return error")
}

c, err = newConnection("127.0.0.1:9160", "NotExists", 1000)
/* kind of pointless
c, err := newConnection("127.0.0.1:9999", "NotExists", 3000)
if err == nil {
t.Fatal("Invalid connection parameters did not return error")
}
*/

c, err := newConnection("127.0.0.1:9160", "NotExists", 1000)
if err == nil {
t.Fatal("Invalid keyspace did not return error")
}
Expand All @@ -33,17 +35,26 @@ func TestConnection(t *testing.T) {

func TestNewConnectionPool(t *testing.T) {

cp, err := NewConnectionPool([]string{"127.0.0.1:9999"}, "NotExists", PoolOptions{Size: 50, Timeout: 3000})
if err == nil {
t.Fatal("Invalid connection parameters did not return error")
}
/* kind of pointless
cp, err := NewConnectionPool([]string{"127.0.0.1:9999"}, "NotExists", PoolOptions{Size: 50, Timeout: 3000})
if err == nil {
t.Fatal("Invalid connection parameters did not return error")
}
*/

cp, err = NewConnectionPool([]string{"127.0.0.1:9160"}, "NotExists", PoolOptions{Size: 50, Timeout: 3000})
cp, err := NewConnectionPool([]string{"127.0.0.1:9160"}, "NotExists", PoolOptions{Size: 50, Timeout: 3000})
if err == nil {
t.Fatal("Invalid keyspace did not return error")
}

cp, err = NewConnectionPool([]string{"127.0.0.1:9160", "127.0.0.1:9170", "127.0.0.1:9180"}, "TestGossie", PoolOptions{Size: 50, Timeout: 3000})
/* kind of pointless
cp, err = NewConnectionPool([]string{"127.0.0.1:9160", "127.0.0.1:9170", "127.0.0.1:9180"}, "TestGossie", PoolOptions{Size: 50, Timeout: 3000})
if err != nil {
t.Fatal("Error connecting to Cassandra:", err)
}
*/

cp, err = NewConnectionPool([]string{"127.0.0.1:9160"}, "TestGossie", PoolOptions{Size: 50, Timeout: 3000})
if err != nil {
t.Fatal("Error connecting to Cassandra:", err)
}
Expand Down
14 changes: 12 additions & 2 deletions src/gossie/struct.go
Expand Up @@ -17,6 +17,18 @@ todo:
support composite key, not just composite column (is this actually in use by anybody???)
name: and type: tag field modifiers to override default naming and marshaling
go maps support for things like
type s struct {
a int `cf:"cfname" key:"a" col:"atts" val:"atts"`
atts map[string]string
}
type s2 struct {
a int `cf:"cfname" key:"a" col:"b,atts" val:"atts"`
b UUID
atts map[string]string
}
--> then think about slicing/pagging this, oops
unmap
---
Expand Down Expand Up @@ -90,7 +102,6 @@ type fieldMapping struct {
fieldKind int
position int
name string
goType reflect.Type
cassandraType TypeDesc
}
type structMapping struct {
Expand Down Expand Up @@ -152,7 +163,6 @@ func newFieldMapping(pos int, sf reflect.StructField) *fieldMapping {
fm.cassandraType, fm.fieldKind = defaultCassandraType(sf.Type)
fm.position = pos
fm.name = sf.Name
fm.goType = sf.Type
return fm
}

Expand Down
167 changes: 122 additions & 45 deletions src/gossie/struct_test.go
Expand Up @@ -57,6 +57,32 @@ type noErrC struct {
b int
c int
}
type noErrD struct {
a int `cf:"cfname" key:"a" col:"b" val:"c"`
b []int
c []int
}
type noErrE struct {
a int `cf:"cfname" key:"a" col:"b,c" val:"d"`
b int
c []int
d []int
}
type everythingComp struct {
Key string `cf:"cfname" key:"Key" col:"FBytes,FBool,FInt8,FInt16,FInt32,FInt,FInt64,FFloat32,FFloat64,FString,FUUID,*name" val:"*value"`
FBytes []byte
FBool bool
FInt8 int8
FInt16 int16
FInt32 int32
FInt int
FInt64 int64
FFloat32 float32
FFloat64 float64
FString string
FUUID UUID
Val string
}

func buildMappingFromPtr(instance interface{}) (*structMapping, os.Error) {
valuePtr := reflect.ValueOf(instance)
Expand All @@ -72,10 +98,13 @@ func structMapMustError(t *testing.T, instance interface{}) {
}
}

func TestStructMapping(t *testing.T) {
var sampleInt int
sampleIntT := reflect.TypeOf(sampleInt)
func checkMapping(t *testing.T, expected, actual interface{}, name string) {
if !reflect.DeepEqual(expected, actual) {
t.Error("Mapping for struct sample", name, "does not match expected output")
}
}

func TestStructMapping(t *testing.T) {
structMapMustError(t, &errNoMeta{})
structMapMustError(t, &errNoMetaKeyColVal{})
structMapMustError(t, &errNoMetaColVal{})
Expand All @@ -87,77 +116,125 @@ func TestStructMapping(t *testing.T) {
mapA, _ := buildMappingFromPtr(&noErrA{1, 2, 3})
goodA := &structMapping{
cf: "cfname",
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", goType: sampleIntT, cassandraType: LongType},
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", cassandraType: LongType},
columns: []*fieldMapping{
&fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", goType: sampleIntT, cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", cassandraType: LongType},
},
value: &fieldMapping{fieldKind: baseTypeField, position: 2, name: "c", goType: sampleIntT, cassandraType: LongType},
value: &fieldMapping{fieldKind: baseTypeField, position: 2, name: "c", cassandraType: LongType},
others: nil,
isCompositeColumn: false,
}
if !reflect.DeepEqual(mapA, goodA) {
t.Error("Mapping for struct sample A does not match expected output, ", mapA, " vs ", goodA)
}
checkMapping(t, goodA, mapA, "mapA")

mapB, _ := buildMappingFromPtr(&noErrB{1, 2, 3})
goodB := &structMapping{
cf: "cfname",
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", goType: sampleIntT, cassandraType: LongType},
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", cassandraType: LongType},
columns: []*fieldMapping{
&fieldMapping{fieldKind: starNameField, position: 0, name: "", goType: nil, cassandraType: 0},
&fieldMapping{fieldKind: starNameField, position: 0, name: "", cassandraType: 0},
},
value: &fieldMapping{fieldKind: starValueField, position: 0, name: "", goType: nil, cassandraType: 0},
value: &fieldMapping{fieldKind: starValueField, position: 0, name: "", cassandraType: 0},
others: map[string]*fieldMapping{
"b": &fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", goType: sampleIntT, cassandraType: LongType},
"c": &fieldMapping{fieldKind: baseTypeField, position: 2, name: "c", goType: sampleIntT, cassandraType: LongType},
"b": &fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", cassandraType: LongType},
"c": &fieldMapping{fieldKind: baseTypeField, position: 2, name: "c", cassandraType: LongType},
},
isCompositeColumn: false,
}
if !reflect.DeepEqual(mapB, goodB) {
t.Error("Mapping for struct sample B does not match expected output, ", mapB, " vs ", goodB)
}
checkMapping(t, goodB, mapB, "mapB")

mapC, _ := buildMappingFromPtr(&noErrC{1, 2, 3})
goodC := &structMapping{
cf: "cfname",
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", goType: sampleIntT, cassandraType: LongType},
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", cassandraType: LongType},
columns: []*fieldMapping{
&fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", goType: sampleIntT, cassandraType: LongType},
&fieldMapping{fieldKind: starNameField, position: 0, name: "", goType: nil, cassandraType: 0},
&fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", cassandraType: LongType},
&fieldMapping{fieldKind: starNameField, position: 0, name: "", cassandraType: 0},
},
value: &fieldMapping{fieldKind: starValueField, position: 0, name: "", goType: nil, cassandraType: 0},
value: &fieldMapping{fieldKind: starValueField, position: 0, name: "", cassandraType: 0},
others: map[string]*fieldMapping{
"c": &fieldMapping{fieldKind: baseTypeField, position: 2, name: "c", goType: sampleIntT, cassandraType: LongType},
"c": &fieldMapping{fieldKind: baseTypeField, position: 2, name: "c", cassandraType: LongType},
},
isCompositeColumn: true,
}
if !reflect.DeepEqual(mapC, goodC) {
t.Error("Mapping for struct sample C does not match expected output, ", mapC, " vs ", goodC)
}
}

type timeline struct {
UserId string `cf:"Timelines" key:"UserId" col:"TweetId,*name" val:"*value"`
TweetId int
Author string
Body string
}

func TestMap(t *testing.T) {

tweet := &timeline{UserId: "abc", TweetId: 3, Author: "xyz", Body: "hello world"}
checkMapping(t, goodC, mapC, "mapC")

row, _ := Map(tweet)
mapD, _ := buildMappingFromPtr(&noErrD{1, []int{2, 3}, []int{4, 5}})
goodD := &structMapping{
cf: "cfname",
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", cassandraType: LongType},
columns: []*fieldMapping{
&fieldMapping{fieldKind: baseTypeSliceField, position: 1, name: "b", cassandraType: LongType},
},
value: &fieldMapping{fieldKind: baseTypeSliceField, position: 2, name: "c", cassandraType: LongType},
others: nil,
isCompositeColumn: false,
}
checkMapping(t, goodD, mapD, "mapD")

if len(row.Columns) != 2 {
t.Error("Expected number of columns is 2, got ", len(row.Columns))
mapE, _ := buildMappingFromPtr(&noErrE{1, 2, []int{3, 4}, []int{5, 6}})
goodE := &structMapping{
cf: "cfname",
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "a", cassandraType: LongType},
columns: []*fieldMapping{
&fieldMapping{fieldKind: baseTypeField, position: 1, name: "b", cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeSliceField, position: 2, name: "c", cassandraType: LongType},
},
value: &fieldMapping{fieldKind: baseTypeSliceField, position: 3, name: "d", cassandraType: LongType},
others: nil,
isCompositeColumn: true,
}
checkMapping(t, goodE, mapE, "mapE")

t.Log(row.Columns[0].Name)
t.Log(row.Columns[0].Value)
t.Log(row.Columns[1].Name)
t.Log(row.Columns[1].Value)
eComp, _ := buildMappingFromPtr(&everythingComp{"a", []byte{1, 2}, true, 3, 4, 5, 6, 7, 8.0, 9.0, "b",
[16]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, "c"})
goodEComp := &structMapping{
cf: "cfname",
key: &fieldMapping{fieldKind: baseTypeField, position: 0, name: "Key", cassandraType: UTF8Type},
columns: []*fieldMapping{
&fieldMapping{fieldKind: baseTypeField, position: 1, name: "FBytes", cassandraType: BytesType},
&fieldMapping{fieldKind: baseTypeField, position: 2, name: "FBool", cassandraType: BooleanType},
&fieldMapping{fieldKind: baseTypeField, position: 3, name: "FInt8", cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeField, position: 4, name: "FInt16", cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeField, position: 5, name: "FInt32", cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeField, position: 6, name: "FInt", cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeField, position: 7, name: "FInt64", cassandraType: LongType},
&fieldMapping{fieldKind: baseTypeField, position: 8, name: "FFloat32", cassandraType: FloatType},
&fieldMapping{fieldKind: baseTypeField, position: 9, name: "FFloat64", cassandraType: DoubleType},
&fieldMapping{fieldKind: baseTypeField, position: 10, name: "FString", cassandraType: UTF8Type},
&fieldMapping{fieldKind: baseTypeField, position: 11, name: "FUUID", cassandraType: UUIDType},
&fieldMapping{fieldKind: starNameField, position: 0, name: "", cassandraType: 0},
},
value: &fieldMapping{fieldKind: starValueField, position: 0, name: "", cassandraType: 0},
others: map[string]*fieldMapping{
"Val": &fieldMapping{fieldKind: baseTypeField, position: 12, name: "Val", cassandraType: UTF8Type},
},
isCompositeColumn: true,
}
t.Log(goodEComp.key)
t.Log(eComp.key)
checkMapping(t, goodEComp, eComp, "eComp")

//t.Fatal("heh")
}

func TestMap(t *testing.T) {
ec := &everythingComp{"a", []byte{1, 2}, true, 3, 4, 5, 6, 7, 8.0, 9.0, "b",
[16]byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}, "c"}
row, err := Map(ec)
if err != nil {
t.Fatal("Unexpected error in test map:", err)
}
if len(row.Columns) != 1 {
t.Error("Expected number of columns is 1, got ", len(row.Columns))
}
name := []byte{0, 2, 1, 2, 0, 0, 1, 1, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 8, 0, 0, 0,
0, 0, 0, 0, 5, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 4, 65, 0, 0, 0, 0, 0,
8, 64, 34, 0, 0, 0, 0, 0, 0, 0, 0, 1, 98, 0, 0, 16, 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204,
221, 238, 255, 0, 0, 3, 86, 97, 108, 0}
value := []byte{99}
if !reflect.DeepEqual(name, row.Columns[0].Name) {
t.Error("Invalid composite column name in for test row")
}
if !reflect.DeepEqual(value, row.Columns[0].Value) {
t.Error("Invalid value in test row")
}
}
10 changes: 10 additions & 0 deletions src/gossie/types.go
Expand Up @@ -641,3 +641,13 @@ func packComposite(current, component []byte, comparator, sliceStart, inclusive
r = append(r, component...)
return append(r, eoc)
}

func unpackComposite(composite []byte) [][]byte {
components := make([][]byte, 0)
for len(composite) > 0 {
l := enc.BigEndian.Uint16(composite[:2])
components = append(components, composite[2:2+l])
composite = composite[3+l:]
}
return components
}

0 comments on commit 506e19c

Please sign in to comment.