Skip to content

Commit

Permalink
refactor: structs create their own data providers if not provided wit…
Browse files Browse the repository at this point in the history
…h one
  • Loading branch information
Oudwins committed Aug 16, 2024
1 parent a7523de commit 6d5971a
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 20 deletions.
25 changes: 15 additions & 10 deletions primitives/DataProviders.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,40 +44,45 @@ func NewMapDataProvider[T any](m map[string]T) DataProvider {

// Tries to create a map data provider from any value if it cannot it will return an empty data provider (which will always return nil)
func NewAnyDataProvider(val any) DataProvider {
dataProvider, _ := TryNewAnyDataProvider(val)
return dataProvider
}

func TryNewAnyDataProvider(val any) (DataProvider, bool) {
x := reflect.ValueOf(val)

switch x.Kind() {
case reflect.Map:
keyTyp := x.Type().Key()

if keyTyp.Kind() != reflect.String {
return &EmptyDataProvider{}
return &EmptyDataProvider{}, false
}

valTyp := x.Type().Elem()

switch valTyp.Kind() { // TODO: add more types
case reflect.String:
return NewMapDataProvider(x.Interface().(map[string]string))
return NewMapDataProvider(x.Interface().(map[string]string)), true
case reflect.Int:
return NewMapDataProvider(x.Interface().(map[string]int))
return NewMapDataProvider(x.Interface().(map[string]int)), true
case reflect.Float64:
return NewMapDataProvider(x.Interface().(map[string]float64))
return NewMapDataProvider(x.Interface().(map[string]float64)), true
case reflect.Bool:
return NewMapDataProvider(x.Interface().(map[string]bool))
return NewMapDataProvider(x.Interface().(map[string]bool)), true
case reflect.Interface:
return NewMapDataProvider(x.Interface().(map[string]any))
return NewMapDataProvider(x.Interface().(map[string]any)), true
default:
return &EmptyDataProvider{}
return &EmptyDataProvider{}, false
}

case reflect.Pointer:
if x.IsNil() {
return &EmptyDataProvider{}
return &EmptyDataProvider{}, false
}
return NewAnyDataProvider(x.Elem().Interface())
return TryNewAnyDataProvider(x.Elem().Interface())

default:
return &EmptyDataProvider{}
return &EmptyDataProvider{}, false
}
}
7 changes: 1 addition & 6 deletions slices.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,7 @@ func (v *sliceProcessor) process(val any, dest any, errs p.ZogErrors, path p.Pat
item := refVal.Index(idx).Interface()
ptr := destVal.Index(idx).Addr().Interface()
path := path.Push(fmt.Sprint(idx))
if procesor, ok := v.schema.(*structProcessor); ok {
dp := p.NewAnyDataProvider(item)
procesor.process(dp, ptr, errs, path, ctx)
} else {
v.schema.process(item, ptr, errs, path, ctx)
}
v.schema.process(item, ptr, errs, path, ctx)
}
}

Expand Down
6 changes: 4 additions & 2 deletions slices_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ func TestSliceOfStructs(t *testing.T) {
var team Team

errsMap := teamSchema.Parse(NewMapDataProvider(data), &team)
fmt.Printf("%+v", errsMap)
fmt.Printf("%+v", team)
assert.Nil(t, errsMap)
assert.Len(t, team.Users, 2)
assert.Equal(t, team.Users[0].Name, "Jane")
assert.Equal(t, team.Users[1].Name, "John")
}
6 changes: 4 additions & 2 deletions struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,10 @@ func (v *structProcessor) process(val any, dest any, errs p.ZogErrors, path p.Pa
// 2. cast data as DataProvider
dataProv, ok := val.(p.DataProvider)
if !ok {
errs.Add(path, Errors.Wrap(fmt.Errorf("expected a DataProvider at path %s", path), "failed to validate field"))
return
if dataProv, ok = p.TryNewAnyDataProvider(val); !ok {
errs.Add(path, Errors.Wrap(fmt.Errorf("expected a DataProvider at path %s", path), "failed to validate field"))
return
}
}

// required
Expand Down

0 comments on commit 6d5971a

Please sign in to comment.