From 762bbe4ebeee9f3f71e613021306e2951758f6c8 Mon Sep 17 00:00:00 2001 From: Murad Biashimov Date: Tue, 19 Nov 2024 11:18:49 +0100 Subject: [PATCH] fix: field name collision --- generator/main.go | 43 ++++++++++++++++---- generator/models.go | 11 +++++ handler/kafkamirrormaker/kafkamirrormaker.go | 5 --- handler/user/user.go | 2 +- openapi_patch.yaml | 37 ----------------- 5 files changed, 48 insertions(+), 50 deletions(-) diff --git a/generator/main.go b/generator/main.go index a6ec3de..a8449c1 100644 --- a/generator/main.go +++ b/generator/main.go @@ -20,6 +20,7 @@ import ( "github.com/kelseyhightower/envconfig" "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "golang.org/x/exp/maps" "golang.org/x/exp/slices" "gopkg.in/yaml.v3" ) @@ -525,19 +526,47 @@ func writeStruct(f *jen.File, s *Schema) error { return nil } -// fmtStruct returns anynonous struct +// reInvertSnakeCase snake case name pattern reversed +var reInvertSnakeCase = regexp.MustCompile("[^a-zA-Z0-9_]+") + +// fmtStruct returns anonymous struct func fmtStruct(s *Schema) *jen.Statement { - fields := make([]jen.Code, 0, len(s.Properties)) - for _, k := range s.propertyNames { - p := s.Properties[k] - field := jen.Id(customCamelCase(k)).Add(getType(p)) - tag := k + // Sorts field names + // Resolves field name collision when a new more conventional JSON name replaces an existing field + jsonNames := maps.Keys(s.Properties) + sort.Slice(jsonNames, func(i, j int) bool { + return reInvertSnakeCase.ReplaceAllString(jsonNames[i], "") > reInvertSnakeCase.ReplaceAllString(jsonNames[j], "") + }) + + // Resolves collisions + uniqueNames := make(map[string]string, len(jsonNames)) + for _, jsonName := range jsonNames { + p := s.Properties[jsonName] + goName := customCamelCase(jsonName) + if exist, ok := uniqueNames[goName]; ok { + log.Warn().Msgf("Field collision: %q overrides %q", p.path(), exist) + } + // WARNING: This is a hack to avoid name collisions in Go fields + // overrides duplicate fields + uniqueNames[goName] = jsonName + } + fields := make([]jen.Code, 0, len(uniqueNames)) + for _, goName := range sortedKeys(uniqueNames) { + jsonName := uniqueNames[goName] + p := s.Properties[jsonName] + + // Adds json tags + tag := jsonName if !p.required { tag += ",omitempty" } - field = field.Tag(map[string]string{"json": strings.ReplaceAll(tag, `\`, "")}) + // Some fields have special characters escaped in the name + tag = strings.ReplaceAll(tag, `\`, "") + + field := jen.Id(goName).Add(getType(p)) + field = field.Tag(map[string]string{"json": tag}) // Adds a comment if it's not equal to the field name if p.Description != "" && p.Description != p.CamelName { diff --git a/generator/models.go b/generator/models.go index 0c99d04..3846f76 100644 --- a/generator/models.go +++ b/generator/models.go @@ -389,6 +389,17 @@ func (s *Schema) level() int { return level } +func (s *Schema) path() string { + path := []string{s.name} + p := s.parent + for p != nil { + path = append(path, p.name) + p = p.parent + } + slices.Reverse(path) + return strings.Join(path, "/") +} + // isAnonymous returns true when a struct should be rendered anonymous to reduce scope noise func (s *Schema) isAnonymous() bool { return s.hasCollision && s.isObject() && s.level() > 3 diff --git a/handler/kafkamirrormaker/kafkamirrormaker.go b/handler/kafkamirrormaker/kafkamirrormaker.go index 12b8eec..542d5aa 100644 --- a/handler/kafkamirrormaker/kafkamirrormaker.go +++ b/handler/kafkamirrormaker/kafkamirrormaker.go @@ -126,7 +126,6 @@ type ReplicationFlowOut struct { TargetCluster string `json:"target_cluster"` // Target cluster alias Topics []string `json:"topics,omitempty"` // List of topics and/or regular expressions to replicate. Topic names and regular expressions that match topic names that should be replicated. MirrorMaker will replicate these topics if they are not matched by "topics.exclude". Currently defaults to [".*"]. TopicsBlacklist []string `json:"topics.blacklist,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. - TopicsExclude []string `json:"topics.exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. TopicsExclude []string `json:"topics_exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. } type ReplicationPolicyClassType string @@ -156,7 +155,6 @@ type ServiceKafkaMirrorMakerCreateReplicationFlowIn struct { TargetCluster string `json:"target_cluster"` // Target cluster alias Topics *[]string `json:"topics,omitempty"` // List of topics and/or regular expressions to replicate. Topic names and regular expressions that match topic names that should be replicated. MirrorMaker will replicate these topics if they are not matched by "topics.exclude". Currently defaults to [".*"]. TopicsBlacklist *[]string `json:"topics.blacklist,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. - TopicsExclude *[]string `json:"topics.exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. TopicsExclude *[]string `json:"topics_exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. } @@ -177,7 +175,6 @@ type ServiceKafkaMirrorMakerGetReplicationFlowOut struct { TargetCluster string `json:"target_cluster"` // Target cluster alias Topics []string `json:"topics,omitempty"` // List of topics and/or regular expressions to replicate. Topic names and regular expressions that match topic names that should be replicated. MirrorMaker will replicate these topics if they are not matched by "topics.exclude". Currently defaults to [".*"]. TopicsBlacklist []string `json:"topics.blacklist,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. - TopicsExclude []string `json:"topics.exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. TopicsExclude []string `json:"topics_exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. } @@ -195,7 +192,6 @@ type ServiceKafkaMirrorMakerPatchReplicationFlowIn struct { SyncGroupOffsetsIntervalSeconds *int `json:"sync_group_offsets_interval_seconds,omitempty"` // Frequency of consumer group offset sync Topics *[]string `json:"topics,omitempty"` // List of topics and/or regular expressions to replicate. Topic names and regular expressions that match topic names that should be replicated. MirrorMaker will replicate these topics if they are not matched by "topics.exclude". Currently defaults to [".*"]. TopicsBlacklist *[]string `json:"topics.blacklist,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. - TopicsExclude *[]string `json:"topics.exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. TopicsExclude *[]string `json:"topics_exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. } @@ -216,7 +212,6 @@ type ServiceKafkaMirrorMakerPatchReplicationFlowOut struct { TargetCluster string `json:"target_cluster"` // Target cluster alias Topics []string `json:"topics,omitempty"` // List of topics and/or regular expressions to replicate. Topic names and regular expressions that match topic names that should be replicated. MirrorMaker will replicate these topics if they are not matched by "topics.exclude". Currently defaults to [".*"]. TopicsBlacklist []string `json:"topics.blacklist,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. - TopicsExclude []string `json:"topics.exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Deprecated property, use 'topics_exclude instead'. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. TopicsExclude []string `json:"topics_exclude,omitempty"` // List of topics and/or regular expressions to not replicate. Topic names and regular expressions that match topic names that should not be replicated. MirrorMaker will not replicate these topics even if they are matched by "topics". If not set, MM2 uses the default exclusion. } diff --git a/handler/user/user.go b/handler/user/user.go index 348c349..c84dcb2 100644 --- a/handler/user/user.go +++ b/handler/user/user.go @@ -694,10 +694,10 @@ type UserAuthLoginOptionsIn struct { // UserAuthLoginOptionsOut UserAuthLoginOptionsResponse type UserAuthLoginOptionsOut struct { - None []map[string]any `json:"None,omitempty"` // List of available login methods Action ActionType `json:"action"` // Action Method MethodType `json:"method,omitempty"` // HTTP method used for redirecting Name *string `json:"name,omitempty"` // Human readable name + None []map[string]any `json:"None,omitempty"` // List of available login methods RedirectUrl *string `json:"redirect_url,omitempty"` // Redirect URL for signing in } diff --git a/openapi_patch.yaml b/openapi_patch.yaml index 57b0dca..4d92d33 100644 --- a/openapi_patch.yaml +++ b/openapi_patch.yaml @@ -65,43 +65,6 @@ components: properties: integration_type: $ref: "#/components/schemas/ServiceCreateRequestBody/properties/service_integrations/items/properties/integration_type" - ServiceKafkaMirrorMakerCreateReplicationFlowRequestBody: - properties: - topics.blacklist: - type: array - items: - type: string - ServiceKafkaMirrorMakerGetReplicationFlowResponse: - properties: - replication_flow: - properties: - topics.blacklist: - type: array - items: - type: string - ServiceKafkaMirrorMakerGetReplicationFlowsResponse: - properties: - replication_flows: - items: - properties: - topics.blacklist: - type: array - items: - type: string - ServiceKafkaMirrorMakerPatchReplicationFlowRequestBody: - properties: - topics.blacklist: - type: array - items: - type: string - ServiceKafkaMirrorMakerPatchReplicationFlowResponse: - properties: - replication_flow: - properties: - topics.blacklist: - type: array - items: - type: string ServiceGetResponse: properties: service: