Skip to content

Commit

Permalink
Merge 'schema: JSON marshalling of schema fixed' from Henrik
Browse files Browse the repository at this point in the history
The schema input file has changed to ensure marshalling of lists
and sets. These types now have a kind property with possible
values (list,set). The reason for this was that it was impossible
to resolve the input JSON for these types otherwise.

Fixes: #97
  • Loading branch information
penberg authored May 22, 2019
2 parents 752cf49 + 84032a3 commit 582563a
Show file tree
Hide file tree
Showing 6 changed files with 323 additions and 44 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

- JSON marshalling of Schema fixed. The schema input file has changed to
ensure marshalling of lists and sets. These types now have a _kind_
property with possible values (_list_,_set_).
- Ensure proper termination when errors happen.
- Fix mutation timestamps to match on system under test and test oracle.
- Gemini now tries to perform mutation on both systems regardless of
Expand Down
8 changes: 8 additions & 0 deletions cmd/gemini/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@
],
"frozen": false
}
},
{
"name": "col6",
"type": {
"kind": "list",
"type": "int",
"frozen": true
}
}
],
"indexes": [
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.6 // indirect
github.com/mitchellh/mapstructure v1.1.2
github.com/pkg/errors v0.8.1
github.com/scylladb/go-set v1.0.2
github.com/scylladb/gocqlx v1.3.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcncea
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA=
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
Expand Down
245 changes: 207 additions & 38 deletions types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gemini

import (
"encoding/hex"
"encoding/json"
"fmt"
"math/big"
"math/rand"
Expand All @@ -11,6 +12,8 @@ import (
"time"

"github.com/gocql/gocql"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"gopkg.in/inf.v0"
)

Expand Down Expand Up @@ -365,30 +368,31 @@ func (tt UDTType) GenValueRange(p *PartitionRange) ([]interface{}, []interface{}
return []interface{}{left}, []interface{}{right}
}

type SetType struct {
type BagType struct {
Kind string `json:"kind"` // We need to differentiate between sets and lists
Type SimpleType `json:"type"`
Frozen bool `json:"frozen"`
}

func (ct SetType) Name() string {
func (ct BagType) Name() string {
if ct.Frozen {
return "frozen<set<" + ct.Type.Name() + ">>"
return "frozen<" + ct.Kind + "<" + ct.Type.Name() + ">>"
}
return "set<" + ct.Type.Name() + ">"
return ct.Kind + "<" + ct.Type.Name() + ">"
}

func (ct SetType) CQLDef() string {
func (ct BagType) CQLDef() string {
if ct.Frozen {
return "frozen<set<" + ct.Type.Name() + ">>"
return "frozen<" + ct.Kind + "<" + ct.Type.Name() + ">>"
}
return "set<" + ct.Type.Name() + ">"
return ct.Kind + "<" + ct.Type.Name() + ">"
}

func (ct SetType) CQLHolder() string {
func (ct BagType) CQLHolder() string {
return "?"
}

func (ct SetType) CQLPretty(query string, value []interface{}) (string, int) {
func (ct BagType) CQLPretty(query string, value []interface{}) (string, int) {
if len(value) == 0 {
return query, 0
}
Expand All @@ -407,7 +411,7 @@ func (ct SetType) CQLPretty(query string, value []interface{}) (string, int) {
panic(fmt.Sprintf("set cql pretty, unknown type %v", ct))
}

func (ct SetType) GenValue(p *PartitionRange) []interface{} {
func (ct BagType) GenValue(p *PartitionRange) []interface{} {
count := p.Rand.Intn(9) + 1
vals := make([]interface{}, count, count)
for i := 0; i < count; i++ {
Expand All @@ -416,7 +420,7 @@ func (ct SetType) GenValue(p *PartitionRange) []interface{} {
return []interface{}{vals}
}

func (ct SetType) GenValueRange(p *PartitionRange) ([]interface{}, []interface{}) {
func (ct BagType) GenValueRange(p *PartitionRange) ([]interface{}, []interface{}) {
count := p.Rand.Intn(9) + 1
left := make([]interface{}, 0, len(ct.Type))
right := make([]interface{}, 0, len(ct.Type))
Expand All @@ -428,28 +432,10 @@ func (ct SetType) GenValueRange(p *PartitionRange) ([]interface{}, []interface{}
return []interface{}{left}, []interface{}{right}
}

func (ct SetType) Indexable() bool {
func (ct BagType) Indexable() bool {
return false
}

type ListType struct {
SetType
}

func (lt ListType) Name() string {
if lt.Frozen {
return "frozen<list<" + lt.Type.Name() + ">>"
}
return "list<" + lt.Type.Name() + ">"
}

func (lt ListType) CQLDef() string {
if lt.Frozen {
return "frozen<list<" + lt.Type.Name() + ">>"
}
return "list<" + lt.Type.Name() + ">"
}

type MapType struct {
KeyType SimpleType `json:"key_type"`
ValueType SimpleType `json:"value_type"`
Expand Down Expand Up @@ -572,26 +558,29 @@ func genUDTType() UDTType {
}
}

func genSetType() SetType {
func genSetType() BagType {
return genBagType("set")
}

func genListType() BagType {
return genBagType("list")
}

func genBagType(kind string) BagType {
var t SimpleType
for {
t = genSimpleType()
if t != TYPE_DURATION {
break
}
}
return SetType{
return BagType{
Kind: kind,
Type: t,
Frozen: rand.Uint32()%2 == 0,
}
}

func genListType() ListType {
return ListType{
SetType: genSetType(),
}
}

func genMapType() MapType {
var t SimpleType
for {
Expand All @@ -615,3 +604,183 @@ func genPrimaryKeyColumnType() Type {
func genIndexName(prefix string, idx int) string {
return fmt.Sprintf("%s_idx", genColumnName(prefix, idx))
}

// JSON Marshalling

func (cd *ColumnDef) UnmarshalJSON(data []byte) error {
dataMap := make(map[string]interface{})
if err := json.Unmarshal(data, &dataMap); err != nil {
return err
}

t, err := getSimpleTypeColumn(dataMap)
if err != nil {
t, err = getUDTTypeColumn(dataMap)
if err != nil {
t, err = getTupleTypeColumn(dataMap)
if err != nil {
t, err = getMapTypeColumn(dataMap)
if err != nil {
t, err = getBagTypeColumn(dataMap)
if err != nil {
return err
}
}
}
}
}
*cd = ColumnDef{
Name: t.Name,
Type: t.Type,
}
return nil
}

func getMapTypeColumn(data map[string]interface{}) (ColumnDef, error) {
st := struct {
Name string
Type map[string]interface{}
}{}
err := mapstructure.Decode(data, &st)

if _, ok := st.Type["frozen"]; !ok {
return ColumnDef{}, errors.Errorf("not a map type, value=%v", st)
}

if _, ok := st.Type["value_type"]; !ok {
return ColumnDef{}, errors.Errorf("not a map type, value=%v", st)
}

if _, ok := st.Type["key_type"]; !ok {
return ColumnDef{}, errors.Errorf("not a map type, value=%v", st)
}

var frozen bool
if err := mapstructure.Decode(st.Type["frozen"], &frozen); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode bool value for MapType::Frozen, value=%v", st)
}
var valueType SimpleType
if err := mapstructure.Decode(st.Type["value_type"], &valueType); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode SimpleType value for MapType::ValueType, value=%v", st)
}
var keyType SimpleType
if err := mapstructure.Decode(st.Type["key_type"], &keyType); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode bool value for MapType::KeyType, value=%v", st)
}
return ColumnDef{
Name: st.Name,
Type: MapType{
Frozen: frozen,
ValueType: valueType,
KeyType: keyType,
},
}, err
}

func getBagTypeColumn(data map[string]interface{}) (ColumnDef, error) {
st := struct {
Name string
Type map[string]interface{}
}{}
err := mapstructure.Decode(data, &st)

var kind string
if err := mapstructure.Decode(st.Type["kind"], &kind); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode string value for BagType::Frozen, value=%v", st)
}
var frozen bool
if err := mapstructure.Decode(st.Type["frozen"], &frozen); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode bool value for BagType::Frozen, value=%v", st)
}
var typ SimpleType
if err := mapstructure.Decode(st.Type["type"], &typ); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode SimpleType value for BagType::ValueType, value=%v", st)
}
return ColumnDef{
Name: st.Name,
Type: BagType{
Kind: kind,
Frozen: frozen,
Type: typ,
},
}, err
}

func getTupleTypeColumn(data map[string]interface{}) (ColumnDef, error) {
st := struct {
Name string
Type map[string]interface{}
}{}
err := mapstructure.Decode(data, &st)

if _, ok := st.Type["types"]; !ok {
return ColumnDef{}, errors.Errorf("not a tuple type, value=%v", st)
}

var types []SimpleType
if err := mapstructure.Decode(st.Type["types"], &types); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode []SimpleType value for TupleType::Types, value=%v", st)
}
var frozen bool
if err := mapstructure.Decode(st.Type["frozen"], &frozen); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode bool value for TupleType::Types, value=%v", st)
}
return ColumnDef{
Name: st.Name,
Type: TupleType{
Types: types,
Frozen: frozen,
},
}, err
}

func getUDTTypeColumn(data map[string]interface{}) (ColumnDef, error) {
st := struct {
Name string
Type map[string]interface{}
}{}
err := mapstructure.Decode(data, &st)

if _, ok := st.Type["types"]; !ok {
return ColumnDef{}, errors.Errorf("not a UDT type, value=%v", st)
}
if _, ok := st.Type["type_name"]; !ok {
return ColumnDef{}, errors.Errorf("not a UDT type, value=%v", st)
}

var types map[string]SimpleType
if err := mapstructure.Decode(st.Type["types"], &types); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode []SimpleType value for UDTType::Types, value=%v", st)
}
var frozen bool
if err := mapstructure.Decode(st.Type["frozen"], &frozen); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode bool value for UDTType::Frozen, value=%v", st)
}
var typeName string
if err := mapstructure.Decode(st.Type["type_name"], &typeName); err != nil {
return ColumnDef{}, errors.Wrapf(err, "can't decode string value for UDTType::TypeName, value=%v", st)
}
return ColumnDef{
Name: st.Name,
Type: UDTType{
Types: types,
TypeName: typeName,
Frozen: frozen,
},
}, err
}

func getSimpleTypeColumn(data map[string]interface{}) (ColumnDef, error) {
st := struct {
Name string
Type SimpleType
}{}
err := mapstructure.Decode(data, &st)
if err != nil {
return ColumnDef{}, err
}
return ColumnDef{
Name: st.Name,
Type: st.Type,
}, err
}
Loading

0 comments on commit 582563a

Please sign in to comment.