Commit de612d9

mo khan <mo@mokhan.ca>
2022-09-24 03:12:46
feat: create mapper package
1 parent fcd69a5
Changed files (2)
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))
+		})
+	})
+}