Replace Unsafe with Strict mechanism
Previously by default the presence of a missing field in a udt would result in an error reported. The Unsafe mechanism could be used to ignore these fields. This PR changes the default behavior to ignoring missing fields and only reporting an error if Strict mode is used. This approach is in line with the gocql.
This commit is contained in:
committed by
Sylwia Szunejko
parent
6a60650668
commit
7072863b0c
@@ -345,8 +345,8 @@ func basicReadScyllaVersion(t *testing.T, session gocqlx.Session) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This examples shows how to bind data from a map using "BindMap" function,
|
// This examples shows how to bind data from a map using "BindMap" function,
|
||||||
// override field name mapping using the "db" tags, and use "Unsafe" function
|
// override field name mapping using the "db" tags, with the default mechanism of
|
||||||
// to handle situations where driver returns more coluns that we are ready to
|
// handling situations where driver returns more coluns that we are ready to
|
||||||
// consume.
|
// consume.
|
||||||
func datatypesBlob(t *testing.T, session gocqlx.Session) {
|
func datatypesBlob(t *testing.T, session gocqlx.Session) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@@ -384,9 +384,8 @@ func datatypesBlob(t *testing.T, session gocqlx.Session) {
|
|||||||
}{}
|
}{}
|
||||||
q := qb.Select("examples.blobs").Where(qb.EqLit("k", "1")).Query(session)
|
q := qb.Select("examples.blobs").Where(qb.EqLit("k", "1")).Query(session)
|
||||||
|
|
||||||
// Unsafe is used here to override validation error that check if all
|
// By default missing UDT fields are treated as null instead of failing
|
||||||
// requested columns are consumed `failed: missing destination name "k" in struct` error
|
if err := q.Iter().Get(row); err != nil {
|
||||||
if err := q.Iter().Unsafe().Get(row); err != nil {
|
|
||||||
t.Fatal("Get() failed:", err)
|
t.Fatal("Get() failed:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
28
iterx.go
28
iterx.go
@@ -13,9 +13,9 @@ import (
|
|||||||
"github.com/scylladb/go-reflectx"
|
"github.com/scylladb/go-reflectx"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultUnsafe enables the behavior of forcing queries and iterators to ignore
|
// DefaultStrict disables the behavior of forcing queries and iterators to ignore
|
||||||
// missing fields for all queries. See Unsafe below for more information.
|
// missing fields for all queries. See Strict below for more information.
|
||||||
var DefaultUnsafe bool
|
var DefaultStrict bool
|
||||||
|
|
||||||
// Iterx is a wrapper around gocql.Iter which adds struct scanning capabilities.
|
// Iterx is a wrapper around gocql.Iter which adds struct scanning capabilities.
|
||||||
type Iterx struct {
|
type Iterx struct {
|
||||||
@@ -26,16 +26,16 @@ type Iterx struct {
|
|||||||
// Cache memory for a rows during iteration in structScan.
|
// Cache memory for a rows during iteration in structScan.
|
||||||
fields [][]int
|
fields [][]int
|
||||||
values []interface{}
|
values []interface{}
|
||||||
unsafe bool
|
strict bool
|
||||||
structOnly bool
|
structOnly bool
|
||||||
applied bool
|
applied bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe forces the iterator to ignore missing fields. By default when scanning
|
// Strict forces the iterator to disable ignoring missing fields. In Strict mode
|
||||||
// a struct if result row has a column that cannot be mapped to any destination
|
// when scanning a struct if result row has a column that cannot be mapped to any
|
||||||
// field an error is reported. With unsafe such columns are ignored.
|
// destination field an error is reported. By default such columns are ignored.
|
||||||
func (iter *Iterx) Unsafe() *Iterx {
|
func (iter *Iterx) Strict() *Iterx {
|
||||||
iter.unsafe = true
|
iter.strict = true
|
||||||
return iter
|
return iter
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ func (iter *Iterx) scan(value reflect.Value) bool {
|
|||||||
if value.Kind() != reflect.Ptr {
|
if value.Kind() != reflect.Ptr {
|
||||||
panic("value must be a pointer")
|
panic("value must be a pointer")
|
||||||
}
|
}
|
||||||
return iter.Iter.Scan(udtWrapValue(value, iter.Mapper, iter.unsafe))
|
return iter.Iter.Scan(udtWrapValue(value, iter.Mapper, iter.strict))
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructScan is like gocql.Iter.Scan, but scans a single row into a single
|
// StructScan is like gocql.Iter.Scan, but scans a single row into a single
|
||||||
@@ -264,8 +264,8 @@ func (iter *Iterx) structScan(value reflect.Value) bool {
|
|||||||
cas := len(columns) > 0 && columns[0] == appliedColumn
|
cas := len(columns) > 0 && columns[0] == appliedColumn
|
||||||
|
|
||||||
iter.fields = iter.Mapper.TraversalsByName(value.Type(), columns)
|
iter.fields = iter.Mapper.TraversalsByName(value.Type(), columns)
|
||||||
// if we are not unsafe and it's not CAS query and are missing fields, return an error
|
// if we are strict and it's not CAS query and are missing fields, return an error
|
||||||
if !iter.unsafe && !cas {
|
if iter.strict && !cas {
|
||||||
if f, err := missingFields(iter.fields); err != nil {
|
if f, err := missingFields(iter.fields); err != nil {
|
||||||
iter.err = fmt.Errorf("missing destination name %q in %s", columns[f], reflect.Indirect(value).Type())
|
iter.err = fmt.Errorf("missing destination name %q in %s", columns[f], reflect.Indirect(value).Type())
|
||||||
return false
|
return false
|
||||||
@@ -302,7 +302,7 @@ func (iter *Iterx) fieldsByTraversal(value reflect.Value, traversals [][]int, va
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
f := reflectx.FieldByIndexes(value, traversal).Addr()
|
f := reflectx.FieldByIndexes(value, traversal).Addr()
|
||||||
values[i] = udtWrapValue(f, iter.Mapper, iter.unsafe)
|
values[i] = udtWrapValue(f, iter.Mapper, iter.strict)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -325,7 +325,7 @@ func columnNames(ci []gocql.ColumnInfo) []string {
|
|||||||
// end of the result set was reached or if an error occurred. Close should
|
// end of the result set was reached or if an error occurred. Close should
|
||||||
// be called afterwards to retrieve any potential errors.
|
// be called afterwards to retrieve any potential errors.
|
||||||
func (iter *Iterx) Scan(dest ...interface{}) bool {
|
func (iter *Iterx) Scan(dest ...interface{}) bool {
|
||||||
return iter.Iter.Scan(udtWrapSlice(iter.Mapper, iter.unsafe, dest)...)
|
return iter.Iter.Scan(udtWrapSlice(iter.Mapper, iter.strict, dest)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the iterator and returns any errors that happened during
|
// Close closes the iterator and returns any errors that happened during
|
||||||
|
|||||||
@@ -264,7 +264,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("insert-bind", func(t *testing.T) {
|
t.Run("insert-bind", func(t *testing.T) {
|
||||||
if err := session.Query(insertStmt, nil).Unsafe().Bind(
|
if err := session.Query(insertStmt, nil).Bind(
|
||||||
testuuid,
|
testuuid,
|
||||||
tc.insert,
|
tc.insert,
|
||||||
).ExecRelease(); err != nil {
|
).ExecRelease(); err != nil {
|
||||||
@@ -273,7 +273,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
|
|
||||||
// Make sure the UDT was inserted correctly
|
// Make sure the UDT was inserted correctly
|
||||||
v := FullUDT{}
|
v := FullUDT{}
|
||||||
if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Unsafe().Bind(testuuid).Get(&v); err != nil {
|
if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(&v); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
diff(t, tc.expectedOnDB, v)
|
diff(t, tc.expectedOnDB, v)
|
||||||
@@ -281,7 +281,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("scan", func(t *testing.T) {
|
t.Run("scan", func(t *testing.T) {
|
||||||
v := reflect.New(reflect.TypeOf(tc.expected)).Interface()
|
v := reflect.New(reflect.TypeOf(tc.expected)).Interface()
|
||||||
if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Unsafe().Bind(testuuid).Scan(v); err != nil {
|
if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Scan(v); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
diff(t, tc.expected, reflect.ValueOf(v).Elem().Interface())
|
diff(t, tc.expected, reflect.ValueOf(v).Elem().Interface())
|
||||||
@@ -289,7 +289,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("get", func(t *testing.T) {
|
t.Run("get", func(t *testing.T) {
|
||||||
v := reflect.New(reflect.TypeOf(tc.expected)).Interface()
|
v := reflect.New(reflect.TypeOf(tc.expected)).Interface()
|
||||||
if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Unsafe().Bind(testuuid).Get(v); err != nil {
|
if err := session.Query(`SELECT testudt FROM udt_table where testuuid = ?`, nil).Bind(testuuid).Get(v); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
diff(t, tc.expected, reflect.ValueOf(v).Elem().Interface())
|
diff(t, tc.expected, reflect.ValueOf(v).Elem().Interface())
|
||||||
@@ -305,7 +305,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("insert-bind-struct", func(t *testing.T) {
|
t.Run("insert-bind-struct", func(t *testing.T) {
|
||||||
b := makeStruct(testuuid, tc.insert)
|
b := makeStruct(testuuid, tc.insert)
|
||||||
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).Unsafe().BindStruct(b).ExecRelease(); err != nil {
|
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).BindStruct(b).ExecRelease(); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,7 +320,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
t.Run("insert-bind-struct-map", func(t *testing.T) {
|
t.Run("insert-bind-struct-map", func(t *testing.T) {
|
||||||
t.Run("empty-map", func(t *testing.T) {
|
t.Run("empty-map", func(t *testing.T) {
|
||||||
b := makeStruct(testuuid, tc.insert)
|
b := makeStruct(testuuid, tc.insert)
|
||||||
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).Unsafe().
|
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).
|
||||||
BindStructMap(b, nil).ExecRelease(); err != nil {
|
BindStructMap(b, nil).ExecRelease(); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
@@ -334,7 +334,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("empty-struct", func(t *testing.T) {
|
t.Run("empty-struct", func(t *testing.T) {
|
||||||
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).Unsafe().
|
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).
|
||||||
BindStructMap(struct{}{}, map[string]interface{}{
|
BindStructMap(struct{}{}, map[string]interface{}{
|
||||||
"test_uuid": testuuid,
|
"test_uuid": testuuid,
|
||||||
"test_udt": tc.insert,
|
"test_udt": tc.insert,
|
||||||
@@ -352,7 +352,7 @@ func TestIterxUDT(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("insert-bind-map", func(t *testing.T) {
|
t.Run("insert-bind-map", func(t *testing.T) {
|
||||||
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).Unsafe().
|
if err := session.Query(insertStmt, []string{"test_uuid", "test_udt"}).
|
||||||
BindMap(map[string]interface{}{
|
BindMap(map[string]interface{}{
|
||||||
"test_uuid": testuuid,
|
"test_uuid": testuuid,
|
||||||
"test_udt": tc.insert,
|
"test_udt": tc.insert,
|
||||||
@@ -736,41 +736,41 @@ func TestIterxStructOnlyUDT(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIterxUnsafe(t *testing.T) {
|
func TestIterxStrict(t *testing.T) {
|
||||||
session := gocqlxtest.CreateSession(t)
|
session := gocqlxtest.CreateSession(t)
|
||||||
defer session.Close()
|
defer session.Close()
|
||||||
|
|
||||||
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.unsafe_table (testtext text PRIMARY KEY, testtextunbound text)`); err != nil {
|
if err := session.ExecStmt(`CREATE TABLE gocqlx_test.strict_table (testtext text PRIMARY KEY, testtextunbound text)`); err != nil {
|
||||||
t.Fatal("create table:", err)
|
t.Fatal("create table:", err)
|
||||||
}
|
}
|
||||||
if err := session.Query(`INSERT INTO unsafe_table (testtext, testtextunbound) values (?, ?)`, nil).Bind("test", "test").Exec(); err != nil {
|
if err := session.Query(`INSERT INTO strict_table (testtext, testtextunbound) values (?, ?)`, nil).Bind("test", "test").Exec(); err != nil {
|
||||||
t.Fatal("insert:", err)
|
t.Fatal("insert:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UnsafeTable struct {
|
type StrictTable struct {
|
||||||
Testtext string
|
Testtext string
|
||||||
}
|
}
|
||||||
|
|
||||||
m := UnsafeTable{
|
m := StrictTable{
|
||||||
Testtext: "test",
|
Testtext: "test",
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
stmt = `SELECT * FROM unsafe_table`
|
stmt = `SELECT * FROM strict_table`
|
||||||
golden = "missing destination name \"testtextunbound\" in gocqlx_test.UnsafeTable"
|
golden = "missing destination name \"testtextunbound\" in gocqlx_test.StrictTable"
|
||||||
)
|
)
|
||||||
|
|
||||||
t.Run("get", func(t *testing.T) {
|
t.Run("get strict", func(t *testing.T) {
|
||||||
var v UnsafeTable
|
var v StrictTable
|
||||||
err := session.Query(stmt, nil).Get(&v)
|
err := session.Query(stmt, nil).Strict().Get(&v)
|
||||||
if err == nil || !strings.HasPrefix(err.Error(), golden) {
|
if err == nil || !strings.HasPrefix(err.Error(), golden) {
|
||||||
t.Fatalf("Get() error=%q expected %s", err, golden)
|
t.Fatalf("Get() error=%q expected %s", err, golden)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("select", func(t *testing.T) {
|
t.Run("select strict", func(t *testing.T) {
|
||||||
var v []UnsafeTable
|
var v []StrictTable
|
||||||
err := session.Query(stmt, nil).Select(&v)
|
err := session.Query(stmt, nil).Strict().Select(&v)
|
||||||
if err == nil || !strings.HasPrefix(err.Error(), golden) {
|
if err == nil || !strings.HasPrefix(err.Error(), golden) {
|
||||||
t.Fatalf("Select() error=%q expected %s", err, golden)
|
t.Fatalf("Select() error=%q expected %s", err, golden)
|
||||||
}
|
}
|
||||||
@@ -779,9 +779,9 @@ func TestIterxUnsafe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("get unsafe", func(t *testing.T) {
|
t.Run("get", func(t *testing.T) {
|
||||||
var v UnsafeTable
|
var v StrictTable
|
||||||
err := session.Query(stmt, nil).Iter().Unsafe().Get(&v)
|
err := session.Query(stmt, nil).Get(&v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Get() failed:", err)
|
t.Fatal("Get() failed:", err)
|
||||||
}
|
}
|
||||||
@@ -790,9 +790,9 @@ func TestIterxUnsafe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("select unsafe", func(t *testing.T) {
|
t.Run("select", func(t *testing.T) {
|
||||||
var v []UnsafeTable
|
var v []StrictTable
|
||||||
err := session.Query(stmt, nil).Iter().Unsafe().Select(&v)
|
err := session.Query(stmt, nil).Select(&v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Select() failed:", err)
|
t.Fatal("Select() failed:", err)
|
||||||
}
|
}
|
||||||
@@ -804,9 +804,9 @@ func TestIterxUnsafe(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("select default unsafe", func(t *testing.T) {
|
t.Run("select default", func(t *testing.T) {
|
||||||
var v []UnsafeTable
|
var v []StrictTable
|
||||||
err := session.Query(stmt, nil).Unsafe().Iter().Select(&v)
|
err := session.Query(stmt, nil).Iter().Select(&v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Select() failed:", err)
|
t.Fatal("Select() failed:", err)
|
||||||
}
|
}
|
||||||
|
|||||||
20
queryx.go
20
queryx.go
@@ -95,7 +95,7 @@ type Queryx struct {
|
|||||||
Mapper *reflectx.Mapper
|
Mapper *reflectx.Mapper
|
||||||
*gocql.Query
|
*gocql.Query
|
||||||
Names []string
|
Names []string
|
||||||
unsafe bool
|
strict bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query creates a new Queryx from gocql.Query using a default mapper.
|
// Query creates a new Queryx from gocql.Query using a default mapper.
|
||||||
@@ -107,7 +107,7 @@ func Query(q *gocql.Query, names []string) *Queryx {
|
|||||||
Names: names,
|
Names: names,
|
||||||
Mapper: DefaultMapper,
|
Mapper: DefaultMapper,
|
||||||
tr: DefaultBindTransformer,
|
tr: DefaultBindTransformer,
|
||||||
unsafe: DefaultUnsafe,
|
strict: DefaultStrict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ func (q *Queryx) bindMapArgs(arg map[string]interface{}) ([]interface{}, error)
|
|||||||
// Bind sets query arguments of query. This can also be used to rebind new query arguments
|
// Bind sets query arguments of query. This can also be used to rebind new query arguments
|
||||||
// to an existing query instance.
|
// to an existing query instance.
|
||||||
func (q *Queryx) Bind(v ...interface{}) *Queryx {
|
func (q *Queryx) Bind(v ...interface{}) *Queryx {
|
||||||
q.Query.Bind(udtWrapSlice(q.Mapper, q.unsafe, v)...)
|
q.Query.Bind(udtWrapSlice(q.Mapper, q.strict, v)...)
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ func (q *Queryx) Bind(v ...interface{}) *Queryx {
|
|||||||
// row into the values pointed at by dest and discards the rest. If no rows
|
// row into the values pointed at by dest and discards the rest. If no rows
|
||||||
// were selected, ErrNotFound is returned.
|
// were selected, ErrNotFound is returned.
|
||||||
func (q *Queryx) Scan(v ...interface{}) error {
|
func (q *Queryx) Scan(v ...interface{}) error {
|
||||||
return q.Query.Scan(udtWrapSlice(q.Mapper, q.unsafe, v)...)
|
return q.Query.Scan(udtWrapSlice(q.Mapper, q.strict, v)...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Err returns any binding errors.
|
// Err returns any binding errors.
|
||||||
@@ -351,14 +351,14 @@ func (q *Queryx) Iter() *Iterx {
|
|||||||
return &Iterx{
|
return &Iterx{
|
||||||
Iter: q.Query.Iter(),
|
Iter: q.Query.Iter(),
|
||||||
Mapper: q.Mapper,
|
Mapper: q.Mapper,
|
||||||
unsafe: q.unsafe,
|
strict: q.strict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsafe forces the query and iterators to ignore missing fields. By default when scanning
|
// Strict forces the query and iterators to report an error if there are missing fields.
|
||||||
// a struct if result row has a column that cannot be mapped to any destination
|
// By default when scanning a struct if result row has a column that cannot be mapped to
|
||||||
// field an error is reported. With unsafe such columns are ignored.
|
// any destination it is ignored. With strict error is reported.
|
||||||
func (q *Queryx) Unsafe() *Queryx {
|
func (q *Queryx) Strict() *Queryx {
|
||||||
q.unsafe = true
|
q.strict = true
|
||||||
return q
|
return q
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (s Session) ContextQuery(ctx context.Context, stmt string, names []string)
|
|||||||
Names: names,
|
Names: names,
|
||||||
Mapper: s.Mapper,
|
Mapper: s.Mapper,
|
||||||
tr: DefaultBindTransformer,
|
tr: DefaultBindTransformer,
|
||||||
unsafe: DefaultUnsafe,
|
strict: DefaultStrict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ func (s Session) Query(stmt string, names []string) *Queryx {
|
|||||||
Names: names,
|
Names: names,
|
||||||
Mapper: s.Mapper,
|
Mapper: s.Mapper,
|
||||||
tr: DefaultBindTransformer,
|
tr: DefaultBindTransformer,
|
||||||
unsafe: DefaultUnsafe,
|
strict: DefaultStrict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
udt.go
18
udt.go
@@ -26,14 +26,14 @@ var (
|
|||||||
type udt struct {
|
type udt struct {
|
||||||
field map[string]reflect.Value
|
field map[string]reflect.Value
|
||||||
value reflect.Value
|
value reflect.Value
|
||||||
unsafe bool
|
strict bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeUDT(value reflect.Value, mapper *reflectx.Mapper, unsafe bool) udt {
|
func makeUDT(value reflect.Value, mapper *reflectx.Mapper, strict bool) udt {
|
||||||
return udt{
|
return udt{
|
||||||
value: value,
|
value: value,
|
||||||
field: mapper.FieldMap(value),
|
field: mapper.FieldMap(value),
|
||||||
unsafe: unsafe,
|
strict: strict,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ func (u udt) MarshalUDT(name string, info gocql.TypeInfo) ([]byte, error) {
|
|||||||
if ok {
|
if ok {
|
||||||
return gocql.Marshal(info, value.Interface())
|
return gocql.Marshal(info, value.Interface())
|
||||||
}
|
}
|
||||||
if u.unsafe {
|
if !u.strict {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("missing name %q in %s", name, u.value.Type())
|
return nil, fmt.Errorf("missing name %q in %s", name, u.value.Type())
|
||||||
@@ -53,25 +53,25 @@ func (u udt) UnmarshalUDT(name string, info gocql.TypeInfo, data []byte) error {
|
|||||||
if ok {
|
if ok {
|
||||||
return gocql.Unmarshal(info, data, value.Addr().Interface())
|
return gocql.Unmarshal(info, data, value.Addr().Interface())
|
||||||
}
|
}
|
||||||
if u.unsafe {
|
if !u.strict {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("missing name %q in %s", name, u.value.Type())
|
return fmt.Errorf("missing name %q in %s", name, u.value.Type())
|
||||||
}
|
}
|
||||||
|
|
||||||
// udtWrapValue adds UDT wrapper if needed.
|
// udtWrapValue adds UDT wrapper if needed.
|
||||||
func udtWrapValue(value reflect.Value, mapper *reflectx.Mapper, unsafe bool) interface{} {
|
func udtWrapValue(value reflect.Value, mapper *reflectx.Mapper, strict bool) interface{} {
|
||||||
if value.Type().Implements(autoUDTInterface) {
|
if value.Type().Implements(autoUDTInterface) {
|
||||||
return makeUDT(value, mapper, unsafe)
|
return makeUDT(value, mapper, strict)
|
||||||
}
|
}
|
||||||
return value.Interface()
|
return value.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
// udtWrapSlice adds UDT wrapper if needed.
|
// udtWrapSlice adds UDT wrapper if needed.
|
||||||
func udtWrapSlice(mapper *reflectx.Mapper, unsafe bool, v []interface{}) []interface{} {
|
func udtWrapSlice(mapper *reflectx.Mapper, strict bool, v []interface{}) []interface{} {
|
||||||
for i := range v {
|
for i := range v {
|
||||||
if _, ok := v[i].(UDT); ok {
|
if _, ok := v[i].(UDT); ok {
|
||||||
v[i] = makeUDT(reflect.ValueOf(v[i]), mapper, unsafe)
|
v[i] = makeUDT(reflect.ValueOf(v[i]), mapper, strict)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
|
|||||||
Reference in New Issue
Block a user