Skip to content
This repository has been archived by the owner on Feb 15, 2023. It is now read-only.

go fields: explicity support non-pointer marshalers #185

Merged
merged 2 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

- `sqlgen.Tester` now compares `driver.Value`s. ([#170](https://github.com/samsarahq/thunder/pull/170))
- Support converting the zero value of fields to NULL in the db with tag `sql:",implicitnull"`. ([#181](https://github.com/samsarahq/thunder/pull/181))
- Support non-pointer protobuf structs. ([#185](https://github.com/samsarahq/thunder/pull/185))

## [0.4.0] - 2018-09-13

Expand Down
14 changes: 14 additions & 0 deletions internal/fields/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,17 @@ type Valuer struct {
value reflect.Value
}

var marshalerType = reflect.TypeOf((*marshaler)(nil)).Elem()

func nonPointerMarshal(d *Descriptor, val reflect.Value) (reflect.Value, bool) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: add a comment here explaining exactly what this is doing

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1
Naming the return types might help too (especially the bool)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

if !d.Ptr && reflect.PtrTo(d.Type).Implements(marshalerType) {
v := reflect.New(d.Type)
v.Elem().Set(val)
return v, true
}
return val, false
}

// Value satisfies the sql/driver.Valuer interface.
// The value should be one of the following:
// int64
Expand Down Expand Up @@ -62,6 +73,9 @@ func (f Valuer) Value() (driver.Value, error) {
// }
switch {
case f.Tags.Contains("binary"):
if v, ok := nonPointerMarshal(f.Descriptor, f.value); ok {
return v.Interface().(marshaler).Marshal()
}
if iface, ok := i.(marshaler); ok {
return iface.Marshal()
}
Expand Down
39 changes: 27 additions & 12 deletions internal/fields/sql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,7 @@ func TestField_ValidateSQLType(t *testing.T) {
{In: ifaceBinaryMarshal{}, Error: true},
{In: ifaceBinaryMarshal{}, Tags: []string{"binary"}, Error: false},
{In: &ifaceBinaryMarshal{}, Tags: []string{"binary"}, Error: false},
// Non-pointer proto does not work because the Marshal() method has a pointer receiver.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love it

{In: proto.ExampleEvent{}, Tags: []string{"binary"}, Error: true},
{In: proto.ExampleEvent{}, Tags: []string{"binary"}, Error: false},
{In: &proto.ExampleEvent{}, Tags: []string{"binary"}, Error: false},
}

Expand All @@ -246,15 +245,31 @@ func TestField_ValidateSQLType(t *testing.T) {
}

func TestField_SupportsProtobuf(t *testing.T) {
event := &proto.ExampleEvent{Table: "users"}
descriptor := fields.New(reflect.TypeOf(event), []string{"binary"})
valuer := descriptor.Valuer(reflect.ValueOf(event))
b, err := valuer.Value()
assert.NoError(t, err)
t.Run("pointer", func(t *testing.T) {
event := &proto.ExampleEvent{Table: "users"}
descriptor := fields.New(reflect.TypeOf(event), []string{"binary"})
valuer := descriptor.Valuer(reflect.ValueOf(event))
b, err := valuer.Value()
assert.NoError(t, err)

got := reflect.New(reflect.TypeOf(event)).Elem()
scanner := descriptor.Scanner()
scanner.Target(got)
scanner.Scan(b)
assert.Equal(t, event, got.Interface())
})

t.Run("pointer", func(t *testing.T) {
event := proto.ExampleEvent{Table: "users"}
descriptor := fields.New(reflect.TypeOf(event), []string{"binary"})
valuer := descriptor.Valuer(reflect.ValueOf(event))
b, err := valuer.Value()
assert.NoError(t, err)

got := reflect.New(reflect.TypeOf(event)).Elem()
scanner := descriptor.Scanner()
scanner.Target(got)
scanner.Scan(b)
assert.Equal(t, event, got.Interface())
got := reflect.New(reflect.TypeOf(event))
scanner := descriptor.Scanner()
scanner.Target(got)
scanner.Scan(b)
assert.Equal(t, event, got.Elem().Interface())
})
}
13 changes: 8 additions & 5 deletions sqlgen/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

_ "github.com/go-sql-driver/mysql"
"github.com/samsarahq/thunder/batch"
"github.com/samsarahq/thunder/internal/proto"
"github.com/samsarahq/thunder/internal/testfixtures"
"github.com/stretchr/testify/assert"
)
Expand All @@ -20,10 +21,11 @@ func setup() (*testfixtures.TestDatabase, *DB, error) {

if _, err = testDb.Exec(`
CREATE TABLE users (
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
uuid VARCHAR(255),
mood VARCHAR(255),
id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255),
uuid VARCHAR(255),
mood VARCHAR(255),
proto BLOB,
implicit_null VARCHAR(255)
)
`); err != nil {
Expand All @@ -40,7 +42,8 @@ type User struct {
Name string
Uuid testfixtures.CustomType
Mood *testfixtures.CustomType
ImplicitNull string `sql:",implicitnull"`
Proto proto.ExampleEvent `sql:",binary"`
ImplicitNull string `sql:",implicitnull"`
}

type Complex struct {
Expand Down