From 9a0d8d5f69303cfc7fda6a6a808bfdd3ce48e108 Mon Sep 17 00:00:00 2001 From: Helene Durand Date: Fri, 2 Feb 2024 14:32:33 +0100 Subject: [PATCH] MEDIUM: enhance struct_equal_generator for v3 model Co-authored-by: Zlatko Bratkovic --- cmd/struct_equal_generator/generate.tmpl | 46 +++++++++++++++++++----- cmd/struct_equal_generator/main.go | 6 ++++ cmd/struct_equal_generator/misc.go | 13 +++++-- cmd/struct_equal_generator/utils.tmpl | 42 ++++++++++++++++++++++ models/utils_compare.go | 42 ++++++++++++++++++++++ 5 files changed, 138 insertions(+), 11 deletions(-) diff --git a/cmd/struct_equal_generator/generate.tmpl b/cmd/struct_equal_generator/generate.tmpl index 93531acf..6d36a874 100644 --- a/cmd/struct_equal_generator/generate.tmpl +++ b/cmd/struct_equal_generator/generate.tmpl @@ -83,6 +83,44 @@ func (s {{.Data.Name}}) {{.Name}}(t {{.Data.Name}}, opts ...Options) {{- if eq $ diff["{{.Name}}"] = []interface{}{ {{if HasPrefix .Type "*"}}ValueOrNil({{end}}s.{{.Name}}{{if HasPrefix .Type "*"}}){{end}}, {{if HasPrefix .Type "*"}}ValueOrNil({{end}}t.{{.Name}}{{if HasPrefix .Type "*"}}){{end}} } {{- end }} } + {{- else if HasPrefix .Type "map" }} + {{- if eq .Type "map[string]map[string]string"}} + if !equalMapStringMapSting(s.{{.Name}}, t.{{.Name}}, opt) { + {{- if eq $topLevel.Name "Equal" }} + return false + {{- else if eq $topLevel.Name "Diff" }} + diff["{{.Name}}"] = []interface{}{ s.{{.Name}}, t.{{.Name}}} + {{- end }} + } + {{- else }} + {{- if not .IsComparable }} + if !CheckSameNilAndLenMap[{{.MapKeyType}},{{.MapItemType}}](s.{{.Name}}, t.{{.Name}}, opt){ + {{- if eq $topLevel.Name "Equal" }} + return false + {{- else if eq $topLevel.Name "Diff" }} + diff["{{.Name}}"] = []interface{}{ s.{{.Name}}, t.{{.Name}}} + {{- end }} + } + + for k,v := range s.{{.Name}} { + if !t.{{.Name}}[k].Equal(v, opt) { + {{- if eq $topLevel.Name "Equal" }} + return false + {{- else if eq $topLevel.Name "Diff" }} + diff["{{.Name}}"] = []interface{}{ s.{{.Name}}, t.{{.Name}}} + {{- end }} + } + } + {{- else }} + if !equalComparableMap(s.{{.Name}}, t.{{.Name}}, opt) { + {{- if eq $topLevel.Name "Equal" }} + return false + {{- else if eq $topLevel.Name "Diff" }} + diff["{{.Name}}"] = []interface{}{ s.{{.Name}}, t.{{.Name}}} + {{- end }} + } + {{- end }} + {{- end }} {{- else if or .IsBasicType .IsComparable}} {{- if HasPrefix .Type "*" }} if !equalPointers(s.{{.Name}}, t.{{.Name}}) { @@ -101,14 +139,6 @@ func (s {{.Data.Name}}) {{.Name}}(t {{.Data.Name}}, opts ...Options) {{- if eq $ {{- end }} } {{- end }} - {{- else if HasPrefix .Type "map" }} - if !equalComparableMap(s.{{.Name}}, t.{{.Name}}, opt) { - {{- if eq $topLevel.Name "Equal" }} - return false - {{- else if eq $topLevel.Name "Diff" }} - diff["{{.Name}}"] = []interface{}{ s.{{.Name}}, t.{{.Name}}} - {{- end }} - } {{- else if .IsArray }} {{- if or .IsComparable .SubType.IsComparable }} if !equalComparableSlice(s.{{.Name}}, t.{{.Name}}, opt) { diff --git a/cmd/struct_equal_generator/main.go b/cmd/struct_equal_generator/main.go index 66c7a218..5ece73e9 100644 --- a/cmd/struct_equal_generator/main.go +++ b/cmd/struct_equal_generator/main.go @@ -298,6 +298,8 @@ func getFields(fields []Field, node *ast.StructType, imports map[string]string) HasEqualOpt: res.HasEqualOpt, IsArray: res.IsArray, IsMap: res.IsMap, + MapKeyType: res.MapKeyType, + MapItemType: res.MapItemType, } if res.SubType != nil { f.SubType = &Field{ @@ -312,6 +314,8 @@ func getFields(fields []Field, node *ast.StructType, imports map[string]string) HasEqualOpt: res.SubType.HasEqualOpt, IsArray: res.SubType.IsArray, IsMap: res.SubType.IsMap, + // MapKeyType: res.MapKeyType, + // MapItemType: res.MapItemType, } } fields = append(fields, f) @@ -336,6 +340,8 @@ func getFields(fields []Field, node *ast.StructType, imports map[string]string) HasString: res.HasStringer, HasEqual: res.HasEqual, HasEqualOpt: res.HasEqualOpt, + // MapKeyType: res.MapKeyType, + // MapItemType: res.MapItemType, }) if res.Name == "Index" { needsOptionsIndex = true diff --git a/cmd/struct_equal_generator/misc.go b/cmd/struct_equal_generator/misc.go index a34a6bbb..3db18284 100644 --- a/cmd/struct_equal_generator/misc.go +++ b/cmd/struct_equal_generator/misc.go @@ -22,6 +22,8 @@ type Field struct { HasEqualOpt bool IsArray bool IsMap bool + MapKeyType string + MapItemType string SubType *Field } @@ -120,6 +122,8 @@ type getTypeStringResponse struct { HasEqualOpt bool IsArray bool IsMap bool + MapKeyType string + MapItemType string StructType *ast.StructType SubType *getTypeStringResponse } @@ -172,9 +176,12 @@ func getTypeString(expr ast.Expr, imports map[string]string) getTypeStringRespon rKey := getTypeString(t.Key, imports) rValue := getTypeString(t.Value, imports) return getTypeStringResponse{ - Name: "map[" + rKey.Name + "]" + rValue.Name, - IsComplex: rValue.IsComplex, - IsMap: true, + Name: "map[" + rKey.Name + "]" + rValue.Name, + MapKeyType: rKey.Name, + MapItemType: rValue.Name, + IsComplex: rValue.IsComplex, + IsMap: true, + IsComparable: isComparable(rValue.Name), } case *ast.SelectorExpr: start := expr.Pos() - 1 diff --git a/cmd/struct_equal_generator/utils.tmpl b/cmd/struct_equal_generator/utils.tmpl index 89f6e4fb..a595b66e 100644 --- a/cmd/struct_equal_generator/utils.tmpl +++ b/cmd/struct_equal_generator/utils.tmpl @@ -44,6 +44,23 @@ func CheckSameNilAndLen[T any](s,t []T, opts ...Options) bool { return true } +func CheckSameNilAndLenMap[S comparable, T any](s, t map[S]T, opts ...Options) bool { + opt := getOptions(opts...) + + if !opt.NilSameAsEmpty { + if s == nil && t != nil { + return false + } + if t == nil && s != nil { + return false + } + } + if len(s) != len(t) { + return false + } + return true +} + func equalComparableSlice[T comparable](s1, s2 []T, opt Options) bool { if !opt.NilSameAsEmpty { if s1 == nil && s2 != nil { @@ -94,3 +111,28 @@ func ValueOrNil[T any](v *T) any { } return *v } + +func equalMapStringMapSting(m1, m2 map[string]map[string]string, opt Options) bool { + if !opt.NilSameAsEmpty { + if m1 == nil && m2 != nil { + return false + } + if m2 == nil && m1 != nil { + return false + } + } + + if len(m1) != len(m2) { + return false + } + for k1, v1 := range m1 { + if v2, ok := m2[k1]; !ok { + return false + } else { + if !equalComparableMap(v1, v2, opt){ + return false + } + } + } + return true +} diff --git a/models/utils_compare.go b/models/utils_compare.go index d9853e9c..cd40d42d 100644 --- a/models/utils_compare.go +++ b/models/utils_compare.go @@ -63,6 +63,23 @@ func CheckSameNilAndLen[T any](s, t []T, opts ...Options) bool { return true } +func CheckSameNilAndLenMap[S comparable, T any](s, t map[S]T, opts ...Options) bool { + opt := getOptions(opts...) + + if !opt.NilSameAsEmpty { + if s == nil && t != nil { + return false + } + if t == nil && s != nil { + return false + } + } + if len(s) != len(t) { + return false + } + return true +} + func equalComparableSlice[T comparable](s1, s2 []T, opt Options) bool { if !opt.NilSameAsEmpty { if s1 == nil && s2 != nil { @@ -113,3 +130,28 @@ func ValueOrNil[T any](v *T) any { } return *v } + +func equalMapStringMapSting(m1, m2 map[string]map[string]string, opt Options) bool { + if !opt.NilSameAsEmpty { + if m1 == nil && m2 != nil { + return false + } + if m2 == nil && m1 != nil { + return false + } + } + + if len(m1) != len(m2) { + return false + } + for k1, v1 := range m1 { + if v2, ok := m2[k1]; !ok { + return false + } else { + if !equalComparableMap(v1, v2, opt) { + return false + } + } + } + return true +}