Skip to content

Commit

Permalink
Fix CastRow to process datetime fields. Fix #99
Browse files Browse the repository at this point in the history
  • Loading branch information
danielfireman committed Apr 1, 2022
1 parent c9919c5 commit 6cc5f3b
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
35 changes: 28 additions & 7 deletions schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,20 +260,41 @@ func getStructFields(out interface{}) ([]structField, error) {
for i := 0; i < outt.NumField(); i++ {
fieldValue := outv.Field(i)
if fieldValue.CanSet() { // Only consider exported fields.
// If it is an struct or a struct pointer
if fieldValue.Kind() == reflect.Struct ||
(fieldValue.Kind() == reflect.Ptr && fieldValue.Type().Elem().Kind() == reflect.Struct) {
if fieldValue.Kind() == reflect.Ptr {
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
switch {
// Special case on datetime fields, wich is a first-class schema
// type, represented as a struct with all fields unexported.
case fieldValue.Type() == reflect.TypeOf(time.Time{}):
fields = append(fields, structField{outt.Field(i), fieldValue})

// It it is a struct, deep dive on fields recursively.
case fieldValue.Kind() == reflect.Struct:
newF, err := getStructFields(reflect.Indirect(fieldValue).Addr().Interface())
if err != nil {
return nil, err
}
fields = append(fields, newF...)

// If it is a pointer.
case fieldValue.Kind() == reflect.Ptr:
// Allocate memory to it.
fieldValue.Set(reflect.New(fieldValue.Type().Elem()))

// If it is not a struct, simply add to the list.
if fieldValue.Type().Elem().Kind() != reflect.Struct {
fields = append(fields, structField{outt.Field(i), fieldValue})
break
}

// It it is a struct, deep dive on fields recursively.
newF, err := getStructFields(reflect.Indirect(fieldValue).Addr().Interface())
if err != nil {
return nil, err
}
fields = append(fields, newF...)
continue

default:
fields = append(fields, structField{outt.Field(i), fieldValue})
}
fields = append(fields, structField{outt.Field(i), fieldValue})
}
}
return fields, nil
Expand Down
12 changes: 12 additions & 0 deletions schema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"net/http/httptest"
"strings"
"testing"
"time"

"github.com/frictionlessdata/tableschema-go/table"
"github.com/matryer/is"
Expand Down Expand Up @@ -322,6 +323,17 @@ func TestSchema_Cast(t *testing.T) {
is.Equal(t1.MyName, "Foo")
is.Equal(t1.E.MyAge, int64(42))
})
t.Run("TimeField", func(t *testing.T) {
is := is.New(t)
t1 := struct {
T time.Time `tableheader:"T"`
}{}
s := Schema{Fields: []Field{{Name: "T", Type: DateTimeType, Format: "%Y-%m-%dT%H:%M:%S.fZ"}}}
is.NoErr(s.CastRow([]string{"2021-11-28T14:51:05.35811Z"}, &t1))

want, _ := time.Parse(time.RFC3339Nano, "2021-11-28T14:51:05.35811Z")
is.Equal(t1.T, want)
})
t.Run("StructPointerField", func(t *testing.T) {
is := is.New(t)
type EmbededT struct {
Expand Down

0 comments on commit 6cc5f3b

Please sign in to comment.