Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

start Cursor interface

  • Loading branch information...
commit a6601cc60b6002122583c329ab9f41c43250c6aa 1 parent 92cdb87
@carloscm authored
View
42 README.md
@@ -8,6 +8,7 @@ The official Apache Thrift libraries for Go are outdated and buggy. For now the
https://github.com/pomack/thrift4go
Installing thrift4go under GOPATH in Go 1:
+
```
1) cd lib/go/src
2) cp -R thrift $GOPATH/src
@@ -18,7 +19,7 @@ Installing thrift4go under GOPATH in Go 1:
There is no need to generate a Cassandra Thrift biding, I am providing one with Gossie (and the whole point is not to have to use it!)
-For application usage copy the sources to your GOPATH/src and issue a go install to build and copy the libraries:
+For application usage copy the sources to your $GOPATH/src and issue a go install to build and copy the libraries:
```
1) cp -R src/* $GOPATH/src
@@ -74,7 +75,7 @@ The first part of the high level Gossie interface is the Map/Unmap functions. Th
In CQL 3.0:
CREATE TABLE timeline (
user_id varchar,
- tweet_id uuid,
+ tweet_id bigint,
author varchar,
body varchar,
PRIMARY KEY (user_id, tweet_id)
@@ -84,17 +85,46 @@ CREATE TABLE timeline (
// In Gossie:
type Timeline struct {
UserID string `cf:"Timeline" key:"UserID" col:"TweetID,*name" val:"*value"`
- TweetID UUID
+ TweetID int64
Author string
Body string
}
-row, err = Map(&Timeline{"userid", ..., "Author Name", "Hey this thing rocks!"})
+row, err = Map(&Timeline{"userid", 10000000000004, "Author Name", "Hey this thing rocks!"})
````
-### High level queries
+### Cursors
+
+As a convenient wrapper over Map/Unmap and the Query/Mutation interfaces Gossie provides the Cursor interface. This wrapper implements a classic database cursor over rows and composite row slices. Example:
+
+```Go
+
+type Timeline struct {
+ UserID string `cf:"Timeline" key:"UserID" col:"TweetID,*name" val:"*value"`
+ TweetID int64
+ Author string
+ Body string
+}
+
+// initialize a cursor over a struct instance. we can reuse both the cursor and the struct for all operations
+tweet := &Timeline{"userid", 10000000000004, "Author Name", "Hey this thing rocks!"}
+cursor := pool.Cursor(tweet)
+
+// write a single tweet
+cursor.Write()
+
+// read a single tweet. this will implicitly use the key field for the row key, and will add a slice operation
+// if the struct has fixed composite columns
+tweet.Read(1)
+
+// change the row key and the fixed composite filed and read a different tweet, reusing both the struct and the cursor
+tweet.UserID = "anotheruser"
+tweet.TweetID = 20000000000001
+cursor.Read(1)
+// tweet now contains the just read tweet
+````
-Coming soon!
+Comming soon: range reads for composites with buffering and paging
# License
View
6 schema-test.txt
@@ -28,3 +28,9 @@ create column family Composite with
key_validation_class = BytesType and
default_validation_class = BytesType
;
+
+create column family Reasonable with
+ comparator = 'CompositeType(LongType,AsciiType)' and
+ key_validation_class = UTF8Type and
+ default_validation_class = BytesType
+;
View
7 src/gossie/connection.go
@@ -59,6 +59,9 @@ type ConnectionPool interface {
// Mutation returns a new mutation builder for write operations
Mutation() Mutation
+ // Cursor returns a high level interface for read and write operations over structs
+ Cursor(interface{}) Cursor
+
// Close all the connections in the pool
Close()
}
@@ -308,6 +311,10 @@ func (cp *connectionPool) Mutation() Mutation {
return makeMutation(cp, cp.options.WriteConsistency)
}
+func (cp *connectionPool) Cursor(source interface{}) Cursor {
+ return makeCursor(cp, source)
+}
+
func (cp *connectionPool) Keyspace() string {
return cp.keyspace
}
View
147 src/gossie/cursor.go
@@ -0,0 +1,147 @@
+package gossie
+
+import (
+ "errors"
+ "fmt"
+)
+
+/*
+
+todo:
+
+ buffering for slicing and range get
+ Next/Prev for the buffering with autopaging
+
+ isSliceColumn == true
+
+ Search() and interface(s) for indexed get
+
+ multiget
+ still need to think abstraction
+ or just with a direct call that accepts interface{} and assumes Go slices? what about composites?
+
+*/
+
+// Cursor is a simple cursor-based interface for reading and writing structs from a Cassandra column family.
+type Cursor interface {
+
+ // Read rows (or slices of a row) to fill up the struct.
+ //
+ // For limit == 1 a single get operation will be issued. If a composite is present then this operation will
+ // issue a slice with an exact match for the composite value
+ //
+ // For limit > 1, and for structs with no composite, a range get operation will be issued, the result buffered
+ // internally in the Cursor, and the first returned row unmapped into the struct. Next() is then available for
+ // paging inside the returned results and will issue new range get operations when neede. Please note that row
+ // range get is unordered in most Cassandra configurations. TO DO
+ //
+ // If the struct has a composite column name then this operation will issue a single row get, but with a slice
+ // predicate that allows for iteration over the row with Next()/Prev() TO DO
+ Read(limit int) error
+
+ //Next() bool
+ //Prev() bool
+
+ //First()
+
+ // Write a single row (or slice of a row) with the data currently in the struct.
+ Write() error
+
+ //Delete()
+}
+
+type cursor struct {
+ source interface{}
+ pool *connectionPool
+ //position int
+ //buffer []interface{}
+}
+
+func makeCursor(cp *connectionPool, source interface{}) (c *cursor) {
+ return &cursor{
+ source: source,
+ pool: cp,
+ }
+}
+
+func (c *cursor) Write() error {
+
+ row, ms, err := internalMap(c.source)
+ if err != nil {
+ return err
+ }
+
+ if err = c.pool.Mutation().Insert(ms.sm.cf, row).Run(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (c *cursor) Read(limit int) error {
+ if limit < 0 {
+ return errors.New("Limit is less than 1, nothing to read")
+ }
+
+ // deconstruct the source struct into a reflect.Value and a (cached) struct mapping
+ ms, err := newMappedStruct(c.source)
+ if err != nil {
+ return err
+ }
+
+ // sanity checks
+ if !ms.sm.isStarNameColumn && !ms.sm.isSliceColumn {
+ return errors.New(fmt.Sprint("Struct ", ms.v.Type().Name(), " has no *name nor slice field in its col tag, nothing to read"))
+ }
+ if ms.sm.isSliceColumn {
+ return errors.New(fmt.Sprint("Slice field in col tag is unsuported in Cursor for now, check back soon!"))
+ }
+
+ // marshal the key field for the key to look up
+ key, err := ms.marshalKey()
+ if err != nil {
+ return err
+ }
+
+ // start building the query
+ q := c.pool.Query().Cf(ms.sm.cf)
+
+ //isCompositeColumn bool
+ //isSliceColumn bool
+ //isStarNameColumn bool
+
+ if limit == 1 {
+
+ if ms.sm.isCompositeColumn {
+ return errors.New(fmt.Sprint("Cursor composite support will be implemented soon!"))
+ /*
+
+ // we only want a single result so issue an exact match composite comparator slice
+ start := make([]byte, 0)
+ start = packComposite(start, component []byte, true, true, true)
+
+ packComposite(start, component []byte, true, sliceStart, inclusive bool) []byte {
+
+ s := &Slice{
+ Start:
+ End:
+ Count: 1
+ }
+ q.Slice(s)
+ */
+
+ }
+ row, err := q.Get(key)
+ if err != nil {
+ return err
+ }
+ err = Unmap(row, c.source)
+ if err != nil {
+ return err
+ }
+ } else {
+ return errors.New(fmt.Sprint("Limit > 1 will be implemented soon!"))
+ }
+
+ return nil
+}
View
52 src/gossie/cursor_test.go
@@ -0,0 +1,52 @@
+package gossie
+
+import (
+ "reflect"
+ "testing"
+)
+
+type ReasonableOne struct {
+ Username string `cf:"Reasonable" key:"Username" col:"TweetID,*name" val:"*value"`
+ TweetID int64
+ Lat float32
+ Lon float32
+ Body string
+ Cursor
+}
+
+func TestRead(t *testing.T) {
+ cp, err := NewConnectionPool([]string{"127.0.0.1:9160"}, "TestGossie", PoolOptions{Size: 1, Timeout: 1000})
+ if err != nil {
+ t.Fatal("Error connecting to Cassandra:", err)
+ }
+
+ ro := &ReasonableOne{
+ Username: "testuser",
+ TweetID: 100000000000002,
+ Lat: 1.00002,
+ Lon: -38.11,
+ Body: "hey this thing appears to work, nice!",
+ }
+
+ cursor := cp.Cursor(ro)
+ err = cursor.Write()
+ if err != nil {
+ t.Error("Writing struct:", err)
+ }
+
+ ro2 := &ReasonableOne{
+ Username: "testuser",
+ TweetID: 100000000000002,
+ }
+
+ cursor2 := cp.Cursor(ro2)
+ err = cursor2.Read(1)
+ if err != nil {
+ t.Error("Reading struct:", err)
+ }
+
+ if !reflect.DeepEqual(ro, ro2) {
+ t.Error("Read does not match Write")
+ }
+
+}
View
2  src/gossie/query.go
@@ -140,7 +140,7 @@ type Mutation interface {
// Delete deletes a single row specified by key
Delete(cf string, key []byte) Mutation
- // Delete deletes the passed columns from the row specified by key
+ // DeleteColumns deletes the passed columns from the row specified by key
DeleteColumns(cf string, key []byte, columns [][]byte) Mutation
//DeleteSlice(cf string, key []byte, slice *Slice) Mutation
View
9 src/gossie/schema.go
@@ -7,6 +7,15 @@ import (
"cassandra"
)
+/*
+to do:
+ generate CQL schema from tagged Go structs
+ validate tagged Go structs against schemas
+ handle ReversedType
+ handle type options
+ handle composited column names in the schema (is this in use/allowed?)
+*/
+
type Schema struct {
ColumnFamilies map[string]*ColumnFamily
}
View
2  src/gossie/schema_test.go
@@ -16,7 +16,7 @@ func TestSchema(t *testing.T) {
schema := newSchema(ksDef)
defer c.close()
- if len(schema.ColumnFamilies) != 3 {
+ if len(schema.ColumnFamilies) != 4 {
t.Error("Test schema must have 3 CFs")
}
View
163 src/gossie/struct.go
@@ -12,6 +12,14 @@ import (
todo:
+ allow some form of "custom composite" to support common use cases like row keys in the form (read as ascii) 111:222:333.
+ -> maybe support it via optional callables over the passed interface? OnMapKey/etc
+
+ allow to reuse the same fields as both key and col component
+
+ OR: introduce special key field tags to use during sharding, since the "row key" concept losses meaning in this case,
+ since it is managed by the lib
+
go maps support for things like
type s struct {
a int `cf:"cfname" key:"a" col:"atts" val:"atts"`
@@ -50,6 +58,8 @@ type structMapping struct {
value *fieldMapping
others map[string]*fieldMapping
isCompositeColumn bool
+ isSliceColumn bool
+ isStarNameColumn bool
}
func defaultCassandraType(t reflect.Type) (TypeDesc, int) {
@@ -175,13 +185,17 @@ func newStructMapping(t reflect.Type) (*structMapping, error) {
if !isLast {
return nil, errors.New(fmt.Sprint("*name can only be used in the last position of a composite, error in struct ", t.Name()))
} else {
+ sm.isStarNameColumn = true
fm = &fieldMapping{fieldKind: starNameField}
}
} else if fm, found = fields[name]; !found {
return nil, errors.New(fmt.Sprint("Referenced column field ", name, " does not exist in struct ", t.Name()))
}
- if fm.fieldKind == baseTypeSliceField && !isLast {
- return nil, errors.New(fmt.Sprint("Slice struct fields can only be used in the last position of a composite, error in struct ", t.Name()))
+ if fm.fieldKind == baseTypeSliceField {
+ sm.isSliceColumn = true
+ if !isLast {
+ return nil, errors.New(fmt.Sprint("Slice struct fields can only be used in the last position of a composite, error in struct ", t.Name()))
+ }
}
delete(fields, name)
sm.columns = append(sm.columns, fm)
@@ -207,6 +221,9 @@ func getMapping(v reflect.Value) (*structMapping, error) {
found := false
t := v.Type()
mapCacheMutex.Lock()
+ if mapCache == nil {
+ mapCache = make(map[reflect.Type]*structMapping)
+ }
if sm, found = mapCache[t]; !found {
sm, err = newStructMapping(t)
if err != nil {
@@ -217,7 +234,16 @@ func getMapping(v reflect.Value) (*structMapping, error) {
return sm, err
}
-func Map(source interface{}) (*Row, error) {
+type mappedStruct struct {
+ source interface{}
+ v reflect.Value
+ sm *structMapping
+}
+
+func newMappedStruct(source interface{}) (*mappedStruct, error) {
+ ms := &mappedStruct{source: source}
+ var err error
+
// always work with a pointer to struct
vp := reflect.ValueOf(source)
if vp.Kind() != reflect.Ptr {
@@ -226,38 +252,63 @@ func Map(source interface{}) (*Row, error) {
if vp.IsNil() {
return nil, errors.New("Passed source is not a pointer to a struct")
}
- v := reflect.Indirect(vp)
- if v.Kind() != reflect.Struct {
+ ms.v = reflect.Indirect(vp)
+ if ms.v.Kind() != reflect.Struct {
return nil, errors.New("Passed source is not a pointer to a struct")
}
- if !v.CanSet() {
+ if !ms.v.CanSet() {
return nil, errors.New("Cannot modify the passed struct instance")
}
- sm, err := getMapping(v)
+ ms.sm, err = getMapping(ms.v)
if err != nil {
return nil, err
}
+
+ return ms, nil
+}
+
+func (ms *mappedStruct) marshalKey() ([]byte, error) {
+ vk := ms.v.Field(ms.sm.key.position)
+ b, err := Marshal(vk.Interface(), ms.sm.key.cassandraType)
+ if err != nil {
+ return nil, errors.New(fmt.Sprint("Error marshaling key field ", ms.sm.key.name, ":", err))
+ }
+ return b, nil
+}
+
+func internalMap(source interface{}) (*Row, *mappedStruct, error) {
+ // deconstruct the source struct into a reflect.Value and a (cached) struct mapping
+ ms, err := newMappedStruct(source)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ // allocate new row to return
row := &Row{}
- // marshal key
- vk := v.Field(sm.key.position)
- b, err := Marshal(vk.Interface(), sm.key.cassandraType)
+ // marshal the key field
+ b, err := ms.marshalKey()
if err != nil {
- return nil, errors.New(fmt.Sprint("Error marshaling key field ", sm.key.name, ":", err))
+ return nil, nil, err
}
row.Key = b
// marshal columns and values
- return row, mapField(v, row, sm, 0, make([]byte, 0), make([]byte, 0), 0)
+ return row, ms, ms.mapField(row, 0, make([]byte, 0), make([]byte, 0), 0)
+}
+
+func Map(source interface{}) (*Row, error) {
+ row, _, err := internalMap(source)
+ return row, err
}
-func mapField(source reflect.Value, row *Row, sm *structMapping, component int, composite []byte, value []byte, valueIndex int) error {
+func (ms *mappedStruct) mapField(row *Row, component int, composite []byte, value []byte, valueIndex int) error {
// check if there are components left
- if component < len(sm.columns) {
+ if component < len(ms.sm.columns) {
- fm := sm.columns[component]
+ fm := ms.sm.columns[component]
// switch type of field named by component
switch fm.fieldKind {
@@ -265,22 +316,22 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
// base type
case baseTypeField:
// set value of the current composite field to the field value
- v := source.Field(fm.position)
+ v := ms.v.Field(fm.position)
b, err := Marshal(v.Interface(), fm.cassandraType)
if err != nil {
return errors.New(fmt.Sprint("Error marshaling field ", fm.name, ":", err))
}
- if sm.isCompositeColumn {
+ if ms.sm.isCompositeColumn {
composite = packComposite(composite, b, false, false, false)
} else {
composite = b
}
- return mapField(source, row, sm, component+1, composite, value, valueIndex)
+ return ms.mapField(row, component+1, composite, value, valueIndex)
// slice of base type
case baseTypeSliceField:
// iterate slice and map more columns
- v := source.Field(fm.position)
+ v := ms.v.Field(fm.position)
n := v.Len()
for i := 0; i < n; i++ {
// set value of the current composite field to the field value
@@ -290,12 +341,12 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
return errors.New(fmt.Sprint("Error marshaling field ", fm.name, ":", err))
}
var subComposite []byte
- if sm.isCompositeColumn {
+ if ms.sm.isCompositeColumn {
subComposite = packComposite(composite, b, false, false, false)
} else {
subComposite = b
}
- err = mapField(source, row, sm, component+1, subComposite, value, i)
+ err = ms.mapField(row, component+1, subComposite, value, i)
if err != nil {
return err
}
@@ -304,26 +355,26 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
// *name
case starNameField:
// iterate over non-key/col/val-referenced struct fields and map more columns
- for _, fm := range sm.others {
+ for _, fm := range ms.sm.others {
// set value of the current composite field to the field name (possibly overriden by name:)
b, err := Marshal(fm.cassandraName, UTF8Type)
if err != nil {
return errors.New(fmt.Sprint("Error marshaling field ", fm.name, ":", err))
}
var subComposite []byte
- if sm.isCompositeColumn {
+ if ms.sm.isCompositeColumn {
subComposite = packComposite(composite, b, false, false, false)
} else {
subComposite = b
}
// marshal field value and pass it to next field mapper in case it is *value
- v := source.Field(fm.position)
+ v := ms.v.Field(fm.position)
b, err = Marshal(v.Interface(), fm.cassandraType)
if err != nil {
return errors.New(fmt.Sprint("Error marshaling field ", fm.name, ":", err))
}
- err = mapField(source, row, sm, component+1, subComposite, b, valueIndex)
+ err = ms.mapField(row, component+1, subComposite, b, valueIndex)
if err != nil {
return err
}
@@ -333,7 +384,7 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
} else {
// no components left, emit column
- fm := sm.value
+ fm := ms.sm.value
// switch type of value field
switch fm.fieldKind {
@@ -344,7 +395,7 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
case baseTypeSliceField:
// set value to the passed value index in this slice
- vs := source.Field(fm.position)
+ vs := ms.v.Field(fm.position)
v := vs.Index(valueIndex)
b, err := Marshal(v.Interface(), fm.cassandraType)
if err != nil {
@@ -354,7 +405,7 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
case baseTypeField:
// set value to the field value
- v := source.Field(fm.position)
+ v := ms.v.Field(fm.position)
b, err := Marshal(v.Interface(), fm.cassandraType)
if err != nil {
return errors.New(fmt.Sprint("Error marshaling field ", fm.name, ":", err))
@@ -371,55 +422,45 @@ func mapField(source reflect.Value, row *Row, sm *structMapping, component int,
}
func Unmap(row *Row, destination interface{}) error {
- // always work with a pointer to struct
- vp := reflect.ValueOf(destination)
- if vp.Kind() != reflect.Ptr {
- return errors.New("Passed destination is not a pointer")
- }
- if vp.IsNil() {
- return errors.New("Passed destination is a nil pointer")
- }
- v := reflect.Indirect(vp)
- if v.Kind() != reflect.Struct {
- return errors.New("Passed destination is not a pointer to a struct")
- }
- sm, err := getMapping(v)
+ // deconstruct the source struct into a reflect.Value and a (cached) struct mapping
+ ms, err := newMappedStruct(destination)
if err != nil {
return err
}
// unmarshal key
- vk := v.Field(sm.key.position)
+ vk := ms.v.Field(ms.sm.key.position)
if !vk.CanAddr() {
return errors.New("Cannot obtain pointer to key field")
}
vkp := vk.Addr()
- err = Unmarshal(row.Key, sm.key.cassandraType, vkp.Interface())
+ err = Unmarshal(row.Key, ms.sm.key.cassandraType, vkp.Interface())
if err != nil {
- return errors.New(fmt.Sprint("Error unmarshaling key field ", sm.key.name, ":", err))
+ return errors.New(fmt.Sprint("Error unmarshaling key field ", ms.sm.key.name, ":", err))
}
// unmarshal col/values
+
setField := func(fm *fieldMapping, b []byte, index int) error {
- vfield := v.Field(fm.position)
+ vfield := ms.v.Field(fm.position)
if index >= 0 {
vfield = vfield.Index(index)
}
if !vfield.CanAddr() {
- return errors.New(fmt.Sprint("Cannot obtain pointer to field ", vfield.Type().Name(), " in struct ", v.Type().Name()))
+ return errors.New(fmt.Sprint("Cannot obtain pointer to field ", vfield.Type().Name(), " in struct ", ms.v.Type().Name()))
}
vfieldp := vfield.Addr()
err = Unmarshal(b, fm.cassandraType, vfieldp.Interface())
if err != nil {
- return errors.New(fmt.Sprint("Error unmarshaling composite field ", vfield.Type().Name(), " in struct ", v.Type().Name(), ", error: ", err))
+ return errors.New(fmt.Sprint("Error unmarshaling composite field ", vfield.Type().Name(), " in struct ", ms.v.Type().Name(), ", error: ", err))
}
return nil
}
prepareSlice := func(fm *fieldMapping, n int) {
- vfield := v.Field(fm.position)
+ vfield := ms.v.Field(fm.position)
t := vfield.Type()
s := reflect.MakeSlice(t, n, n)
vfield.Set(s)
@@ -428,29 +469,29 @@ func Unmap(row *Row, destination interface{}) error {
rowLength := len(row.Columns)
// prepare slice components and value
- for _, fm := range sm.columns {
+ for _, fm := range ms.sm.columns {
if fm.fieldKind == baseTypeSliceField {
prepareSlice(fm, rowLength)
}
}
- if sm.value.fieldKind == baseTypeSliceField {
- prepareSlice(sm.value, rowLength)
+ if ms.sm.value.fieldKind == baseTypeSliceField {
+ prepareSlice(ms.sm.value, rowLength)
}
for i, column := range row.Columns {
var components [][]byte
- if sm.isCompositeColumn {
+ if ms.sm.isCompositeColumn {
components = unpackComposite(column.Name)
} else {
components = [][]byte{column.Name}
}
- if len(components) != len(sm.columns) {
- return errors.New(fmt.Sprint("Returned number of components in composite column name does not match struct col: component in struct ", v.Type().Name()))
+ if len(components) != len(ms.sm.columns) {
+ return errors.New(fmt.Sprint("Returned number of components in composite column name does not match struct col: component in struct ", ms.v.Type().Name()))
}
// iterate over column name components and set them, plus values
for j, b := range components {
- fm := sm.columns[j]
+ fm := ms.sm.columns[j]
switch fm.fieldKind {
case baseTypeField:
@@ -462,9 +503,9 @@ func Unmap(row *Row, destination interface{}) error {
var name string
err = Unmarshal(b, UTF8Type, &name)
if err != nil {
- return errors.New(fmt.Sprint("Error unmarshaling composite field as UTF8Type for *name in struct ", v.Type().Name(), ", error: ", err))
+ return errors.New(fmt.Sprint("Error unmarshaling composite field as UTF8Type for *name in struct ", ms.v.Type().Name(), ", error: ", err))
}
- if valueFM, found := sm.others[name]; found {
+ if valueFM, found := ms.sm.others[name]; found {
if err = setField(valueFM, column.Value, -1); err != nil {
return err
}
@@ -478,16 +519,16 @@ func Unmap(row *Row, destination interface{}) error {
}
// set value field for the non-*name cases
- if sm.value != nil {
- switch sm.value.fieldKind {
+ if ms.sm.value != nil {
+ switch ms.sm.value.fieldKind {
case baseTypeField:
- if err = setField(sm.value, column.Value, -1); err != nil {
+ if err = setField(ms.sm.value, column.Value, -1); err != nil {
return err
}
case baseTypeSliceField:
- if err = setField(sm.value, column.Value, i); err != nil {
+ if err = setField(ms.sm.value, column.Value, i); err != nil {
return err
}
}
View
14 src/gossie/struct_test.go
@@ -9,9 +9,9 @@ import (
todo:
- much more testing on struct mapping
+ more testing on struct mapping, more cases, more automation
- more test for name: and type:
+ more tests for name: and type:
*/
@@ -153,6 +153,8 @@ func TestStructMapping(t *testing.T) {
"C": &fieldMapping{fieldKind: baseTypeField, position: 2, name: "C", cassandraType: AsciiType, cassandraName: "C"},
},
isCompositeColumn: false,
+ isSliceColumn: false,
+ isStarNameColumn: true,
}
checkMapping(t, goodB, mapB, "mapB")
@@ -169,6 +171,8 @@ func TestStructMapping(t *testing.T) {
"C": &fieldMapping{fieldKind: baseTypeField, position: 2, name: "C", cassandraType: LongType, cassandraName: "C"},
},
isCompositeColumn: true,
+ isSliceColumn: false,
+ isStarNameColumn: true,
}
checkMapping(t, goodC, mapC, "mapC")
@@ -182,6 +186,8 @@ func TestStructMapping(t *testing.T) {
value: &fieldMapping{fieldKind: baseTypeSliceField, position: 2, name: "C", cassandraType: LongType, cassandraName: "C"},
others: make(map[string]*fieldMapping, 0),
isCompositeColumn: false,
+ isSliceColumn: true,
+ isStarNameColumn: false,
}
checkMapping(t, goodD, mapD, "mapD")
@@ -196,6 +202,8 @@ func TestStructMapping(t *testing.T) {
value: &fieldMapping{fieldKind: baseTypeSliceField, position: 3, name: "D", cassandraType: LongType, cassandraName: "D"},
others: make(map[string]*fieldMapping, 0),
isCompositeColumn: true,
+ isSliceColumn: true,
+ isStarNameColumn: false,
}
checkMapping(t, goodE, mapE, "mapE")
@@ -223,6 +231,8 @@ func TestStructMapping(t *testing.T) {
"Val": &fieldMapping{fieldKind: baseTypeField, position: 12, name: "Val", cassandraType: UTF8Type, cassandraName: "Val"},
},
isCompositeColumn: true,
+ isSliceColumn: false,
+ isStarNameColumn: true,
}
checkMapping(t, goodEComp, eComp, "eComp")
Please sign in to comment.
Something went wrong with that request. Please try again.