diff --git a/internal/pkg/ds/app.go b/internal/pkg/ds/app.go index 861415d..4601467 100644 --- a/internal/pkg/ds/app.go +++ b/internal/pkg/ds/app.go @@ -360,8 +360,9 @@ type FlagDeclaration struct { } type PartialFieldDeclaration struct { - Name string // Имя части поля - Type string // Тип части поля + Name string // Имя части поля + Type string // Тип части поля + MappingKeyName string // Имя ключа в мепе модифицированных полей } type LinkedPackageDeclaration struct { diff --git a/internal/pkg/generator/tmpl/octopus/main.tmpl b/internal/pkg/generator/tmpl/octopus/main.tmpl index 17f0135..636037b 100644 --- a/internal/pkg/generator/tmpl/octopus/main.tmpl +++ b/internal/pkg/generator/tmpl/octopus/main.tmpl @@ -660,7 +660,7 @@ func (obj *{{ $PublicStructName }}) pack{{ $fstruct.Name }}PartialFields(op octo {{ range $i, $f := $customMutator.PartialFields }} func (obj *{{ $PublicStructName }}) Set{{ $customMutator.Name }}{{ $f.Name }}({{ $f.Name }} {{ $f.Type }}) error { - obj.Mutators.{{ $customMutator.Name }}.PartialFields["{{ $f.Name }}"] = {{ $f.Name }} + obj.Mutators.{{ $customMutator.Name }}.PartialFields["{{ $f.MappingKeyName }}"] = {{ $f.Name }} if err := obj.pack{{ $fstruct.Name }}PartialFields(octopus.OpUpdate); err != nil { return fmt.Errorf("pack {{ $customMutator.Name }}{{ $f.Name }}: %w", err) diff --git a/internal/pkg/parser/mutator_b_test.go b/internal/pkg/parser/mutator_b_test.go index 135be17..ba1a41d 100644 --- a/internal/pkg/parser/mutator_b_test.go +++ b/internal/pkg/parser/mutator_b_test.go @@ -81,10 +81,10 @@ func TestParseMutator(t *testing.T) { Update: "updateFunc,param1,param2", Replace: "replaceFunc", PartialFields: []ds.PartialFieldDeclaration{ - {Name: "Key", Type: "string"}, - {Name: "Bar", Type: "ds.AppInfo"}, - {Name: "BeerData", Type: "[]foo.Beer"}, - {Name: "MapData", Type: "map[string]any"}, + {Name: "Key", Type: "string", MappingKeyName: "Key"}, + {Name: "Bar", Type: "ds.AppInfo", MappingKeyName: "Bar"}, + {Name: "BeerData", Type: "[]foo.Beer", MappingKeyName: "beer_data"}, + {Name: "MapData", Type: "map[string]any", MappingKeyName: "MapData"}, }, }, "SimpleTypeMutatorField": { @@ -145,18 +145,18 @@ func TestParseMutator(t *testing.T) { }, ImportStructFieldsMap: map[string][]ds.PartialFieldDeclaration{ "ds.AppInfo": { - {Name: "appName", Type: "string"}, - {Name: "version", Type: "string"}, - {Name: "buildTime", Type: "string"}, - {Name: "buildOS", Type: "string"}, - {Name: "buildCommit", Type: "string"}, - {Name: "generateTime", Type: "string"}, + {Name: "appName", Type: "string", MappingKeyName: "appName"}, + {Name: "version", Type: "string", MappingKeyName: "version"}, + {Name: "buildTime", Type: "string", MappingKeyName: "buildTime"}, + {Name: "buildOS", Type: "string", MappingKeyName: "buildOS"}, + {Name: "buildCommit", Type: "string", MappingKeyName: "buildCommit"}, + {Name: "generateTime", Type: "string", MappingKeyName: "generateTime"}, }, "foo.Foo": { - {Name: "Key", Type: "string"}, - {Name: "Bar", Type: "ds.AppInfo"}, - {Name: "BeerData", Type: "[]foo.Beer"}, - {Name: "MapData", Type: "map[string]any"}, + {Name: "Key", Type: "string", MappingKeyName: "Key"}, + {Name: "Bar", Type: "ds.AppInfo", MappingKeyName: "Bar"}, + {Name: "BeerData", Type: "[]foo.Beer", MappingKeyName: "beer_data"}, + {Name: "MapData", Type: "map[string]any", MappingKeyName: "MapData"}, }, }, }, diff --git a/internal/pkg/parser/partialstruct.go b/internal/pkg/parser/partialstruct.go index 67e55ca..5e5c46e 100644 --- a/internal/pkg/parser/partialstruct.go +++ b/internal/pkg/parser/partialstruct.go @@ -6,6 +6,7 @@ import ( "go/parser" "go/token" "path/filepath" + "strings" "github.com/mailru/activerecord/internal/pkg/arerror" "github.com/mailru/activerecord/internal/pkg/ds" @@ -35,14 +36,24 @@ func parseStructFields(dst *ds.RecordPackage, gen *ast.GenDecl, name, pkgName st continue } + fName, ignore, err := parseTag(field) + if err != nil { + return nil, &arerror.ErrParseTypeStructDecl{Name: currType.Name.Name, Err: err} + } + + if ignore { + continue + } + t, err := ParseFieldType(dst, name, pkgName, field.Type) if err != nil { return nil, &arerror.ErrParseTypeFieldStructDecl{Name: name, FieldType: field.Names[0].Name, Err: err} } field := ds.PartialFieldDeclaration{ - Name: field.Names[0].Name, - Type: t, + Name: field.Names[0].Name, + Type: t, + MappingKeyName: fName, } partialFields = append(partialFields, field) @@ -55,6 +66,28 @@ func parseStructFields(dst *ds.RecordPackage, gen *ast.GenDecl, name, pkgName st return nil, nil } +// parseTag parse tag with format `ar: "name,[ignore]"`. tag is optional +func parseTag(field *ast.Field) (name string, ignore bool, err error) { + name = field.Names[0].Name + + if field.Tag == nil { + return name, false, nil + } + + tagParam, parseErr := splitTag(field, NoCheckFlag, map[TagNameType]ParamValueRule{}) + if parseErr != nil { + return "", false, parseErr + } + + if len(tagParam) > 0 { + k := strings.Split(tagParam[0][0], ",") + name = k[0] + ignore = len(k) > 1 && strings.Contains(tagParam[0][0], "ignore") + } + + return name, ignore, err +} + func ParsePartialStructFields(dst *ds.RecordPackage, name, pkgName, path string) ([]ds.PartialFieldDeclaration, error) { relPath, err := filepath.Rel(dst.Namespace.ModuleName, path) if err != nil { diff --git a/internal/pkg/parser/partialstruct_test.go b/internal/pkg/parser/partialstruct_test.go index d5a0542..363be45 100644 --- a/internal/pkg/parser/partialstruct_test.go +++ b/internal/pkg/parser/partialstruct_test.go @@ -8,7 +8,9 @@ import ( ) type Foo struct { - Bar int + Bar int `ar:"bar"` + Other string `ar:"bar,ignore"` + Other2 string `ar:",ignore"` } func TestParsePartialStructFields(t *testing.T) { @@ -41,7 +43,7 @@ func TestParsePartialStructFields(t *testing.T) { path: ".", }, want: []ds.PartialFieldDeclaration{ - {Name: "Bar", Type: "int"}, + {Name: "Bar", Type: "int", MappingKeyName: "bar"}, }, wantErr: false, }, diff --git a/internal/pkg/parser/testdata/foo/foo.go b/internal/pkg/parser/testdata/foo/foo.go index f706749..16dd19a 100644 --- a/internal/pkg/parser/testdata/foo/foo.go +++ b/internal/pkg/parser/testdata/foo/foo.go @@ -7,6 +7,7 @@ type Beer struct{} type Foo struct { Key string Bar ds.AppInfo - BeerData []Beer + BeerData []Beer `ar:"beer_data"` MapData map[string]any + Other map[string]any `ar:",ignore"` } diff --git a/internal/pkg/parser/utils.go b/internal/pkg/parser/utils.go index dfaa226..ba8a5c2 100644 --- a/internal/pkg/parser/utils.go +++ b/internal/pkg/parser/utils.go @@ -68,15 +68,31 @@ func splitTag(field *ast.Field, checkFlag uint32, rule map[TagNameType]ParamValu return nil, arerror.ErrParseTagSplitAbsent } - if !strings.HasPrefix(field.Tag.Value, "`ar:\"") { + tag := searchARTag(field) + + if checkFlag&NoCheckFlag != 0 && tag == "" { + return [][]string{}, nil + } + + if checkFlag&CheckFlagEmpty != 0 && (tag == "" || tag == "`ar:\"\"`") { return nil, arerror.ErrParseTagInvalidFormat } - if checkFlag&CheckFlagEmpty != 0 && field.Tag.Value == "`ar:\"\"`" { - return nil, arerror.ErrParseTagSplitEmpty + idx := strings.LastIndex(tag, "ar:\"") + + return splitParam(tag[idx+3:len(tag)-1], rule) +} + +func searchARTag(field *ast.Field) string { + tags := strings.Split(field.Tag.Value, " ") + + for _, tag := range tags { + if strings.Contains(tag, "ar:\"") { + return tag + } } - return splitParam(field.Tag.Value[4:len(field.Tag.Value)-1], rule) + return "" } func splitParam(str string, rule map[TagNameType]ParamValueRule) ([][]string, error) { diff --git a/internal/pkg/parser/utils_w_test.go b/internal/pkg/parser/utils_w_test.go index f0dd1a5..84c811c 100644 --- a/internal/pkg/parser/utils_w_test.go +++ b/internal/pkg/parser/utils_w_test.go @@ -176,8 +176,9 @@ func Test_splitTag(t *testing.T) { { name: "emptytag", wantErr: false, args: args{ - field: &ast.Field{Tag: &ast.BasicLit{Value: "`ar:\"\"`"}}, - rule: map[TagNameType]ParamValueRule{}, + field: &ast.Field{Tag: &ast.BasicLit{Value: "`ar:\"\"`"}}, + rule: map[TagNameType]ParamValueRule{}, + checkFlag: NoCheckFlag, }, want: [][]string{}, }, @@ -193,16 +194,18 @@ func Test_splitTag(t *testing.T) { { name: "tagnoprefix", wantErr: true, args: args{ - field: &ast.Field{Tag: &ast.BasicLit{Value: "dsjfgsadkjgfdskj"}}, - rule: map[TagNameType]ParamValueRule{}, + field: &ast.Field{Tag: &ast.BasicLit{Value: "dsjfgsadkjgfdskj"}}, + checkFlag: CheckFlagEmpty, + rule: map[TagNameType]ParamValueRule{}, }, want: nil, }, { name: "tag", wantErr: false, args: args{ - field: &ast.Field{Tag: &ast.BasicLit{Value: "`ar:\"a:b;c:d;d:r,t\"`"}}, - rule: map[TagNameType]ParamValueRule{}, + field: &ast.Field{Tag: &ast.BasicLit{Value: "`ar:\"a:b;c:d;d:r,t\"`"}}, + rule: map[TagNameType]ParamValueRule{}, + checkFlag: CheckFlagEmpty, }, want: [][]string{{"a", "b"}, {"c", "d"}, {"d", "r,t"}}, },