Skip to content

Commit

Permalink
fix: driver.Valuer method was being ignored (#289)
Browse files Browse the repository at this point in the history
When a type had implemented custom Value func to convert the type,
then the conversion method was not being called for structs.

Fixes #281
  • Loading branch information
egonelbre authored Aug 29, 2024
1 parent 698932d commit 78fb05d
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 4 deletions.
12 changes: 8 additions & 4 deletions driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -748,13 +748,11 @@ func (c *conn) IsValid() bool {
return !c.closed
}

// checkIsValidType returns true for types that do not need extra conversion
// for spanner.
func checkIsValidType(v driver.Value) bool {
switch v.(type) {
default:
// google-cloud-go/spanner knows how to deal with these
if isStructOrArrayOfStructValue(v) || isAnArrayOfProtoColumn(v) {
return true
}
return false
case nil:
case sql.NullInt64:
Expand Down Expand Up @@ -851,6 +849,12 @@ func (c *conn) CheckNamedValue(value *driver.NamedValue) error {
return nil
}
}

// google-cloud-go/spanner knows how to deal with these
if isStructOrArrayOfStructValue(value.Value) || isAnArrayOfProtoColumn(value.Value) {
return nil
}

return spanner.ToSpannerError(status.Errorf(codes.InvalidArgument, "unsupported value type: %T", value.Value))
}

Expand Down
49 changes: 49 additions & 0 deletions driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -467,3 +467,52 @@ func TestConn_GetCommitTimestampAfterAutocommitQuery(t *testing.T) {
t.Fatalf("error code mismatch\n Got: %v\nWant: %v", g, w)
}
}

func TestConn_CheckNamedValue(t *testing.T) {
c := &conn{}

type Person struct {
Name string
Age int64
}

tests := []struct {
in any
want any
}{
// basic types should stay unchanged
{in: int64(256), want: int64(256)},
// driver.Valuer types should call .Value func
{in: &ValuerPerson{Name: "hello", Age: 123}, want: "hello"},
// structs should be sent to spanner
{in: &Person{Name: "hello", Age: 123}, want: &Person{Name: "hello", Age: 123}},
}

for _, test := range tests {
value := &driver.NamedValue{
Ordinal: 1,
Value: test.in,
}

err := c.CheckNamedValue(value)
if err != nil {
t.Errorf("expected no error, got: %v", err)
continue
}

if diff := cmp.Diff(test.want, value.Value); diff != "" {
t.Errorf("wrong result, got %#v expected %#v:\n%v", value.Value, test.want, diff)
}
}
}

// ValuerPerson implements driver.Valuer
type ValuerPerson struct {
Name string
Age int64
}

// Value implements conversion func for database.
func (p *ValuerPerson) Value() (driver.Value, error) {
return p.Name, nil
}

0 comments on commit 78fb05d

Please sign in to comment.