Fix struct tag with spaces as values (#36)

This commit is contained in:
sunboyy 2023-04-19 19:42:08 +07:00 committed by GitHub
parent bdb63c8129
commit 021de6214c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 38 additions and 86 deletions

View file

@ -3,6 +3,7 @@ package code
import ( import (
"fmt" "fmt"
"go/ast" "go/ast"
"reflect"
"strconv" "strconv"
"strings" "strings"
) )
@ -60,7 +61,7 @@ func extractStructType(name string, structType *ast.StructType) Struct {
} }
strField.Type = getType(field.Type) strField.Type = getType(field.Type)
if field.Tag != nil { if field.Tag != nil {
strField.Tags = extractStructTag(field.Tag.Value) strField.Tag = extractStructTag(field.Tag.Value)
} }
str.Fields = append(str.Fields, strField) str.Fields = append(str.Fields, strField)
@ -103,26 +104,8 @@ func extractInterfaceType(name string, interfaceType *ast.InterfaceType) Interfa
return intf return intf
} }
func extractStructTag(tagValue string) map[string][]string { func extractStructTag(tagValue string) reflect.StructTag {
tagTokens := strings.Fields(tagValue[1 : len(tagValue)-1]) return reflect.StructTag(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 extractFunction(name string, comments []string, funcType *ast.FuncType) Method { func extractFunction(name string, comments []string, funcType *ast.FuncType) Method {

View file

@ -61,6 +61,7 @@ import (
type UserModel struct { type UserModel struct {
ID primitive.ObjectID ` + "`bson:\"_id,omitempty\" json:\"id\"`" + ` ID primitive.ObjectID ` + "`bson:\"_id,omitempty\" json:\"id\"`" + `
Username string ` + "`bson:\"username\" json:\"username\"`" + ` Username string ` + "`bson:\"username\" json:\"username\"`" + `
Password string ` + "`bson:\"password\" json:\"-\" note:\"This should be hidden.\"`" + `
}`, }`,
ExpectedOutput: code.File{ ExpectedOutput: code.File{
PackageName: "user", PackageName: "user",
@ -71,18 +72,17 @@ type UserModel struct {
code.StructField{ code.StructField{
Name: "ID", Name: "ID",
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
Tags: map[string][]string{ Tag: `bson:"_id,omitempty" json:"id"`,
"bson": {"_id", "omitempty"},
"json": {"id"},
},
}, },
code.StructField{ code.StructField{
Name: "Username", Name: "Username",
Type: code.TypeString, Type: code.TypeString,
Tags: map[string][]string{ Tag: `bson:"username" json:"username"`,
"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{ code.StructField{
Name: "ID", Name: "ID",
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
Tags: map[string][]string{ Tag: `bson:"_id,omitempty" json:"id"`,
"bson": {"_id", "omitempty"},
"json": {"id"},
},
}, },
code.StructField{ code.StructField{
Name: "Username", Name: "Username",
Type: code.TypeString, Type: code.TypeString,
Tags: map[string][]string{ Tag: `bson:"username" json:"username"`,
"bson": {"username"},
"json": {"username"},
},
}, },
}, },
}, },

View file

@ -2,6 +2,7 @@ package code
import ( import (
"fmt" "fmt"
"reflect"
) )
// File is a container of all required components for code generation in the file // 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 { type StructField struct {
Name string Name string
Type Type Type Type
Tags map[string][]string Tag reflect.StructTag
} }
// InterfaceType is a definition of the interface // InterfaceType is a definition of the interface

View file

@ -62,10 +62,7 @@ func TestBuilderBuild(t *testing.T) {
PackageAlias: "primitive", PackageAlias: "primitive",
Name: "ObjectID", Name: "ObjectID",
}, },
Tags: map[string][]string{ Tag: `bson:"id" json:"id,omitempty"`,
"bson": {"id"},
"json": {"id", "omitempty"},
},
}, },
{ {
Name: "Username", Name: "Username",

View file

@ -3,7 +3,6 @@ package codegen
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"sort"
"strings" "strings"
"text/template" "text/template"
@ -39,25 +38,10 @@ func (sb StructBuilder) GenFields() string {
var fieldLines []string var fieldLines []string
for _, field := range sb.Fields { for _, field := range sb.Fields {
fieldLine := fmt.Sprintf("\t%s %s", field.Name, field.Type.Code()) fieldLine := fmt.Sprintf("\t%s %s", field.Name, field.Type.Code())
if len(field.Tags) > 0 { if len(field.Tag) > 0 {
fieldLine += fmt.Sprintf(" `%s`", sb.generateStructTag(field.Tags)) fieldLine += fmt.Sprintf(" `%s`", string(field.Tag))
} }
fieldLines = append(fieldLines, fieldLine) fieldLines = append(fieldLines, fieldLine)
} }
return strings.Join(fieldLines, "\n") 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, " ")
}

View file

@ -28,25 +28,17 @@ func TestStructBuilderBuild(t *testing.T) {
PackageAlias: "primitive", PackageAlias: "primitive",
Name: "ObjectID", Name: "ObjectID",
}, },
Tags: map[string][]string{ Tag: `bson:"id,omitempty" json:"id,omitempty"`,
"json": {"id", "omitempty"},
"bson": {"id", "omitempty"},
},
}, },
{ {
Name: "Username", Name: "Username",
Type: code.TypeString, Type: code.TypeString,
Tags: map[string][]string{ Tag: `bson:"username" json:"username"`,
"json": {"username"},
"bson": {"username"},
},
}, },
{ {
Name: "Age", Name: "Age",
Type: code.TypeInt, Type: code.TypeInt,
Tags: map[string][]string{ Tag: `bson:"age"`,
"bson": {"age"},
},
}, },
{ {
Name: "orderCount", Name: "orderCount",

View file

@ -14,17 +14,17 @@ var (
idField = code.StructField{ idField = code.StructField{
Name: "ID", Name: "ID",
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
Tags: map[string][]string{"bson": {"_id", "omitempty"}}, Tag: `bson:"_id,omitempty"`,
} }
genderField = code.StructField{ genderField = code.StructField{
Name: "Gender", Name: "Gender",
Type: code.SimpleType("Gender"), Type: code.SimpleType("Gender"),
Tags: map[string][]string{"bson": {"gender"}}, Tag: `bson:"gender"`,
} }
ageField = code.StructField{ ageField = code.StructField{
Name: "Age", Name: "Age",
Type: code.TypeInt, Type: code.TypeInt,
Tags: map[string][]string{"bson": {"age"}}, Tag: `bson:"age"`,
} }
) )
@ -36,7 +36,7 @@ func TestGenerateMongoRepository(t *testing.T) {
code.StructField{ code.StructField{
Name: "Username", Name: "Username",
Type: code.TypeString, Type: code.TypeString,
Tags: map[string][]string{"bson": {"username"}}, Tag: `bson:"username"`,
}, },
genderField, genderField,
ageField, ageField,

View file

@ -63,12 +63,13 @@ func (g baseMethodGenerator) bsonFieldReference(fieldReference spec.FieldReferen
} }
func (g baseMethodGenerator) bsonTagFromField(field code.StructField) (string, error) { func (g baseMethodGenerator) bsonTagFromField(field code.StructField) (string, error) {
bsonTag, ok := field.Tags["bson"] bsonTag, ok := field.Tag.Lookup("bson")
if !ok { if !ok {
return "", NewBsonTagNotFoundError(field.Name) 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) { func (g baseMethodGenerator) convertQuerySpec(query spec.QuerySpec) (querySpec, error) {

View file

@ -15,37 +15,37 @@ var (
idField = code.StructField{ idField = code.StructField{
Name: "ID", Name: "ID",
Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"}, Type: code.ExternalType{PackageAlias: "primitive", Name: "ObjectID"},
Tags: map[string][]string{"bson": {"_id", "omitempty"}}, Tag: `bson:"_id,omitempty"`,
} }
genderField = code.StructField{ genderField = code.StructField{
Name: "Gender", Name: "Gender",
Type: code.SimpleType("Gender"), Type: code.SimpleType("Gender"),
Tags: map[string][]string{"bson": {"gender"}}, Tag: `bson:"gender"`,
} }
ageField = code.StructField{ ageField = code.StructField{
Name: "Age", Name: "Age",
Type: code.TypeInt, Type: code.TypeInt,
Tags: map[string][]string{"bson": {"age"}}, Tag: `bson:"age"`,
} }
nameField = code.StructField{ nameField = code.StructField{
Name: "Name", Name: "Name",
Type: code.SimpleType("NameModel"), Type: code.SimpleType("NameModel"),
Tags: map[string][]string{"bson": {"name"}}, Tag: `bson:"name"`,
} }
referrerField = code.StructField{ referrerField = code.StructField{
Name: "Referrer", Name: "Referrer",
Type: code.PointerType{ContainedType: code.SimpleType("UserModel")}, Type: code.PointerType{ContainedType: code.SimpleType("UserModel")},
Tags: map[string][]string{"bson": {"referrer"}}, Tag: `bson:"referrer"`,
} }
consentHistoryField = code.StructField{ consentHistoryField = code.StructField{
Name: "ConsentHistory", Name: "ConsentHistory",
Type: code.ArrayType{ContainedType: code.SimpleType("ConsentHistory")}, Type: code.ArrayType{ContainedType: code.SimpleType("ConsentHistory")},
Tags: map[string][]string{"bson": {"consent_history"}}, Tag: `bson:"consent_history"`,
} }
enabledField = code.StructField{ enabledField = code.StructField{
Name: "Enabled", Name: "Enabled",
Type: code.TypeBool, Type: code.TypeBool,
Tags: map[string][]string{"bson": {"enabled"}}, Tag: `bson:"enabled"`,
} }
accessTokenField = code.StructField{ accessTokenField = code.StructField{
Name: "AccessToken", Name: "AccessToken",
@ -55,7 +55,7 @@ var (
firstNameField = code.StructField{ firstNameField = code.StructField{
Name: "First", Name: "First",
Type: code.TypeString, Type: code.TypeString,
Tags: map[string][]string{"bson": {"first"}}, Tag: `bson:"first"`,
} }
) )
@ -66,7 +66,7 @@ var userModel = code.Struct{
code.StructField{ code.StructField{
Name: "Username", Name: "Username",
Type: code.TypeString, Type: code.TypeString,
Tags: map[string][]string{"bson": {"username"}}, Tag: `bson:"username"`,
}, },
genderField, genderField,
ageField, ageField,