From 021de6214c6eeb8af58d62d9ebe6549686577509 Mon Sep 17 00:00:00 2001 From: sunboyy Date: Wed, 19 Apr 2023 19:42:08 +0700 Subject: [PATCH] Fix struct tag with spaces as values (#36) --- internal/code/extractor.go | 25 ++++--------------------- internal/code/extractor_test.go | 26 ++++++++++---------------- internal/code/models.go | 3 ++- internal/codegen/builder_test.go | 5 +---- internal/codegen/struct.go | 20 ++------------------ internal/codegen/struct_test.go | 14 +++----------- internal/generator/generator_test.go | 8 ++++---- internal/mongo/common.go | 5 +++-- internal/mongo/generator_test.go | 18 +++++++++--------- 9 files changed, 38 insertions(+), 86 deletions(-) diff --git a/internal/code/extractor.go b/internal/code/extractor.go index 7235f54..428954a 100644 --- a/internal/code/extractor.go +++ b/internal/code/extractor.go @@ -3,6 +3,7 @@ package code import ( "fmt" "go/ast" + "reflect" "strconv" "strings" ) @@ -60,7 +61,7 @@ func extractStructType(name string, structType *ast.StructType) Struct { } strField.Type = getType(field.Type) if field.Tag != nil { - strField.Tags = extractStructTag(field.Tag.Value) + strField.Tag = extractStructTag(field.Tag.Value) } str.Fields = append(str.Fields, strField) @@ -103,26 +104,8 @@ func extractInterfaceType(name string, interfaceType *ast.InterfaceType) Interfa return intf } -func extractStructTag(tagValue string) map[string][]string { - tagTokens := strings.Fields(tagValue[1 : len(tagValue)-1]) - - tags := make(map[string][]string) - for _, tagToken := range tagTokens { - colonIndex := strings.Index(tagToken, ":") - if colonIndex == -1 { - continue - } - tagKey := tagToken[:colonIndex] - tagValue, err := strconv.Unquote(tagToken[colonIndex+1:]) - if err != nil { - fmt.Printf("cannot unquote struct tag %s : %s\n", tagToken[colonIndex+1:], err) - continue - } - tagValues := strings.Split(tagValue, ",") - tags[tagKey] = tagValues - } - - return tags +func extractStructTag(tagValue string) reflect.StructTag { + return reflect.StructTag(tagValue[1 : len(tagValue)-1]) } func extractFunction(name string, comments []string, funcType *ast.FuncType) Method { diff --git a/internal/code/extractor_test.go b/internal/code/extractor_test.go index 3106cda..6e03c3b 100644 --- a/internal/code/extractor_test.go +++ b/internal/code/extractor_test.go @@ -61,6 +61,7 @@ import ( type UserModel struct { ID primitive.ObjectID ` + "`bson:\"_id,omitempty\" json:\"id\"`" + ` Username string ` + "`bson:\"username\" json:\"username\"`" + ` + Password string ` + "`bson:\"password\" json:\"-\" note:\"This should be hidden.\"`" + ` }`, ExpectedOutput: code.File{ PackageName: "user", @@ -71,18 +72,17 @@ type UserModel struct { code.StructField{ Name: "ID", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, - Tags: map[string][]string{ - "bson": {"_id", "omitempty"}, - "json": {"id"}, - }, + Tag: `bson:"_id,omitempty" json:"id"`, }, code.StructField{ Name: "Username", Type: code.TypeString, - Tags: map[string][]string{ - "bson": {"username"}, - "json": {"username"}, - }, + Tag: `bson:"username" json:"username"`, + }, + code.StructField{ + Name: "Password", + Type: code.TypeString, + Tag: `bson:"password" json:"-" note:"This should be hidden."`, }, }, }, @@ -268,18 +268,12 @@ type UserRepository interface { code.StructField{ Name: "ID", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, - Tags: map[string][]string{ - "bson": {"_id", "omitempty"}, - "json": {"id"}, - }, + Tag: `bson:"_id,omitempty" json:"id"`, }, code.StructField{ Name: "Username", Type: code.TypeString, - Tags: map[string][]string{ - "bson": {"username"}, - "json": {"username"}, - }, + Tag: `bson:"username" json:"username"`, }, }, }, diff --git a/internal/code/models.go b/internal/code/models.go index 1ecc762..9320264 100644 --- a/internal/code/models.go +++ b/internal/code/models.go @@ -2,6 +2,7 @@ package code import ( "fmt" + "reflect" ) // File is a container of all required components for code generation in the file @@ -46,7 +47,7 @@ func (fields StructFields) ByName(name string) (StructField, bool) { type StructField struct { Name string Type Type - Tags map[string][]string + Tag reflect.StructTag } // InterfaceType is a definition of the interface diff --git a/internal/codegen/builder_test.go b/internal/codegen/builder_test.go index 194730e..84c0849 100644 --- a/internal/codegen/builder_test.go +++ b/internal/codegen/builder_test.go @@ -62,10 +62,7 @@ func TestBuilderBuild(t *testing.T) { PackageAlias: "primitive", Name: "ObjectID", }, - Tags: map[string][]string{ - "bson": {"id"}, - "json": {"id", "omitempty"}, - }, + Tag: `bson:"id" json:"id,omitempty"`, }, { Name: "Username", diff --git a/internal/codegen/struct.go b/internal/codegen/struct.go index 300468d..82530a6 100644 --- a/internal/codegen/struct.go +++ b/internal/codegen/struct.go @@ -3,7 +3,6 @@ package codegen import ( "bytes" "fmt" - "sort" "strings" "text/template" @@ -39,25 +38,10 @@ func (sb StructBuilder) GenFields() string { var fieldLines []string for _, field := range sb.Fields { fieldLine := fmt.Sprintf("\t%s %s", field.Name, field.Type.Code()) - if len(field.Tags) > 0 { - fieldLine += fmt.Sprintf(" `%s`", sb.generateStructTag(field.Tags)) + if len(field.Tag) > 0 { + fieldLine += fmt.Sprintf(" `%s`", string(field.Tag)) } fieldLines = append(fieldLines, fieldLine) } return strings.Join(fieldLines, "\n") } - -func (sb StructBuilder) generateStructTag(tags map[string][]string) string { - var tagKeys []string - for key := range tags { - tagKeys = append(tagKeys, key) - } - sort.Strings(tagKeys) - - var tagGroups []string - for _, key := range tagKeys { - tagValue := strings.Join(tags[key], ",") - tagGroups = append(tagGroups, fmt.Sprintf("%s:\"%s\"", key, tagValue)) - } - return strings.Join(tagGroups, " ") -} diff --git a/internal/codegen/struct_test.go b/internal/codegen/struct_test.go index 588366c..c51697b 100644 --- a/internal/codegen/struct_test.go +++ b/internal/codegen/struct_test.go @@ -28,25 +28,17 @@ func TestStructBuilderBuild(t *testing.T) { PackageAlias: "primitive", Name: "ObjectID", }, - Tags: map[string][]string{ - "json": {"id", "omitempty"}, - "bson": {"id", "omitempty"}, - }, + Tag: `bson:"id,omitempty" json:"id,omitempty"`, }, { Name: "Username", Type: code.TypeString, - Tags: map[string][]string{ - "json": {"username"}, - "bson": {"username"}, - }, + Tag: `bson:"username" json:"username"`, }, { Name: "Age", Type: code.TypeInt, - Tags: map[string][]string{ - "bson": {"age"}, - }, + Tag: `bson:"age"`, }, { Name: "orderCount", diff --git a/internal/generator/generator_test.go b/internal/generator/generator_test.go index 35506fd..dc051a4 100644 --- a/internal/generator/generator_test.go +++ b/internal/generator/generator_test.go @@ -14,17 +14,17 @@ var ( idField = code.StructField{ Name: "ID", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, - Tags: map[string][]string{"bson": {"_id", "omitempty"}}, + Tag: `bson:"_id,omitempty"`, } genderField = code.StructField{ Name: "Gender", Type: code.SimpleType("Gender"), - Tags: map[string][]string{"bson": {"gender"}}, + Tag: `bson:"gender"`, } ageField = code.StructField{ Name: "Age", Type: code.TypeInt, - Tags: map[string][]string{"bson": {"age"}}, + Tag: `bson:"age"`, } ) @@ -36,7 +36,7 @@ func TestGenerateMongoRepository(t *testing.T) { code.StructField{ Name: "Username", Type: code.TypeString, - Tags: map[string][]string{"bson": {"username"}}, + Tag: `bson:"username"`, }, genderField, ageField, diff --git a/internal/mongo/common.go b/internal/mongo/common.go index 23ecef4..bc8992a 100644 --- a/internal/mongo/common.go +++ b/internal/mongo/common.go @@ -63,12 +63,13 @@ func (g baseMethodGenerator) bsonFieldReference(fieldReference spec.FieldReferen } func (g baseMethodGenerator) bsonTagFromField(field code.StructField) (string, error) { - bsonTag, ok := field.Tags["bson"] + bsonTag, ok := field.Tag.Lookup("bson") if !ok { return "", NewBsonTagNotFoundError(field.Name) } - return bsonTag[0], nil + documentKey := strings.Split(bsonTag, ",")[0] + return documentKey, nil } func (g baseMethodGenerator) convertQuerySpec(query spec.QuerySpec) (querySpec, error) { diff --git a/internal/mongo/generator_test.go b/internal/mongo/generator_test.go index 34900f8..9904a2b 100644 --- a/internal/mongo/generator_test.go +++ b/internal/mongo/generator_test.go @@ -15,37 +15,37 @@ var ( idField = code.StructField{ Name: "ID", Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, - Tags: map[string][]string{"bson": {"_id", "omitempty"}}, + Tag: `bson:"_id,omitempty"`, } genderField = code.StructField{ Name: "Gender", Type: code.SimpleType("Gender"), - Tags: map[string][]string{"bson": {"gender"}}, + Tag: `bson:"gender"`, } ageField = code.StructField{ Name: "Age", Type: code.TypeInt, - Tags: map[string][]string{"bson": {"age"}}, + Tag: `bson:"age"`, } nameField = code.StructField{ Name: "Name", Type: code.SimpleType("NameModel"), - Tags: map[string][]string{"bson": {"name"}}, + Tag: `bson:"name"`, } referrerField = code.StructField{ Name: "Referrer", Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}, - Tags: map[string][]string{"bson": {"referrer"}}, + Tag: `bson:"referrer"`, } consentHistoryField = code.StructField{ Name: "ConsentHistory", Type: code.ArrayType{ContainedType: code.SimpleType("ConsentHistory")}, - Tags: map[string][]string{"bson": {"consent_history"}}, + Tag: `bson:"consent_history"`, } enabledField = code.StructField{ Name: "Enabled", Type: code.TypeBool, - Tags: map[string][]string{"bson": {"enabled"}}, + Tag: `bson:"enabled"`, } accessTokenField = code.StructField{ Name: "AccessToken", @@ -55,7 +55,7 @@ var ( firstNameField = code.StructField{ Name: "First", Type: code.TypeString, - Tags: map[string][]string{"bson": {"first"}}, + Tag: `bson:"first"`, } ) @@ -66,7 +66,7 @@ var userModel = code.Struct{ code.StructField{ Name: "Username", Type: code.TypeString, - Tags: map[string][]string{"bson": {"username"}}, + Tag: `bson:"username"`, }, genderField, ageField,