Automated UDT support

This patch adds the power of GocqlX to UDTs.
Now you can make a struct be UDT compatible by adding a single line.

```
type FullName struct {
	gocqlx.UDT
	FirstName string
	LastName  string
}
```

Signed-off-by: Michał Matczuk <michal@scylladb.com>
This commit is contained in:
Michał Matczuk
2020-04-15 17:06:29 +02:00
committed by Michal Jan Matczuk
parent 2569c3dd8f
commit ab279e68ed
8 changed files with 284 additions and 86 deletions

View File

@@ -28,6 +28,10 @@ func structOnlyError(t reflect.Type) error {
return fmt.Errorf("expected a struct but the provided struct type %s implements gocql.UDTUnmarshaler", t.Name())
}
if isAutoUDT := reflect.PtrTo(t).Implements(autoUDTInterface); isAutoUDT {
return fmt.Errorf("expected a struct but the provided struct type %s implements gocqlx.UDT", t.Name())
}
return fmt.Errorf("expected a struct, but struct %s has no exported fields", t.Name())
}
@@ -36,6 +40,7 @@ func structOnlyError(t reflect.Type) error {
var (
unmarshallerInterface = reflect.TypeOf((*gocql.Unmarshaler)(nil)).Elem()
udtUnmarshallerInterface = reflect.TypeOf((*gocql.UDTUnmarshaler)(nil)).Elem()
autoUDTInterface = reflect.TypeOf((*UDT)(nil)).Elem()
)
func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
@@ -46,32 +51,6 @@ func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
return t, nil
}
// fieldsByName fills a values interface with fields from the passed value based
// on the traversals in int. If ptrs is true, return addresses instead of values.
// We write this instead of using FieldsByName to save allocations and map lookups
// when iterating over many rows. Empty traversals will get an interface pointer.
// Because of the necessity of requesting ptrs or values, it's considered a bit too
// specialized for inclusion in reflectx itself.
func fieldsByTraversal(v reflect.Value, traversals [][]int, values []interface{}, ptrs bool) error {
v = reflect.Indirect(v)
if v.Kind() != reflect.Struct {
return errors.New("argument not a struct")
}
for i, traversal := range traversals {
if len(traversal) == 0 {
continue
}
f := reflectx.FieldByIndexes(v, traversal)
if ptrs {
values[i] = f.Addr().Interface()
} else {
values[i] = f.Interface()
}
}
return nil
}
func missingFields(transversals [][]int) (field int, err error) {
for i, t := range transversals {
if len(t) == 0 {