Skip to content

Commit 97a16f9

Browse files
refactor: improve populator naming and handling of structs in unmarshaller (#16)
1 parent 0cae2ba commit 97a16f9

23 files changed

+593
-481
lines changed

arazzo/arazzo.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func Unmarshal(ctx context.Context, doc io.Reader, opts ...Option[unmarshalOptio
7575
}
7676

7777
arazzo := &Arazzo{}
78-
if err := marshaller.PopulateModel(*c, arazzo); err != nil {
78+
if err := marshaller.Populate(*c, arazzo); err != nil {
7979
return nil, nil, err
8080
}
8181

arazzo/criterion/criterion.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ func (c CriterionTypeUnion) GetVersion() CriterionTypeVersion {
136136
return c.ExpressionType.Version
137137
}
138138

139-
func (c *CriterionTypeUnion) FromCore(cr any) error {
140-
coreCriterionTypeUnion, ok := cr.(core.CriterionTypeUnion)
139+
func (c *CriterionTypeUnion) Populate(source any) error {
140+
coreCriterionTypeUnion, ok := source.(core.CriterionTypeUnion)
141141
if !ok {
142142
return fmt.Errorf("expected core.CriterionTypeUnion, got %T", c)
143143
}
@@ -147,7 +147,7 @@ func (c *CriterionTypeUnion) FromCore(cr any) error {
147147
c.Type = &typ
148148
} else if coreCriterionTypeUnion.ExpressionType != nil {
149149
c.ExpressionType = &CriterionExpressionType{}
150-
if err := marshaller.PopulateModel(*coreCriterionTypeUnion.ExpressionType, c.ExpressionType); err != nil {
150+
if err := marshaller.Populate(*coreCriterionTypeUnion.ExpressionType, c.ExpressionType); err != nil {
151151
return err
152152
}
153153
}

extensions/extensions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ func UnmarshalExtensionModel[H any, L any](ctx context.Context, e *Extensions, e
8383

8484
var mV H
8585

86-
if err := marshaller.PopulateModel(*c, &mV); err != nil {
86+
if err := marshaller.Populate(*c, &mV); err != nil {
8787
return err
8888
}
8989
*m = mV

extensions/extensions_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ func getTestModelWithExtensions(ctx context.Context, t *testing.T, data string)
116116
require.NoError(t, err)
117117

118118
m := &ModelWithExtensions{}
119-
err = marshaller.PopulateModel(c, m)
119+
err = marshaller.Populate(c, m)
120120
require.NoError(t, err)
121121

122122
return m

marshaller/extensions_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ primitiveField: hello
4242
type TestExtensionModel struct {
4343
marshaller.CoreModel
4444
PrimitiveField marshaller.Node[string] `key:"primitiveField"`
45-
Extensions marshaller.Extensions `key:"extensions"`
45+
Extensions Extensions `key:"extensions"`
4646
}
4747

4848
func Test_Extensions_SyncExtensions_Success(t *testing.T) {
@@ -74,7 +74,7 @@ func Test_Extensions_SyncExtensions_Success(t *testing.T) {
7474

7575
type TestExtensionUnmarshalError struct {
7676
marshaller.CoreModel
77-
Extensions marshaller.Extensions `key:"extensions"`
77+
Extensions Extensions `key:"extensions"`
7878
}
7979

8080
func Test_Extensions_UnmarshalError_Coverage(t *testing.T) {

marshaller/populator.go

Lines changed: 20 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import (
55
"reflect"
66
)
77

8-
type ModelFromCore interface {
9-
FromCore(c any) error
8+
type Populator interface {
9+
Populate(source any) error
1010
}
1111

12-
func PopulateModel(source any, target any) error {
12+
func Populate(source any, target any) error {
1313
t := reflect.ValueOf(target)
1414

1515
if t.Kind() == reflect.Ptr && t.IsNil() {
@@ -125,12 +125,8 @@ func populateValue(source any, target reflect.Value) error {
125125
target = target.Addr()
126126
}
127127

128-
if value.Kind() == reflect.Ptr {
129-
value = value.Elem()
130-
}
131-
132-
if target.Type().Implements(reflect.TypeOf((*ModelFromCore)(nil)).Elem()) {
133-
return target.Interface().(ModelFromCore).FromCore(value.Interface())
128+
if target.Type().Implements(reflect.TypeOf((*Populator)(nil)).Elem()) {
129+
return target.Interface().(Populator).Populate(value.Interface())
134130
}
135131

136132
// Check if target implements CoreSetter interface
@@ -143,58 +139,33 @@ func populateValue(source any, target reflect.Value) error {
143139
return nil
144140
}
145141

146-
if target.Type().Implements(reflect.TypeOf((*SequencedMap)(nil)).Elem()) {
147-
return populateSequencedMap(value, target)
148-
}
149-
150142
target = target.Elem()
151143

152-
switch value.Kind() {
144+
valueDerefed := value
145+
if value.Kind() == reflect.Ptr {
146+
valueDerefed = value.Elem()
147+
}
148+
149+
switch valueDerefed.Kind() {
153150
case reflect.Slice, reflect.Array:
154-
if value.IsNil() {
151+
if valueDerefed.IsNil() {
155152
return nil
156153
}
157154

158-
target.Set(reflect.MakeSlice(target.Type(), value.Len(), value.Len()))
155+
target.Set(reflect.MakeSlice(target.Type(), valueDerefed.Len(), valueDerefed.Len()))
159156

160-
for i := 0; i < value.Len(); i++ {
161-
if err := populateValue(value.Index(i).Interface(), target.Index(i)); err != nil {
157+
for i := 0; i < valueDerefed.Len(); i++ {
158+
if err := populateValue(valueDerefed.Index(i).Interface(), target.Index(i)); err != nil {
162159
return err
163160
}
164161
}
165162
default:
166-
if value.Type().AssignableTo(target.Type()) {
167-
target.Set(value)
168-
} else if value.CanConvert(target.Type()) {
169-
target.Set(value.Convert(target.Type()))
163+
if valueDerefed.Type().AssignableTo(target.Type()) {
164+
target.Set(valueDerefed)
165+
} else if valueDerefed.CanConvert(target.Type()) {
166+
target.Set(valueDerefed.Convert(target.Type()))
170167
} else {
171-
return fmt.Errorf("cannot convert %v to %v", value.Type(), target.Type())
172-
}
173-
}
174-
175-
return nil
176-
}
177-
178-
func populateSequencedMap(source reflect.Value, target reflect.Value) error {
179-
sm, ok := source.Addr().Interface().(SequencedMap)
180-
if !ok {
181-
return fmt.Errorf("expected source to be SequencedMap, got %s", source.Type())
182-
}
183-
184-
tm, ok := target.Interface().(SequencedMap)
185-
if !ok {
186-
return fmt.Errorf("expected target to be SequencedMap, got %s", target.Type())
187-
}
188-
189-
tm.Init()
190-
191-
for key, value := range sm.AllUntyped() {
192-
targetValue := reflect.New(tm.GetValueType()).Elem()
193-
if err := populateValue(value, targetValue); err != nil {
194-
return err
195-
}
196-
if err := tm.SetUntyped(key, targetValue.Interface()); err != nil {
197-
return err
168+
return fmt.Errorf("cannot convert %v to %v", valueDerefed.Type(), target.Type())
198169
}
199170
}
200171

marshaller/populator_bare_slice_test.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
// To trigger the slice/array case in populateValue, we need:
12-
// 1. A target that does NOT implement ModelFromCore, CoreSetter, or SequencedMap
12+
// 1. A target that does NOT implement Populator, CoreSetter, or SequencedMap
1313
// 2. A source that is a slice or array
1414
// 3. The target to be a pointer that after target.Elem() can accept the slice/array
1515

@@ -28,15 +28,15 @@ func Test_PopulateValue_BareSliceTarget_Success(t *testing.T) {
2828

2929
target := &BareSliceTarget{}
3030

31-
err := marshaller.PopulateModel(source, target)
31+
err := marshaller.Populate(source, target)
3232
require.NoError(t, err)
3333

3434
assert.Equal(t, []string{"bare1", "bare2", "bare3"}, target.SimpleSlice)
3535
assert.Equal(t, [3]int{10, 20, 30}, target.SimpleArray)
3636
}
3737

3838
// Try with an even simpler case: directly pass slice values
39-
// This creates a scenario where populateValue would be called recursively
39+
// This creates a scenario where populateValue would be called recursively
4040
// with slice source and pointer target
4141

4242
type ContainerWithSliceField struct {
@@ -51,7 +51,7 @@ func Test_PopulateValue_ContainerWithSlice_Success(t *testing.T) {
5151

5252
target := &ContainerWithSliceField{}
5353

54-
err := marshaller.PopulateModel(source, target)
54+
err := marshaller.Populate(source, target)
5555
require.NoError(t, err)
5656

5757
assert.Equal(t, []string{"container1", "container2"}, target.SliceField)
@@ -66,15 +66,15 @@ type PointerSliceTarget struct {
6666
func Test_PopulateValue_PointerSliceTarget_Success(t *testing.T) {
6767
sourceSlice := []string{"ptr1", "ptr2"}
6868
sourceArray := [2]int{100, 200}
69-
69+
7070
source := PointerSliceTarget{
7171
SlicePtr: &sourceSlice,
7272
ArrayPtr: &sourceArray,
7373
}
7474

7575
target := &PointerSliceTarget{}
7676

77-
err := marshaller.PopulateModel(source, target)
77+
err := marshaller.Populate(source, target)
7878
require.NoError(t, err)
7979

8080
require.NotNil(t, target.SlicePtr)
@@ -101,7 +101,7 @@ func Test_PopulateValue_EmbeddedSliceStruct_Success(t *testing.T) {
101101

102102
target := &EmbeddedSliceStruct{}
103103

104-
err := marshaller.PopulateModel(source, target)
104+
err := marshaller.Populate(source, target)
105105
require.NoError(t, err)
106106

107107
assert.Equal(t, []string{"embedded1", "embedded2"}, target.Inner.Data)
@@ -119,8 +119,8 @@ func Test_PopulateValue_JustSlice_Success(t *testing.T) {
119119

120120
target := &JustSlice{}
121121

122-
err := marshaller.PopulateModel(source, target)
122+
err := marshaller.Populate(source, target)
123123
require.NoError(t, err)
124124

125125
assert.Equal(t, []string{"just1", "just2"}, target.Data)
126-
}
126+
}

marshaller/populator_comprehensive_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func Test_PopulateModel_SimpleStructToStruct(t *testing.T) {
2727

2828
target := &Target{}
2929

30-
err := marshaller.PopulateModel(source, target)
30+
err := marshaller.Populate(source, target)
3131
require.NoError(t, err)
3232
assert.Equal(t, "test", target.StringField)
3333
assert.Equal(t, 42, target.IntField)
@@ -49,7 +49,7 @@ func Test_PopulateModel_WithSlices(t *testing.T) {
4949

5050
target := &Target{}
5151

52-
err := marshaller.PopulateModel(source, target)
52+
err := marshaller.Populate(source, target)
5353
require.NoError(t, err)
5454
assert.Equal(t, []string{"a", "b", "c"}, target.SliceField)
5555
}
@@ -70,7 +70,7 @@ func Test_PopulateModel_WithNilSlice(t *testing.T) {
7070

7171
target := &Target{}
7272

73-
err := marshaller.PopulateModel(source, target)
73+
err := marshaller.Populate(source, target)
7474
require.NoError(t, err)
7575
assert.Nil(t, target.SliceField)
7676
}
@@ -91,7 +91,7 @@ func Test_PopulateModel_TypeConversion(t *testing.T) {
9191

9292
target := &Target{}
9393

94-
err := marshaller.PopulateModel(source, target)
94+
err := marshaller.Populate(source, target)
9595
// This might fail due to type incompatibility - that's expected
9696
if err != nil {
9797
assert.Contains(t, err.Error(), "cannot convert")
@@ -117,7 +117,7 @@ func Test_PopulateModel_WithPointers(t *testing.T) {
117117

118118
target := &Target{}
119119

120-
err := marshaller.PopulateModel(source, target)
120+
err := marshaller.Populate(source, target)
121121
require.NoError(t, err)
122122
require.NotNil(t, target.PtrField)
123123
assert.Equal(t, "test-value", *target.PtrField)
@@ -139,7 +139,7 @@ func Test_PopulateModel_WithNilPointer(t *testing.T) {
139139

140140
target := &Target{}
141141

142-
err := marshaller.PopulateModel(source, target)
142+
err := marshaller.Populate(source, target)
143143
require.NoError(t, err)
144144
assert.Nil(t, target.PtrField)
145145
}
@@ -153,7 +153,7 @@ func Test_PopulateModel_NonStructSource_Error(t *testing.T) {
153153
source := "not-a-struct"
154154
target := &Target{}
155155

156-
err := marshaller.PopulateModel(source, target)
156+
err := marshaller.Populate(source, target)
157157
require.Error(t, err)
158158
assert.Contains(t, err.Error(), "cannot convert")
159159
}
@@ -174,7 +174,7 @@ func Test_PopulateModel_IncompatibleTypes_Error(t *testing.T) {
174174

175175
target := &Target{}
176176

177-
err := marshaller.PopulateModel(source, target)
177+
err := marshaller.Populate(source, target)
178178
require.Error(t, err)
179179
assert.Contains(t, err.Error(), "cannot convert")
180180
}
@@ -202,9 +202,9 @@ func Test_PopulateModel_NestedSlices(t *testing.T) {
202202

203203
target := &Target{}
204204

205-
err := marshaller.PopulateModel(source, target)
205+
err := marshaller.Populate(source, target)
206206
require.NoError(t, err)
207207
require.Len(t, target.NestedSlice, 2)
208208
assert.Equal(t, "first", target.NestedSlice[0].Value)
209209
assert.Equal(t, "second", target.NestedSlice[1].Value)
210-
}
210+
}

0 commit comments

Comments
 (0)