Skip to content

Commit

Permalink
fixes and tests
Browse files Browse the repository at this point in the history
Change-Id: I9c7e952df2d8c4d30d149ca97a267672eacbea4a
  • Loading branch information
shentongmartin committed Jan 6, 2025
1 parent b94ec40 commit 7a31f1c
Show file tree
Hide file tree
Showing 6 changed files with 335 additions and 233 deletions.
110 changes: 63 additions & 47 deletions compose/field_mapping.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 2024 CloudWeGo Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package compose

import (
Expand All @@ -10,26 +26,26 @@ import (
)

func takeOne(input any, m *Mapping) (any, error) {
if len(m.FromField) == 0 && len(m.FromMapKey) == 0 {
if len(m.fromField) == 0 && len(m.fromMapKey) == 0 {
return input, nil
}

if len(m.FromField) > 0 && len(m.FromMapKey) > 0 {
return nil, fmt.Errorf("mapping has both FromField and FromMapKey, m=%+v", m)
if len(m.fromField) > 0 && len(m.fromMapKey) > 0 {
return nil, fmt.Errorf("mapping has both fromField and fromMapKey, m=%s", m)
}

inputValue := reflect.ValueOf(input)

if len(m.FromField) > 0 {
f, err := checkAndExtractFromField(m.FromField, inputValue)
if len(m.fromField) > 0 {
f, err := checkAndExtractFromField(m.fromField, inputValue)
if err != nil {
return nil, err
}

return f.Interface(), nil
}

v, err := checkAndExtractFromMapKey(m.FromMapKey, inputValue)
v, err := checkAndExtractFromMapKey(m.fromMapKey, inputValue)
if err != nil {
return nil, err
}
Expand All @@ -44,7 +60,7 @@ func assignOne[T any](dest T, taken any, m *Mapping) (T, error) {
destValue = reflect.ValueOf(&dest).Elem()
}

if len(m.ToField) == 0 && len(m.ToMapKey) == 0 { // assign to output directly
if len(m.toField) == 0 && len(m.toMapKey) == 0 { // assign to output directly
toSet := reflect.ValueOf(taken)
if !toSet.Type().AssignableTo(destValue.Type()) {
return dest, fmt.Errorf("mapping entire value has a mismatched type. from=%v, to=%v", toSet.Type(), destValue.Type())
Expand All @@ -55,14 +71,14 @@ func assignOne[T any](dest T, taken any, m *Mapping) (T, error) {
return destValue.Interface().(T), nil
}

if len(m.ToField) > 0 && len(m.ToMapKey) > 0 {
return dest, fmt.Errorf("mapping has both ToField and ToMapKey, m=%+v", m)
if len(m.toField) > 0 && len(m.toMapKey) > 0 {
return dest, fmt.Errorf("mapping has both toField and toMapKey, m=%s", m)
}

toSet := reflect.ValueOf(taken)

if len(m.ToField) > 0 {
field, err := checkAndExtractToField(m.ToField, destValue, toSet)
if len(m.toField) > 0 {
field, err := checkAndExtractToField(m.toField, destValue, toSet)
if err != nil {
return dest, err
}
Expand All @@ -71,7 +87,7 @@ func assignOne[T any](dest T, taken any, m *Mapping) (T, error) {
return destValue.Interface().(T), nil
}

key, err := checkAndExtractToMapKey(m.ToMapKey, destValue, toSet)
key, err := checkAndExtractToMapKey(m.toMapKey, destValue, toSet)
if err != nil {
return dest, err
}
Expand All @@ -87,16 +103,16 @@ func mapFrom[T any](input any, mappings []*Mapping) (T, error) {
return t, errors.New("mapper has no Mappings")
}

from := mappings[0].From
from := mappings[0].fromNodeKey
for _, mapping := range mappings {
if len(mapping.ToField) == 0 && len(mapping.ToMapKey) == 0 {
if len(mapping.toField) == 0 && len(mapping.toMapKey) == 0 {
if len(mappings) > 1 {
return t, fmt.Errorf("one of the mapping maps to entire input, conflict")
}
}

if mapping.From != from {
return t, fmt.Errorf("multiple mappings from the same node have different keys: %s, %s", mapping.From, from)
if mapping.fromNodeKey != from {
return t, fmt.Errorf("multiple mappings from the same node have different keys: %s, %s", mapping.fromNodeKey, from)
}

taken, err := takeOne(input, mapping)
Expand Down Expand Up @@ -150,16 +166,16 @@ func checkAndExtractFromField(fromField string, input reflect.Value) (reflect.Va
}

if input.Kind() != reflect.Struct {
return reflect.Value{}, fmt.Errorf("mapping has FromField but input is not struct or struct ptr, type= %v", input.Type())
return reflect.Value{}, fmt.Errorf("mapping has fromField but input is not struct or struct ptr, type= %v", input.Type())
}

f := input.FieldByName(fromField)
if !f.IsValid() {
return reflect.Value{}, fmt.Errorf("mapping has FromField not found. field=%v, inputType=%v", fromField, input.Type())
return reflect.Value{}, fmt.Errorf("mapping has fromField not found. field=%v, inputType=%v", fromField, input.Type())
}

if !f.CanInterface() {
return reflect.Value{}, fmt.Errorf("mapping has FromField not exported. field= %v, inputType=%v", fromField, input.Type())
return reflect.Value{}, fmt.Errorf("mapping has fromField not exported. field= %v, inputType=%v", fromField, input.Type())
}

return f, nil
Expand All @@ -176,7 +192,7 @@ func checkAndExtractFromMapKey(fromMapKey string, input reflect.Value) (reflect.

v := input.MapIndex(reflect.ValueOf(fromMapKey))
if !v.IsValid() {
return reflect.Value{}, fmt.Errorf("mapping FromMapKey not found in input. key=%s, inputType= %v", fromMapKey, input.Type())
return reflect.Value{}, fmt.Errorf("mapping fromMapKey not found in input. key=%s, inputType= %v", fromMapKey, input.Type())
}

return v, nil
Expand All @@ -188,42 +204,42 @@ func checkAndExtractToField(toField string, output, toSet reflect.Value) (reflec
}

if output.Kind() != reflect.Struct {
return reflect.Value{}, fmt.Errorf("mapping has ToField but output is not a struct, type=%v", output.Type())
return reflect.Value{}, fmt.Errorf("mapping has toField but output is not a struct, type=%v", output.Type())
}

field := output.FieldByName(toField)
if !field.IsValid() {
return reflect.Value{}, fmt.Errorf("mapping has ToField not found. field=%v, outputType=%v", toField, output.Type())
return reflect.Value{}, fmt.Errorf("mapping has toField not found. field=%v, outputType=%v", toField, output.Type())
}

if !field.CanSet() {
return reflect.Value{}, fmt.Errorf("mapping has ToField not exported. field=%v, outputType=%v", toField, output.Type())
return reflect.Value{}, fmt.Errorf("mapping has toField not exported. field=%v, outputType=%v", toField, output.Type())
}

if !toSet.Type().AssignableTo(field.Type()) {
return reflect.Value{}, fmt.Errorf("mapping ToField has a mismatched type. field=%s, from=%v, to=%v", toField, toSet.Type(), field.Type())
return reflect.Value{}, fmt.Errorf("mapping toField has a mismatched type. field=%s, from=%v, to=%v", toField, toSet.Type(), field.Type())
}

return field, nil
}

func checkAndExtractToMapKey(toMapKey string, output, toSet reflect.Value) (reflect.Value, error) {
if output.Kind() != reflect.Map {
return reflect.Value{}, fmt.Errorf("mapping has ToMapKey but output is not a map, type=%v", output.Type())
return reflect.Value{}, fmt.Errorf("mapping has toMapKey but output is not a map, type=%v", output.Type())
}

if !reflect.TypeOf(toMapKey).AssignableTo(output.Type().Key()) {
return reflect.Value{}, fmt.Errorf("mapping has ToMapKey but output is not a map with string key, type=%v", output.Type())
return reflect.Value{}, fmt.Errorf("mapping has toMapKey but output is not a map with string key, type=%v", output.Type())
}

if !toSet.Type().AssignableTo(output.Type().Elem()) {
return reflect.Value{}, fmt.Errorf("mapping ToMapKey has a mismatched type. key=%s, from=%v, to=%v", toMapKey, toSet.Type(), output.Type().Elem())
return reflect.Value{}, fmt.Errorf("mapping toMapKey has a mismatched type. key=%s, from=%v, to=%v", toMapKey, toSet.Type(), output.Type().Elem())
}

return reflect.ValueOf(toMapKey), nil
}

func checkAndExtractMapValueType(mapKey string, typ reflect.Type) (reflect.Type, error) {
func checkAndExtractMapValueType(typ reflect.Type) (reflect.Type, error) {
if typ.Kind() != reflect.Map {
return nil, fmt.Errorf("type[%v] is not a map", typ)
}
Expand Down Expand Up @@ -261,65 +277,65 @@ func checkMappingGroup(mappings []*Mapping) error {
return nil
}

from := mappings[0].From
from := mappings[0].fromNodeKey
var fromMapKeyFlag, toMapKeyFlag, fromFieldFlag, toFieldFlag bool
fromMap := make(map[string]bool, len(mappings))
toMap := make(map[string]bool, len(mappings))
for _, mapping := range mappings {
if mapping.From != from {
return fmt.Errorf("multiple mappings from the same group have from node keys: %s, %s", mapping.From, from)
if mapping.fromNodeKey != from {
return fmt.Errorf("multiple mappings from the same group have from node keys: %s, %s", mapping.fromNodeKey, from)
}

if len(mapping.FromMapKey) > 0 {
if len(mapping.fromMapKey) > 0 {
if fromFieldFlag {
return fmt.Errorf("multiple mappings from the same group have both from field and from map key, mappings=%v", mappings)
}

if _, ok := fromMap[mapping.FromMapKey]; ok {
return fmt.Errorf("multiple mappings from the same group have the same from map key = %s, mappings=%v", mapping.FromMapKey, mappings)
if _, ok := fromMap[mapping.fromMapKey]; ok {
return fmt.Errorf("multiple mappings from the same group have the same from map key = %s, mappings=%v", mapping.fromMapKey, mappings)
}

fromMapKeyFlag = true
fromMap[mapping.FromMapKey] = true
fromMap[mapping.fromMapKey] = true
}

if len(mapping.FromField) > 0 {
if len(mapping.fromField) > 0 {
if fromMapKeyFlag {
return fmt.Errorf("multiple mappings from the same group have both from field and from map key, mappings=%v", mappings)
}

if _, ok := fromMap[mapping.FromField]; ok {
return fmt.Errorf("multiple mappings from the same group have the same from field = %s, mappings=%v", mapping.FromField, mappings)
if _, ok := fromMap[mapping.fromField]; ok {
return fmt.Errorf("multiple mappings from the same group have the same from field = %s, mappings=%v", mapping.fromField, mappings)
}

fromFieldFlag = true
fromMap[mapping.FromField] = true
fromMap[mapping.fromField] = true
}

if len(mapping.ToMapKey) > 0 {
if len(mapping.toMapKey) > 0 {
if toFieldFlag {
return fmt.Errorf("multiple mappings from the same group have both to field and to map key, mappings=%v", mappings)
}

if _, ok := toMap[mapping.ToMapKey]; ok {
return fmt.Errorf("multiple mappings from the same group have the same to map key = %s, mappings=%v", mapping.ToMapKey, mappings)
if _, ok := toMap[mapping.toMapKey]; ok {
return fmt.Errorf("multiple mappings from the same group have the same to map key = %s, mappings=%v", mapping.toMapKey, mappings)
}

toMapKeyFlag = true
toMap[mapping.ToMapKey] = true
toMap[mapping.toMapKey] = true
}

if len(mapping.ToField) > 0 {
if len(mapping.toField) > 0 {
if toMapKeyFlag {
return fmt.Errorf("multiple mappings from the same group have both to field and to map key, mappings=%v", mappings)
}

if _, ok := toMap[mapping.ToField]; ok {
return fmt.Errorf("multiple mappings from the same group have the same to field = %s, mappings=%v", mapping.ToField, mappings)
if _, ok := toMap[mapping.toField]; ok {
return fmt.Errorf("multiple mappings from the same group have the same to field = %s, mappings=%v", mapping.toField, mappings)
}

toFieldFlag = true
toMap[mapping.ToField] = true
toMap[mapping.toField] = true
}
}

Expand Down
Loading

0 comments on commit 7a31f1c

Please sign in to comment.