Commit de612d9
pkg/mapper/mapper.go
@@ -0,0 +1,46 @@
+package mapper
+
+import (
+ "fmt"
+ "reflect"
+)
+
+type Mapping[TInput any, TOutput any] func(TInput) TOutput
+
+var mappings map[string]interface{}
+
+func init() {
+ mappings = map[string]interface{}{}
+}
+
+func Register[Input any, Output any](mapping Mapping[Input, Output]) {
+ mappings[keyFor[Input, Output]()] = mapping
+}
+
+func MapFrom[Input any, Output any](input Input) Output {
+ if mapping, ok := mappings[keyFor[Input, Output]()]; ok {
+ return mapping.(Mapping[Input, Output])(input)
+ }
+ var output Output
+ return output
+}
+
+func MapEachFrom[Input any, Output any](input []Input) []Output {
+ var zero Output
+ zeroValue := reflect.Zero(reflect.TypeOf(zero))
+
+ results := []Output{}
+ for _, item := range input {
+ tmp := MapFrom[Input, Output](item)
+ if zeroValue != reflect.ValueOf(tmp) {
+ results = append(results, tmp)
+ }
+ }
+ return results
+}
+
+func keyFor[Input any, Output any]() string {
+ var input Input
+ var output Output
+ return fmt.Sprintf("%v-%v", reflect.TypeOf(input), reflect.TypeOf(output))
+}
pkg/mapper/test.go
@@ -0,0 +1,77 @@
+package mapper
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+type unregisteredType struct{}
+
+type testObject struct {
+ GivenName string
+ FamilyName string
+}
+
+type testModel struct {
+ Name string
+}
+
+func TestMapper(t *testing.T) {
+ Register[*testObject, *testModel](func(item *testObject) *testModel {
+ return &testModel{
+ Name: fmt.Sprintf("%v %v", item.GivenName, item.FamilyName),
+ }
+ })
+
+ t.Run("MapFrom", func(t *testing.T) {
+ t.Run("when the mapping is registered", func(t *testing.T) {
+ item := &testObject{
+ GivenName: "Tsuyoshi",
+ FamilyName: "Garret",
+ }
+
+ model := MapFrom[*testObject, *testModel](item)
+
+ require.NotNil(t, model)
+ assert.Equal(t, "Tsuyoshi Garret", model.Name)
+ })
+
+ t.Run("When the mapping is not registered", func(t *testing.T) {
+ item := &unregisteredType{}
+ model := MapFrom[*unregisteredType, *testModel](item)
+
+ assert.Nil(t, model)
+ })
+ })
+
+ t.Run("MapEachFrom", func(t *testing.T) {
+ t.Run("when the mapping is registered", func(t *testing.T) {
+ datum := []*testObject{
+ {GivenName: "Tsuyoshi", FamilyName: "Garret"},
+ {GivenName: "Takashi", FamilyName: "Shirogane"},
+ }
+
+ results := MapEachFrom[*testObject, *testModel](datum)
+
+ require.NotNil(t, results)
+ require.Equal(t, 2, len(results))
+
+ assert.Equal(t, "Tsuyoshi Garret", results[0].Name)
+ assert.Equal(t, "Takashi Shirogane", results[1].Name)
+ })
+
+ t.Run("when the mapping is not registered", func(t *testing.T) {
+ datum := []*unregisteredType{
+ {},
+ }
+
+ results := MapEachFrom[*unregisteredType, *testModel](datum)
+
+ require.NotNil(t, results)
+ assert.Equal(t, 0, len(results))
+ })
+ })
+}