From 5da91b52f943734c7af2e5dcd79b91b566f15803 Mon Sep 17 00:00:00 2001 From: earlgray Date: Sat, 29 Mar 2025 19:45:29 +0900 Subject: [PATCH 1/5] feat: support go normal struct --- internal/gen/generator.go | 2 +- internal/gen/structs/structs.go | 89 +++++++++++++++++++ internal/gen/util.go | 13 ++- internal/templates/structs.go.tmpl | 35 ++++++++ internal/templates/structs_common.go.tmpl | 3 + internal/templates/templates.go | 14 +-- test/fixgen_test.go | 14 +-- test/structs/test/go.mod | 7 ++ test/structs/test/go.sum | 12 +++ test/structs/test/models/todo.go | 13 +++ test/structs/test/models/user.go | 12 +++ .../test/testdata-context/goldie-common.go | 8 ++ .../testdata-context/goldie-structs_common.go | 9 ++ .../test/testdata-context/goldie-todo.go | 56 ++++++++++++ .../test/testdata-context/goldie-user.go | 53 +++++++++++ .../test/testdata-math-v1/goldie-common.go | 8 ++ .../testdata-math-v1/goldie-structs_common.go | 9 ++ .../test/testdata-math-v1/goldie-todo.go | 56 ++++++++++++ .../test/testdata-math-v1/goldie-user.go | 53 +++++++++++ .../testdata-value-modifier/goldie-common.go | 8 ++ .../goldie-structs_common.go | 9 ++ .../testdata-value-modifier/goldie-todo.go | 56 ++++++++++++ .../testdata-value-modifier/goldie-user.go | 53 +++++++++++ .../test/testdata-zero/goldie-common.go | 8 ++ .../testdata-zero/goldie-structs_common.go | 9 ++ .../structs/test/testdata-zero/goldie-todo.go | 53 +++++++++++ .../structs/test/testdata-zero/goldie-user.go | 52 +++++++++++ test/structs/test/testdata/goldie-common.go | 8 ++ .../test/testdata/goldie-structs_common.go | 9 ++ test/structs/test/testdata/goldie-todo.go | 56 ++++++++++++ test/structs/test/testdata/goldie-user.go | 53 +++++++++++ 31 files changed, 826 insertions(+), 14 deletions(-) create mode 100644 internal/gen/structs/structs.go create mode 100644 internal/templates/structs.go.tmpl create mode 100644 internal/templates/structs_common.go.tmpl create mode 100644 test/structs/test/go.mod create mode 100644 test/structs/test/go.sum create mode 100644 test/structs/test/models/todo.go create mode 100644 test/structs/test/models/user.go create mode 100644 test/structs/test/testdata-context/goldie-common.go create mode 100644 test/structs/test/testdata-context/goldie-structs_common.go create mode 100644 test/structs/test/testdata-context/goldie-todo.go create mode 100644 test/structs/test/testdata-context/goldie-user.go create mode 100644 test/structs/test/testdata-math-v1/goldie-common.go create mode 100644 test/structs/test/testdata-math-v1/goldie-structs_common.go create mode 100644 test/structs/test/testdata-math-v1/goldie-todo.go create mode 100644 test/structs/test/testdata-math-v1/goldie-user.go create mode 100644 test/structs/test/testdata-value-modifier/goldie-common.go create mode 100644 test/structs/test/testdata-value-modifier/goldie-structs_common.go create mode 100644 test/structs/test/testdata-value-modifier/goldie-todo.go create mode 100644 test/structs/test/testdata-value-modifier/goldie-user.go create mode 100644 test/structs/test/testdata-zero/goldie-common.go create mode 100644 test/structs/test/testdata-zero/goldie-structs_common.go create mode 100644 test/structs/test/testdata-zero/goldie-todo.go create mode 100644 test/structs/test/testdata-zero/goldie-user.go create mode 100644 test/structs/test/testdata/goldie-common.go create mode 100644 test/structs/test/testdata/goldie-structs_common.go create mode 100644 test/structs/test/testdata/goldie-todo.go create mode 100644 test/structs/test/testdata/goldie-user.go diff --git a/internal/gen/generator.go b/internal/gen/generator.go index e9cd17f..b7dc905 100644 --- a/internal/gen/generator.go +++ b/internal/gen/generator.go @@ -78,7 +78,7 @@ func GenerateWithFormat[G Generator](g G, c *config.Config, opts ...OptionFunc) for _, f := range files { content, err := Format(append(header, f.Content...)) if err != nil { - return nil, fmt.Errorf("failed to Format: %+w", err) + return nil, fmt.Errorf("failed to Format(%s): %+w", f.Name, err) } f.Content = content } diff --git a/internal/gen/structs/structs.go b/internal/gen/structs/structs.go new file mode 100644 index 0000000..663c455 --- /dev/null +++ b/internal/gen/structs/structs.go @@ -0,0 +1,89 @@ +package datastore + +import ( + "fmt" + "maps" + "strings" + + "github.com/earlgray283/fixgen/internal/caseconv" + "github.com/earlgray283/fixgen/internal/gen" + "github.com/earlgray283/fixgen/internal/load" + "github.com/earlgray283/fixgen/internal/templates" +) + +type Generator struct { + packagePath string + dirPath string + filepaths []string +} + +var _ gen.Generator = (*Generator)(nil) + +func NewGenerator(workDir, packageDirPath string) (*Generator, error) { + goModulePath, err := gen.LoadGoModulePath(workDir) + if err != nil { + return nil, fmt.Errorf("failed to load go module path: %+w", err) + } + + filepaths, err := gen.ReadDir(packageDirPath) + if err != nil { + return nil, fmt.Errorf("failed to read dir: %+w", err) + } + + return &Generator{ + packagePath: strings.Join([]string{goModulePath, packageDirPath}, "/"), + dirPath: packageDirPath, + filepaths: filepaths, + }, nil +} + +// Generate implements gen.Generator. +func (g *Generator) Generate(structInfos []*load.StructInfo, data map[string]any) ([]*gen.File, error) { + files := make([]*gen.File, 0, len(structInfos)+1) + + content, err := templates.Execute(templates.TmplStructsCommonFile, nil) + if err != nil { + return nil, err + } + files = append(files, &gen.File{ + Name: "structs_common", + Content: content, + }) + + for _, si := range structInfos { + file, err := g.execute(si, data) + if err != nil { + return nil, err + } + files = append(files, file) + } + + return files, nil +} + +func (g *Generator) execute(si *load.StructInfo, data map[string]any) (*gen.File, error) { + newData := map[string]any{ + "TableName": si.Name, + "Fields": si.Fields, + } + maps.Copy(newData, data) + + content, err := templates.Execute(templates.TmplStructsFile, newData) + if err != nil { + return nil, err + } + + return &gen.File{ + Name: caseconv.ConvertPascalToSnake(si.Name), + Content: content, + }, nil +} + +// PackageInfo implements gen.Generator. +func (g *Generator) PackageInfo() *gen.PackageInfo { + return &gen.PackageInfo{ + PackagePath: g.packagePath, + PackageAlias: "structs", + PackageLocation: g.dirPath, + } +} diff --git a/internal/gen/util.go b/internal/gen/util.go index 6478024..477e1ba 100644 --- a/internal/gen/util.go +++ b/internal/gen/util.go @@ -28,9 +28,18 @@ func findAndReadDir(rootDir string, keyFunc func(d fs.DirEntry) bool) (string, [ } dirPath := filepath.Dir(keyPath) + filepaths, err := ReadDir(dirPath) + if err != nil { + return "", nil, fmt.Errorf("failed to read dir: %+w", err) + } + + return dirPath, filepaths, nil +} + +func ReadDir(dirPath string) ([]string, error) { entries, err := os.ReadDir(dirPath) if err != nil { - return "", nil, err + return nil, err } filepaths := make([]string, 0, len(entries)) @@ -41,7 +50,7 @@ func findAndReadDir(rootDir string, keyFunc func(d fs.DirEntry) bool) (string, [ filepaths = append(filepaths, filepath.Join(dirPath, e.Name())) } - return dirPath, filepaths, nil + return filepaths, nil } func findByKey(rootDir string, keyFunc func(d fs.DirEntry) bool) (string, error) { diff --git a/internal/templates/structs.go.tmpl b/internal/templates/structs.go.tmpl new file mode 100644 index 0000000..9418c0a --- /dev/null +++ b/internal/templates/structs.go.tmpl @@ -0,0 +1,35 @@ +func Create{{.TableName}}({{ if .UseContext}}ctx context.Context,{{ end }} t *testing.T, db Inserter, m {{ if not .UseValueModifier }}*{{ end }}structs_gen.{{.TableName}}, opts ...func(*structs_gen.{{ .TableName }})) *structs_gen.{{.TableName}} { + t.Helper() + + tbl := &structs_gen.{{.TableName}} { + {{ range $i, $f := .Fields -}} + {{ if $f.DefaultValue }} {{ $f.Name }}: {{ $f.DefaultValue }}, {{ if $f.IsOverwritten }} // {{ $f.Name }} is overwritten {{ end }} + {{ else if $f.Type.IsSlice }} // {{ $f.Name }} is slice + {{ else -}} // {{ $f.Name }} is unknown + {{ end }} + {{- end -}} + } + + {{ range $i, $f := .Fields -}} + {{ if $f.MustOverwrite -}} tbl.{{ $f.Name }} = m.{{ $f.Name }} // must overwrite + {{ else -}} + if + {{ if $f.IsModifiedCond -}} {{ $f.IsModifiedCond }} + {{- else if $f.Type.IsSlice -}} len(m.{{ $f.Name }}) > 0 + {{- else -}} isModified(m.{{ $f.Name }}) + {{- end -}} { + tbl.{{ $f.Name }} = m.{{ $f.Name }} + } + {{ end -}} + {{- end -}} + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert({{ if .UseContext }}ctx{{ else }}context.Background(){{ end}}, tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/internal/templates/structs_common.go.tmpl b/internal/templates/structs_common.go.tmpl new file mode 100644 index 0000000..7881e8e --- /dev/null +++ b/internal/templates/structs_common.go.tmpl @@ -0,0 +1,3 @@ +type Inserter[M any] interface { + Insert(ctx context.Context, m M) (M, error) +} diff --git a/internal/templates/templates.go b/internal/templates/templates.go index f636d48..0f46070 100644 --- a/internal/templates/templates.go +++ b/internal/templates/templates.go @@ -9,11 +9,13 @@ import ( var ( //go:embed * - embedFs embed.FS - TmplEntFile *template.Template - TmplYoFile *template.Template - TmplCommonFile *template.Template - TmplHeaderFile *template.Template + embedFs embed.FS + TmplEntFile *template.Template + TmplYoFile *template.Template + TmplCommonFile *template.Template + TmplHeaderFile *template.Template + TmplStructsFile *template.Template + TmplStructsCommonFile *template.Template ) func init() { @@ -21,6 +23,8 @@ func init() { TmplYoFile = parseFS("yo.go.tmpl") TmplCommonFile = parseFS("common.go.tmpl") TmplHeaderFile = parseFS("header.go.tmpl") + TmplStructsFile = parseFS("structs.go.tmpl") + TmplStructsCommonFile = parseFS("structs_common.go.tmpl") } func parseFS(pattern string) *template.Template { diff --git a/test/fixgen_test.go b/test/fixgen_test.go index 37e0945..6a3bb29 100644 --- a/test/fixgen_test.go +++ b/test/fixgen_test.go @@ -5,13 +5,13 @@ import ( "path/filepath" "testing" - "github.com/goccy/go-yaml" goldiev2 "github.com/sebdah/goldie/v2" "github.com/stretchr/testify/require" "github.com/earlgray283/fixgen/internal/config" "github.com/earlgray283/fixgen/internal/gen" gen_ent "github.com/earlgray283/fixgen/internal/gen/ent" + gen_structs "github.com/earlgray283/fixgen/internal/gen/structs" gen_yo "github.com/earlgray283/fixgen/internal/gen/yo" ) @@ -50,7 +50,7 @@ func Test_GoldenTest(t *testing.T) { } } - generators := []string{"yo", "ent"} + generators := []string{"yo", "ent", "structs"} for _, typ := range generators { testDir := filepath.Join(wd, typ, "test") @@ -104,10 +104,10 @@ func Test_GoldenTest(t *testing.T) { files, err := gen.GenerateWithFormat(g, c, tc.opts...) require.NoError(t, err) - f, err := os.Create(filepath.Join(wd, typ, "test", tc.fixtureDir, "fixgen.yaml")) - require.NoError(t, err) - defer f.Close() - require.NoError(t, yaml.NewEncoder(f).Encode(c)) + // f, err := os.Create(filepath.Join(wd, typ, "test", tc.fixtureDir, "fixgen.yaml")) + // require.NoError(t, err) + // defer f.Close() + // require.NoError(t, yaml.NewEncoder(f).Encode(c)) goldie := goldiev2.New(t, goldiev2.WithDiffEngine(goldiev2.ColoredDiff), goldiev2.WithNameSuffix(".go"), goldiev2.WithFixtureDir(filepath.Join(wd, typ, "test", tc.fixtureDir))) for _, f := range files { @@ -131,6 +131,8 @@ func mustNewGenerator(t *testing.T, typ string) gen.Generator { g, err = gen_yo.NewGenerator(".") case "ent": g, err = gen_ent.NewGenerator(".") + case "structs": + g, err = gen_structs.NewGenerator(".", "models") default: t.Fatalf("unrecognized generator type `%s`", typ) } diff --git a/test/structs/test/go.mod b/test/structs/test/go.mod new file mode 100644 index 0000000..827bfb1 --- /dev/null +++ b/test/structs/test/go.mod @@ -0,0 +1,7 @@ +module structs + +go 1.24.1 + +require github.com/samber/lo v1.49.1 + +require golang.org/x/text v0.21.0 // indirect diff --git a/test/structs/test/go.sum b/test/structs/test/go.sum new file mode 100644 index 0000000..f01c319 --- /dev/null +++ b/test/structs/test/go.sum @@ -0,0 +1,12 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/samber/lo v1.49.1 h1:4BIFyVfuQSEpluc7Fua+j1NolZHiEHEpaSEKdsH0tew= +github.com/samber/lo v1.49.1/go.mod h1:dO6KHFzUKXgP8LDhU0oI8d2hekjXnGOu0DB8Jecxd6o= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/structs/test/models/todo.go b/test/structs/test/models/todo.go new file mode 100644 index 0000000..e7dcf25 --- /dev/null +++ b/test/structs/test/models/todo.go @@ -0,0 +1,13 @@ +package models + +import "time" + +type Todo struct { + ID int64 + Title string + Description string + Tags []string + CreatedAt time.Time + UpdatedAt *time.Time + DoneAt *time.Time +} diff --git a/test/structs/test/models/user.go b/test/structs/test/models/user.go new file mode 100644 index 0000000..e40c224 --- /dev/null +++ b/test/structs/test/models/user.go @@ -0,0 +1,12 @@ +package models + +import "time" + +type User struct { + ID int64 + Name string + IconURL string + UserType int64 + CreatedAt time.Time + UpdatedAt *time.Time +} diff --git a/test/structs/test/testdata-context/goldie-common.go b/test/structs/test/testdata-context/goldie-common.go new file mode 100644 index 0000000..9c73a01 --- /dev/null +++ b/test/structs/test/testdata-context/goldie-common.go @@ -0,0 +1,8 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +func isModified[T comparable](v T) bool { + var zero T + return v != zero +} diff --git a/test/structs/test/testdata-context/goldie-structs_common.go b/test/structs/test/testdata-context/goldie-structs_common.go new file mode 100644 index 0000000..13caa89 --- /dev/null +++ b/test/structs/test/testdata-context/goldie-structs_common.go @@ -0,0 +1,9 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import "context" + +type Inserter[M any] interface { + Insert(ctx context.Context, m M) (M, error) +} diff --git a/test/structs/test/testdata-context/goldie-todo.go b/test/structs/test/testdata-context/goldie-todo.go new file mode 100644 index 0000000..c3edfb0 --- /dev/null +++ b/test/structs/test/testdata-context/goldie-todo.go @@ -0,0 +1,56 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "math/rand/v2" + "testing" + "time" + + "github.com/samber/lo" +) + +func CreateTodo(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { + t.Helper() + + tbl := &structs_gen.Todo{ + ID: rand.Int64(), + Title: lo.RandomString(32, lo.AlphanumericCharset), + Description: lo.RandomString(32, lo.AlphanumericCharset), + // Tags is slice + CreatedAt: time.Now(), + // UpdatedAt is unknown + // DoneAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + tbl.Title = m.Title // must overwrite + if isModified(m.Description) { + tbl.Description = m.Description + } + if len(m.Tags) > 0 { + tbl.Tags = m.Tags + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + if isModified(m.DoneAt) { + tbl.DoneAt = m.DoneAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(ctx, tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-context/goldie-user.go b/test/structs/test/testdata-context/goldie-user.go new file mode 100644 index 0000000..074543c --- /dev/null +++ b/test/structs/test/testdata-context/goldie-user.go @@ -0,0 +1,53 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "fmt" + "math/rand/v2" + "testing" + "time" +) + +func CreateUser(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { + t.Helper() + + tbl := &structs_gen.User{ + ID: rand.Int64(), + Name: "Taro Yamada", // Name is overwritten + IconURL: fmt.Sprintf("http://example.com/%d", 123456), // IconURL is overwritten + UserType: 1, // UserType is overwritten + CreatedAt: time.Now(), + // UpdatedAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + if isModified(m.Name) { + tbl.Name = m.Name + } + if isModified(m.IconURL) { + tbl.IconURL = m.IconURL + } + if m.UserType != 1 { + tbl.UserType = m.UserType + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(ctx, tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-math-v1/goldie-common.go b/test/structs/test/testdata-math-v1/goldie-common.go new file mode 100644 index 0000000..9c73a01 --- /dev/null +++ b/test/structs/test/testdata-math-v1/goldie-common.go @@ -0,0 +1,8 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +func isModified[T comparable](v T) bool { + var zero T + return v != zero +} diff --git a/test/structs/test/testdata-math-v1/goldie-structs_common.go b/test/structs/test/testdata-math-v1/goldie-structs_common.go new file mode 100644 index 0000000..13caa89 --- /dev/null +++ b/test/structs/test/testdata-math-v1/goldie-structs_common.go @@ -0,0 +1,9 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import "context" + +type Inserter[M any] interface { + Insert(ctx context.Context, m M) (M, error) +} diff --git a/test/structs/test/testdata-math-v1/goldie-todo.go b/test/structs/test/testdata-math-v1/goldie-todo.go new file mode 100644 index 0000000..8139543 --- /dev/null +++ b/test/structs/test/testdata-math-v1/goldie-todo.go @@ -0,0 +1,56 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "math/rand" + "testing" + "time" + + "github.com/samber/lo" +) + +func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { + t.Helper() + + tbl := &structs_gen.Todo{ + ID: rand.Int63(), + Title: lo.RandomString(32, lo.AlphanumericCharset), + Description: lo.RandomString(32, lo.AlphanumericCharset), + // Tags is slice + CreatedAt: time.Now(), + // UpdatedAt is unknown + // DoneAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + tbl.Title = m.Title // must overwrite + if isModified(m.Description) { + tbl.Description = m.Description + } + if len(m.Tags) > 0 { + tbl.Tags = m.Tags + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + if isModified(m.DoneAt) { + tbl.DoneAt = m.DoneAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-math-v1/goldie-user.go b/test/structs/test/testdata-math-v1/goldie-user.go new file mode 100644 index 0000000..9bddb25 --- /dev/null +++ b/test/structs/test/testdata-math-v1/goldie-user.go @@ -0,0 +1,53 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "fmt" + "math/rand" + "testing" + "time" +) + +func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { + t.Helper() + + tbl := &structs_gen.User{ + ID: rand.Int63(), + Name: "Taro Yamada", // Name is overwritten + IconURL: fmt.Sprintf("http://example.com/%d", 123456), // IconURL is overwritten + UserType: 1, // UserType is overwritten + CreatedAt: time.Now(), + // UpdatedAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + if isModified(m.Name) { + tbl.Name = m.Name + } + if isModified(m.IconURL) { + tbl.IconURL = m.IconURL + } + if m.UserType != 1 { + tbl.UserType = m.UserType + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-value-modifier/goldie-common.go b/test/structs/test/testdata-value-modifier/goldie-common.go new file mode 100644 index 0000000..9c73a01 --- /dev/null +++ b/test/structs/test/testdata-value-modifier/goldie-common.go @@ -0,0 +1,8 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +func isModified[T comparable](v T) bool { + var zero T + return v != zero +} diff --git a/test/structs/test/testdata-value-modifier/goldie-structs_common.go b/test/structs/test/testdata-value-modifier/goldie-structs_common.go new file mode 100644 index 0000000..13caa89 --- /dev/null +++ b/test/structs/test/testdata-value-modifier/goldie-structs_common.go @@ -0,0 +1,9 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import "context" + +type Inserter[M any] interface { + Insert(ctx context.Context, m M) (M, error) +} diff --git a/test/structs/test/testdata-value-modifier/goldie-todo.go b/test/structs/test/testdata-value-modifier/goldie-todo.go new file mode 100644 index 0000000..d95538f --- /dev/null +++ b/test/structs/test/testdata-value-modifier/goldie-todo.go @@ -0,0 +1,56 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "math/rand/v2" + "testing" + "time" + + "github.com/samber/lo" +) + +func CreateTodo(t *testing.T, db Inserter, m structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { + t.Helper() + + tbl := &structs_gen.Todo{ + ID: rand.Int64(), + Title: lo.RandomString(32, lo.AlphanumericCharset), + Description: lo.RandomString(32, lo.AlphanumericCharset), + // Tags is slice + CreatedAt: time.Now(), + // UpdatedAt is unknown + // DoneAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + tbl.Title = m.Title // must overwrite + if isModified(m.Description) { + tbl.Description = m.Description + } + if len(m.Tags) > 0 { + tbl.Tags = m.Tags + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + if isModified(m.DoneAt) { + tbl.DoneAt = m.DoneAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-value-modifier/goldie-user.go b/test/structs/test/testdata-value-modifier/goldie-user.go new file mode 100644 index 0000000..ce35741 --- /dev/null +++ b/test/structs/test/testdata-value-modifier/goldie-user.go @@ -0,0 +1,53 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "fmt" + "math/rand/v2" + "testing" + "time" +) + +func CreateUser(t *testing.T, db Inserter, m structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { + t.Helper() + + tbl := &structs_gen.User{ + ID: rand.Int64(), + Name: "Taro Yamada", // Name is overwritten + IconURL: fmt.Sprintf("http://example.com/%d", 123456), // IconURL is overwritten + UserType: 1, // UserType is overwritten + CreatedAt: time.Now(), + // UpdatedAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + if isModified(m.Name) { + tbl.Name = m.Name + } + if isModified(m.IconURL) { + tbl.IconURL = m.IconURL + } + if m.UserType != 1 { + tbl.UserType = m.UserType + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-zero/goldie-common.go b/test/structs/test/testdata-zero/goldie-common.go new file mode 100644 index 0000000..9c73a01 --- /dev/null +++ b/test/structs/test/testdata-zero/goldie-common.go @@ -0,0 +1,8 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +func isModified[T comparable](v T) bool { + var zero T + return v != zero +} diff --git a/test/structs/test/testdata-zero/goldie-structs_common.go b/test/structs/test/testdata-zero/goldie-structs_common.go new file mode 100644 index 0000000..13caa89 --- /dev/null +++ b/test/structs/test/testdata-zero/goldie-structs_common.go @@ -0,0 +1,9 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import "context" + +type Inserter[M any] interface { + Insert(ctx context.Context, m M) (M, error) +} diff --git a/test/structs/test/testdata-zero/goldie-todo.go b/test/structs/test/testdata-zero/goldie-todo.go new file mode 100644 index 0000000..07aaec4 --- /dev/null +++ b/test/structs/test/testdata-zero/goldie-todo.go @@ -0,0 +1,53 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "testing" + "time" +) + +func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { + t.Helper() + + tbl := &structs_gen.Todo{ + ID: 0, + Title: "", + Description: "", + // Tags is slice + CreatedAt: time.Time{}, + // UpdatedAt is unknown + // DoneAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + tbl.Title = m.Title // must overwrite + if isModified(m.Description) { + tbl.Description = m.Description + } + if len(m.Tags) > 0 { + tbl.Tags = m.Tags + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + if isModified(m.DoneAt) { + tbl.DoneAt = m.DoneAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata-zero/goldie-user.go b/test/structs/test/testdata-zero/goldie-user.go new file mode 100644 index 0000000..932e3ee --- /dev/null +++ b/test/structs/test/testdata-zero/goldie-user.go @@ -0,0 +1,52 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "fmt" + "testing" + "time" +) + +func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { + t.Helper() + + tbl := &structs_gen.User{ + ID: 0, + Name: "Taro Yamada", // Name is overwritten + IconURL: fmt.Sprintf("http://example.com/%d", 123456), // IconURL is overwritten + UserType: 1, // UserType is overwritten + CreatedAt: time.Time{}, + // UpdatedAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + if isModified(m.Name) { + tbl.Name = m.Name + } + if isModified(m.IconURL) { + tbl.IconURL = m.IconURL + } + if m.UserType != 1 { + tbl.UserType = m.UserType + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata/goldie-common.go b/test/structs/test/testdata/goldie-common.go new file mode 100644 index 0000000..9c73a01 --- /dev/null +++ b/test/structs/test/testdata/goldie-common.go @@ -0,0 +1,8 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +func isModified[T comparable](v T) bool { + var zero T + return v != zero +} diff --git a/test/structs/test/testdata/goldie-structs_common.go b/test/structs/test/testdata/goldie-structs_common.go new file mode 100644 index 0000000..13caa89 --- /dev/null +++ b/test/structs/test/testdata/goldie-structs_common.go @@ -0,0 +1,9 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import "context" + +type Inserter[M any] interface { + Insert(ctx context.Context, m M) (M, error) +} diff --git a/test/structs/test/testdata/goldie-todo.go b/test/structs/test/testdata/goldie-todo.go new file mode 100644 index 0000000..46a756b --- /dev/null +++ b/test/structs/test/testdata/goldie-todo.go @@ -0,0 +1,56 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "math/rand/v2" + "testing" + "time" + + "github.com/samber/lo" +) + +func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { + t.Helper() + + tbl := &structs_gen.Todo{ + ID: rand.Int64(), + Title: lo.RandomString(32, lo.AlphanumericCharset), + Description: lo.RandomString(32, lo.AlphanumericCharset), + // Tags is slice + CreatedAt: time.Now(), + // UpdatedAt is unknown + // DoneAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + tbl.Title = m.Title // must overwrite + if isModified(m.Description) { + tbl.Description = m.Description + } + if len(m.Tags) > 0 { + tbl.Tags = m.Tags + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + if isModified(m.DoneAt) { + tbl.DoneAt = m.DoneAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} diff --git a/test/structs/test/testdata/goldie-user.go b/test/structs/test/testdata/goldie-user.go new file mode 100644 index 0000000..251677e --- /dev/null +++ b/test/structs/test/testdata/goldie-user.go @@ -0,0 +1,53 @@ +// Code generated by fixgen, DO NOT EDIT. + +package fixture + +import ( + "context" + "fmt" + "math/rand/v2" + "testing" + "time" +) + +func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { + t.Helper() + + tbl := &structs_gen.User{ + ID: rand.Int64(), + Name: "Taro Yamada", // Name is overwritten + IconURL: fmt.Sprintf("http://example.com/%d", 123456), // IconURL is overwritten + UserType: 1, // UserType is overwritten + CreatedAt: time.Now(), + // UpdatedAt is unknown + } + + if isModified(m.ID) { + tbl.ID = m.ID + } + if isModified(m.Name) { + tbl.Name = m.Name + } + if isModified(m.IconURL) { + tbl.IconURL = m.IconURL + } + if m.UserType != 1 { + tbl.UserType = m.UserType + } + if isModified(m.CreatedAt) { + tbl.CreatedAt = m.CreatedAt + } + if isModified(m.UpdatedAt) { + tbl.UpdatedAt = m.UpdatedAt + } + for _, opt := range opts { + opt(tbl) + } + + m, err := db.Insert(context.Background(), tbl) + if err != nil { + t.Fatal(err) + } + + return m +} From c051ce79999d7463f10c7296b267a2d28707e1b6 Mon Sep 17 00:00:00 2001 From: earlgray Date: Sat, 29 Mar 2025 23:36:02 +0900 Subject: [PATCH 2/5] fix: update golden test --- test/structs/test/testdata-context/goldie-todo.go | 2 +- test/structs/test/testdata-context/goldie-user.go | 2 +- test/structs/test/testdata-math-v1/goldie-todo.go | 2 +- test/structs/test/testdata-math-v1/goldie-user.go | 2 +- test/structs/test/testdata-value-modifier/goldie-todo.go | 2 +- test/structs/test/testdata-value-modifier/goldie-user.go | 2 +- test/structs/test/testdata-zero/goldie-todo.go | 2 +- test/structs/test/testdata-zero/goldie-user.go | 2 +- test/structs/test/testdata/goldie-todo.go | 2 +- test/structs/test/testdata/goldie-user.go | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/test/structs/test/testdata-context/goldie-todo.go b/test/structs/test/testdata-context/goldie-todo.go index c3edfb0..7837da4 100644 --- a/test/structs/test/testdata-context/goldie-todo.go +++ b/test/structs/test/testdata-context/goldie-todo.go @@ -11,7 +11,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { +func CreateTodo(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-context/goldie-user.go b/test/structs/test/testdata-context/goldie-user.go index 074543c..5392177 100644 --- a/test/structs/test/testdata-context/goldie-user.go +++ b/test/structs/test/testdata-context/goldie-user.go @@ -10,7 +10,7 @@ import ( "time" ) -func CreateUser(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { +func CreateUser(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata-math-v1/goldie-todo.go b/test/structs/test/testdata-math-v1/goldie-todo.go index 8139543..2954bcc 100644 --- a/test/structs/test/testdata-math-v1/goldie-todo.go +++ b/test/structs/test/testdata-math-v1/goldie-todo.go @@ -11,7 +11,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { +func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-math-v1/goldie-user.go b/test/structs/test/testdata-math-v1/goldie-user.go index 9bddb25..921f0e4 100644 --- a/test/structs/test/testdata-math-v1/goldie-user.go +++ b/test/structs/test/testdata-math-v1/goldie-user.go @@ -10,7 +10,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { +func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata-value-modifier/goldie-todo.go b/test/structs/test/testdata-value-modifier/goldie-todo.go index d95538f..62139f4 100644 --- a/test/structs/test/testdata-value-modifier/goldie-todo.go +++ b/test/structs/test/testdata-value-modifier/goldie-todo.go @@ -11,7 +11,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(t *testing.T, db Inserter, m structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { +func CreateTodo(t *testing.T, db Inserter, m structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-value-modifier/goldie-user.go b/test/structs/test/testdata-value-modifier/goldie-user.go index ce35741..c6036d6 100644 --- a/test/structs/test/testdata-value-modifier/goldie-user.go +++ b/test/structs/test/testdata-value-modifier/goldie-user.go @@ -10,7 +10,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { +func CreateUser(t *testing.T, db Inserter, m structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata-zero/goldie-todo.go b/test/structs/test/testdata-zero/goldie-todo.go index 07aaec4..3928f54 100644 --- a/test/structs/test/testdata-zero/goldie-todo.go +++ b/test/structs/test/testdata-zero/goldie-todo.go @@ -8,7 +8,7 @@ import ( "time" ) -func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { +func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-zero/goldie-user.go b/test/structs/test/testdata-zero/goldie-user.go index 932e3ee..35c16e8 100644 --- a/test/structs/test/testdata-zero/goldie-user.go +++ b/test/structs/test/testdata-zero/goldie-user.go @@ -9,7 +9,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { +func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata/goldie-todo.go b/test/structs/test/testdata/goldie-todo.go index 46a756b..cdde10e 100644 --- a/test/structs/test/testdata/goldie-todo.go +++ b/test/structs/test/testdata/goldie-todo.go @@ -11,7 +11,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *yo_gen.Todo { +func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata/goldie-user.go b/test/structs/test/testdata/goldie-user.go index 251677e..ee29abd 100644 --- a/test/structs/test/testdata/goldie-user.go +++ b/test/structs/test/testdata/goldie-user.go @@ -10,7 +10,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *yo_gen.User { +func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ From 9fcf6aadc147b02f6c973b37e977466c4e6d24ad Mon Sep 17 00:00:00 2001 From: earlgray Date: Sun, 30 Mar 2025 01:24:20 +0900 Subject: [PATCH 3/5] fix(structs): package alias --- internal/gen/structs/structs.go | 2 +- test/fixgen_test.go | 9 +++++---- test/structs/test/testdata-context/fixgen.yaml | 16 ++++++++++++++++ .../test/testdata-context/goldie-todo.go | 1 + .../test/testdata-context/goldie-user.go | 1 + test/structs/test/testdata-math-v1/fixgen.yaml | 18 ++++++++++++++++++ .../test/testdata-math-v1/goldie-todo.go | 1 + .../test/testdata-math-v1/goldie-user.go | 1 + .../test/testdata-value-modifier/fixgen.yaml | 16 ++++++++++++++++ .../testdata-value-modifier/goldie-todo.go | 1 + .../testdata-value-modifier/goldie-user.go | 1 + test/structs/test/testdata-zero/fixgen.yaml | 18 ++++++++++++++++++ test/structs/test/testdata-zero/goldie-todo.go | 1 + test/structs/test/testdata-zero/goldie-user.go | 1 + test/structs/test/testdata/fixgen.yaml | 16 ++++++++++++++++ test/structs/test/testdata/goldie-todo.go | 1 + test/structs/test/testdata/goldie-user.go | 1 + 17 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 test/structs/test/testdata-context/fixgen.yaml create mode 100644 test/structs/test/testdata-math-v1/fixgen.yaml create mode 100644 test/structs/test/testdata-value-modifier/fixgen.yaml create mode 100644 test/structs/test/testdata-zero/fixgen.yaml create mode 100644 test/structs/test/testdata/fixgen.yaml diff --git a/internal/gen/structs/structs.go b/internal/gen/structs/structs.go index 663c455..9c76bf6 100644 --- a/internal/gen/structs/structs.go +++ b/internal/gen/structs/structs.go @@ -83,7 +83,7 @@ func (g *Generator) execute(si *load.StructInfo, data map[string]any) (*gen.File func (g *Generator) PackageInfo() *gen.PackageInfo { return &gen.PackageInfo{ PackagePath: g.packagePath, - PackageAlias: "structs", + PackageAlias: "structs_gen", PackageLocation: g.dirPath, } } diff --git a/test/fixgen_test.go b/test/fixgen_test.go index 6a3bb29..823b1ec 100644 --- a/test/fixgen_test.go +++ b/test/fixgen_test.go @@ -5,6 +5,7 @@ import ( "path/filepath" "testing" + "github.com/goccy/go-yaml" goldiev2 "github.com/sebdah/goldie/v2" "github.com/stretchr/testify/require" @@ -104,10 +105,10 @@ func Test_GoldenTest(t *testing.T) { files, err := gen.GenerateWithFormat(g, c, tc.opts...) require.NoError(t, err) - // f, err := os.Create(filepath.Join(wd, typ, "test", tc.fixtureDir, "fixgen.yaml")) - // require.NoError(t, err) - // defer f.Close() - // require.NoError(t, yaml.NewEncoder(f).Encode(c)) + f, err := os.Create(filepath.Join(wd, typ, "test", tc.fixtureDir, "fixgen.yaml")) + require.NoError(t, err) + defer f.Close() + require.NoError(t, yaml.NewEncoder(f).Encode(c)) goldie := goldiev2.New(t, goldiev2.WithDiffEngine(goldiev2.ColoredDiff), goldiev2.WithNameSuffix(".go"), goldiev2.WithFixtureDir(filepath.Join(wd, typ, "test", tc.fixtureDir))) for _, f := range files { diff --git a/test/structs/test/testdata-context/fixgen.yaml b/test/structs/test/testdata-context/fixgen.yaml new file mode 100644 index 0000000..7ebe424 --- /dev/null +++ b/test/structs/test/testdata-context/fixgen.yaml @@ -0,0 +1,16 @@ +structs: + Todo: + fields: + Title: + overwrite: true + User: + fields: + IconURL: + expr: fmt.Sprintf("http://example.com/%d", 123456) + Name: + value: Taro Yamada + UserType: + value: 1 + isModifiedCond: m.UserType != 1 +imports: +- package: fmt diff --git a/test/structs/test/testdata-context/goldie-todo.go b/test/structs/test/testdata-context/goldie-todo.go index 7837da4..a0b92db 100644 --- a/test/structs/test/testdata-context/goldie-todo.go +++ b/test/structs/test/testdata-context/goldie-todo.go @@ -5,6 +5,7 @@ package fixture import ( "context" "math/rand/v2" + structs_gen "structs/models" "testing" "time" diff --git a/test/structs/test/testdata-context/goldie-user.go b/test/structs/test/testdata-context/goldie-user.go index 5392177..412a6a9 100644 --- a/test/structs/test/testdata-context/goldie-user.go +++ b/test/structs/test/testdata-context/goldie-user.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "math/rand/v2" + structs_gen "structs/models" "testing" "time" ) diff --git a/test/structs/test/testdata-math-v1/fixgen.yaml b/test/structs/test/testdata-math-v1/fixgen.yaml new file mode 100644 index 0000000..128edff --- /dev/null +++ b/test/structs/test/testdata-math-v1/fixgen.yaml @@ -0,0 +1,18 @@ +defaultValuePolicy: + type: randlegacy +structs: + Todo: + fields: + Title: + overwrite: true + User: + fields: + IconURL: + expr: fmt.Sprintf("http://example.com/%d", 123456) + Name: + value: Taro Yamada + UserType: + value: 1 + isModifiedCond: m.UserType != 1 +imports: +- package: fmt diff --git a/test/structs/test/testdata-math-v1/goldie-todo.go b/test/structs/test/testdata-math-v1/goldie-todo.go index 2954bcc..a10346e 100644 --- a/test/structs/test/testdata-math-v1/goldie-todo.go +++ b/test/structs/test/testdata-math-v1/goldie-todo.go @@ -5,6 +5,7 @@ package fixture import ( "context" "math/rand" + structs_gen "structs/models" "testing" "time" diff --git a/test/structs/test/testdata-math-v1/goldie-user.go b/test/structs/test/testdata-math-v1/goldie-user.go index 921f0e4..8186e21 100644 --- a/test/structs/test/testdata-math-v1/goldie-user.go +++ b/test/structs/test/testdata-math-v1/goldie-user.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "math/rand" + structs_gen "structs/models" "testing" "time" ) diff --git a/test/structs/test/testdata-value-modifier/fixgen.yaml b/test/structs/test/testdata-value-modifier/fixgen.yaml new file mode 100644 index 0000000..7ebe424 --- /dev/null +++ b/test/structs/test/testdata-value-modifier/fixgen.yaml @@ -0,0 +1,16 @@ +structs: + Todo: + fields: + Title: + overwrite: true + User: + fields: + IconURL: + expr: fmt.Sprintf("http://example.com/%d", 123456) + Name: + value: Taro Yamada + UserType: + value: 1 + isModifiedCond: m.UserType != 1 +imports: +- package: fmt diff --git a/test/structs/test/testdata-value-modifier/goldie-todo.go b/test/structs/test/testdata-value-modifier/goldie-todo.go index 62139f4..32f5c25 100644 --- a/test/structs/test/testdata-value-modifier/goldie-todo.go +++ b/test/structs/test/testdata-value-modifier/goldie-todo.go @@ -5,6 +5,7 @@ package fixture import ( "context" "math/rand/v2" + structs_gen "structs/models" "testing" "time" diff --git a/test/structs/test/testdata-value-modifier/goldie-user.go b/test/structs/test/testdata-value-modifier/goldie-user.go index c6036d6..02abdd0 100644 --- a/test/structs/test/testdata-value-modifier/goldie-user.go +++ b/test/structs/test/testdata-value-modifier/goldie-user.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "math/rand/v2" + structs_gen "structs/models" "testing" "time" ) diff --git a/test/structs/test/testdata-zero/fixgen.yaml b/test/structs/test/testdata-zero/fixgen.yaml new file mode 100644 index 0000000..efa7dd9 --- /dev/null +++ b/test/structs/test/testdata-zero/fixgen.yaml @@ -0,0 +1,18 @@ +defaultValuePolicy: + type: zero +structs: + Todo: + fields: + Title: + overwrite: true + User: + fields: + IconURL: + expr: fmt.Sprintf("http://example.com/%d", 123456) + Name: + value: Taro Yamada + UserType: + value: 1 + isModifiedCond: m.UserType != 1 +imports: +- package: fmt diff --git a/test/structs/test/testdata-zero/goldie-todo.go b/test/structs/test/testdata-zero/goldie-todo.go index 3928f54..9363ba0 100644 --- a/test/structs/test/testdata-zero/goldie-todo.go +++ b/test/structs/test/testdata-zero/goldie-todo.go @@ -4,6 +4,7 @@ package fixture import ( "context" + structs_gen "structs/models" "testing" "time" ) diff --git a/test/structs/test/testdata-zero/goldie-user.go b/test/structs/test/testdata-zero/goldie-user.go index 35c16e8..63c12fa 100644 --- a/test/structs/test/testdata-zero/goldie-user.go +++ b/test/structs/test/testdata-zero/goldie-user.go @@ -5,6 +5,7 @@ package fixture import ( "context" "fmt" + structs_gen "structs/models" "testing" "time" ) diff --git a/test/structs/test/testdata/fixgen.yaml b/test/structs/test/testdata/fixgen.yaml new file mode 100644 index 0000000..7ebe424 --- /dev/null +++ b/test/structs/test/testdata/fixgen.yaml @@ -0,0 +1,16 @@ +structs: + Todo: + fields: + Title: + overwrite: true + User: + fields: + IconURL: + expr: fmt.Sprintf("http://example.com/%d", 123456) + Name: + value: Taro Yamada + UserType: + value: 1 + isModifiedCond: m.UserType != 1 +imports: +- package: fmt diff --git a/test/structs/test/testdata/goldie-todo.go b/test/structs/test/testdata/goldie-todo.go index cdde10e..13c0bbc 100644 --- a/test/structs/test/testdata/goldie-todo.go +++ b/test/structs/test/testdata/goldie-todo.go @@ -5,6 +5,7 @@ package fixture import ( "context" "math/rand/v2" + structs_gen "structs/models" "testing" "time" diff --git a/test/structs/test/testdata/goldie-user.go b/test/structs/test/testdata/goldie-user.go index ee29abd..2b704b0 100644 --- a/test/structs/test/testdata/goldie-user.go +++ b/test/structs/test/testdata/goldie-user.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "math/rand/v2" + structs_gen "structs/models" "testing" "time" ) From ff75b9507ef758ab3f22612aab2c588853bebdeb Mon Sep 17 00:00:00 2001 From: earlgray Date: Sun, 30 Mar 2025 01:24:48 +0900 Subject: [PATCH 4/5] feat(structs): add structs subcommand --- internal/cmd/option.go | 8 +++++--- internal/cmd/root.go | 11 +++++++++-- internal/gen/option.go | 8 ++++++++ 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/internal/cmd/option.go b/internal/cmd/option.go index 68678b4..b51c298 100644 --- a/internal/cmd/option.go +++ b/internal/cmd/option.go @@ -18,6 +18,7 @@ type Options struct { useContext bool useValueModifier bool config string + targetDir string } func (o *Options) packageDir() string { @@ -45,11 +46,12 @@ func (o *Options) buildGenOptions() []gen.OptionFunc { type GeneratorType string const ( - GeneratorTypeYo GeneratorType = "yo" - GeneratorTypeEnt GeneratorType = "ent" + GeneratorTypeYo GeneratorType = "yo" + GeneratorTypeEnt GeneratorType = "ent" + GeneratorTypeStructs GeneratorType = "structs" ) -var generatorTypes = []GeneratorType{GeneratorTypeYo, GeneratorTypeEnt} +var generatorTypes = []GeneratorType{GeneratorTypeYo, GeneratorTypeEnt, GeneratorTypeStructs} func (t GeneratorType) Validate() error { if t == "" { diff --git a/internal/cmd/root.go b/internal/cmd/root.go index aa31f10..fc5a4e2 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -11,6 +11,7 @@ import ( "github.com/earlgray283/fixgen/internal/config" "github.com/earlgray283/fixgen/internal/gen" gen_ent "github.com/earlgray283/fixgen/internal/gen/ent" + gen_structs "github.com/earlgray283/fixgen/internal/gen/structs" gen_yo "github.com/earlgray283/fixgen/internal/gen/yo" "github.com/spf13/cobra" ) @@ -32,8 +33,11 @@ func NewCommand() *cobra.Command { if err := generatorType.Validate(); err != nil { return fmt.Errorf("%+w", err) } + if generatorType == GeneratorTypeStructs && opts.targetDir == "" { + return errors.New("`--target-dir` is required for structs generator") + } - generator, err := loadGenerator(generatorType, ".") + generator, err := loadGenerator(generatorType, ".", opts.targetDir) if err != nil { return fmt.Errorf("failed to load generator: %+w", err) } @@ -71,16 +75,19 @@ func NewCommand() *cobra.Command { fs.BoolVar(&opts.useContext, "use-context", false, "add context.Context argument for the generated functions") fs.BoolVar(&opts.useValueModifier, "use-value-modifier", false, "use value modifier for the generated functions") fs.StringVarP(&opts.config, "config", "c", "fixgen.yaml", "config file path") + fs.StringVar(&opts.targetDir, "target-dir", "", "target directory for the generated files") return cmd } -func loadGenerator(typ GeneratorType, workDir string) (gen.Generator, error) { +func loadGenerator(typ GeneratorType, workDir, targetDir string) (gen.Generator, error) { switch typ { case GeneratorTypeEnt: return gen_ent.NewGenerator(workDir) case GeneratorTypeYo: return gen_yo.NewGenerator(workDir) + case GeneratorTypeStructs: + return gen_structs.NewGenerator(workDir, targetDir) default: return nil, fmt.Errorf("unrecognized generator type: %s", typ) } diff --git a/internal/gen/option.go b/internal/gen/option.go index 45eeab3..2147402 100644 --- a/internal/gen/option.go +++ b/internal/gen/option.go @@ -4,6 +4,7 @@ type option struct { packageName string // default: "fixture" useContext bool useValueModifier bool + targetDir string } func defaultOption() *option { @@ -11,6 +12,7 @@ func defaultOption() *option { packageName: "fixture", useContext: false, useValueModifier: false, + targetDir: "", } } @@ -39,3 +41,9 @@ func UseValueModifier() OptionFunc { o.useValueModifier = true } } + +func TargetDir(targetDir string) OptionFunc { + return func(o *option) { + o.targetDir = targetDir + } +} From 562f8f63f0ecf3d38c142f75d9144fedc97745a6 Mon Sep 17 00:00:00 2001 From: earlgray Date: Sun, 30 Mar 2025 01:36:32 +0900 Subject: [PATCH 5/5] fix(structs): package format, pass actual type --- internal/gen/structs/structs.go | 8 +++++++- internal/templates/structs.go.tmpl | 2 +- test/structs/test/testdata-context/goldie-todo.go | 2 +- test/structs/test/testdata-context/goldie-user.go | 2 +- test/structs/test/testdata-math-v1/goldie-todo.go | 2 +- test/structs/test/testdata-math-v1/goldie-user.go | 2 +- test/structs/test/testdata-value-modifier/goldie-todo.go | 2 +- test/structs/test/testdata-value-modifier/goldie-user.go | 2 +- test/structs/test/testdata-zero/goldie-todo.go | 2 +- test/structs/test/testdata-zero/goldie-user.go | 2 +- test/structs/test/testdata/goldie-todo.go | 2 +- test/structs/test/testdata/goldie-user.go | 2 +- 12 files changed, 18 insertions(+), 12 deletions(-) diff --git a/internal/gen/structs/structs.go b/internal/gen/structs/structs.go index 9c76bf6..acb2577 100644 --- a/internal/gen/structs/structs.go +++ b/internal/gen/structs/structs.go @@ -3,6 +3,7 @@ package datastore import ( "fmt" "maps" + "path/filepath" "strings" "github.com/earlgray283/fixgen/internal/caseconv" @@ -30,8 +31,13 @@ func NewGenerator(workDir, packageDirPath string) (*Generator, error) { return nil, fmt.Errorf("failed to read dir: %+w", err) } + rel, err := filepath.Rel(".", packageDirPath) + if err != nil { + return nil, fmt.Errorf("failed to get relative path: %+w", err) + } + return &Generator{ - packagePath: strings.Join([]string{goModulePath, packageDirPath}, "/"), + packagePath: strings.Join([]string{goModulePath, rel}, "/"), dirPath: packageDirPath, filepaths: filepaths, }, nil diff --git a/internal/templates/structs.go.tmpl b/internal/templates/structs.go.tmpl index 9418c0a..eb3c69f 100644 --- a/internal/templates/structs.go.tmpl +++ b/internal/templates/structs.go.tmpl @@ -1,4 +1,4 @@ -func Create{{.TableName}}({{ if .UseContext}}ctx context.Context,{{ end }} t *testing.T, db Inserter, m {{ if not .UseValueModifier }}*{{ end }}structs_gen.{{.TableName}}, opts ...func(*structs_gen.{{ .TableName }})) *structs_gen.{{.TableName}} { +func Create{{.TableName}}({{ if .UseContext}}ctx context.Context,{{ end }} t *testing.T, db Inserter[*structs_gen.{{ .TableName }}], m {{ if not .UseValueModifier }}*{{ end }}structs_gen.{{.TableName}}, opts ...func(*structs_gen.{{ .TableName }})) *structs_gen.{{.TableName}} { t.Helper() tbl := &structs_gen.{{.TableName}} { diff --git a/test/structs/test/testdata-context/goldie-todo.go b/test/structs/test/testdata-context/goldie-todo.go index a0b92db..79f34e6 100644 --- a/test/structs/test/testdata-context/goldie-todo.go +++ b/test/structs/test/testdata-context/goldie-todo.go @@ -12,7 +12,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { +func CreateTodo(ctx context.Context, t *testing.T, db Inserter[*structs_gen.Todo], m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-context/goldie-user.go b/test/structs/test/testdata-context/goldie-user.go index 412a6a9..9522ee5 100644 --- a/test/structs/test/testdata-context/goldie-user.go +++ b/test/structs/test/testdata-context/goldie-user.go @@ -11,7 +11,7 @@ import ( "time" ) -func CreateUser(ctx context.Context, t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { +func CreateUser(ctx context.Context, t *testing.T, db Inserter[*structs_gen.User], m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata-math-v1/goldie-todo.go b/test/structs/test/testdata-math-v1/goldie-todo.go index a10346e..74785ae 100644 --- a/test/structs/test/testdata-math-v1/goldie-todo.go +++ b/test/structs/test/testdata-math-v1/goldie-todo.go @@ -12,7 +12,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { +func CreateTodo(t *testing.T, db Inserter[*structs_gen.Todo], m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-math-v1/goldie-user.go b/test/structs/test/testdata-math-v1/goldie-user.go index 8186e21..7d6031b 100644 --- a/test/structs/test/testdata-math-v1/goldie-user.go +++ b/test/structs/test/testdata-math-v1/goldie-user.go @@ -11,7 +11,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { +func CreateUser(t *testing.T, db Inserter[*structs_gen.User], m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata-value-modifier/goldie-todo.go b/test/structs/test/testdata-value-modifier/goldie-todo.go index 32f5c25..0a1753a 100644 --- a/test/structs/test/testdata-value-modifier/goldie-todo.go +++ b/test/structs/test/testdata-value-modifier/goldie-todo.go @@ -12,7 +12,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(t *testing.T, db Inserter, m structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { +func CreateTodo(t *testing.T, db Inserter[*structs_gen.Todo], m structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-value-modifier/goldie-user.go b/test/structs/test/testdata-value-modifier/goldie-user.go index 02abdd0..c65501e 100644 --- a/test/structs/test/testdata-value-modifier/goldie-user.go +++ b/test/structs/test/testdata-value-modifier/goldie-user.go @@ -11,7 +11,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { +func CreateUser(t *testing.T, db Inserter[*structs_gen.User], m structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata-zero/goldie-todo.go b/test/structs/test/testdata-zero/goldie-todo.go index 9363ba0..0e52958 100644 --- a/test/structs/test/testdata-zero/goldie-todo.go +++ b/test/structs/test/testdata-zero/goldie-todo.go @@ -9,7 +9,7 @@ import ( "time" ) -func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { +func CreateTodo(t *testing.T, db Inserter[*structs_gen.Todo], m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata-zero/goldie-user.go b/test/structs/test/testdata-zero/goldie-user.go index 63c12fa..cd0d126 100644 --- a/test/structs/test/testdata-zero/goldie-user.go +++ b/test/structs/test/testdata-zero/goldie-user.go @@ -10,7 +10,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { +func CreateUser(t *testing.T, db Inserter[*structs_gen.User], m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{ diff --git a/test/structs/test/testdata/goldie-todo.go b/test/structs/test/testdata/goldie-todo.go index 13c0bbc..33f2c2c 100644 --- a/test/structs/test/testdata/goldie-todo.go +++ b/test/structs/test/testdata/goldie-todo.go @@ -12,7 +12,7 @@ import ( "github.com/samber/lo" ) -func CreateTodo(t *testing.T, db Inserter, m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { +func CreateTodo(t *testing.T, db Inserter[*structs_gen.Todo], m *structs_gen.Todo, opts ...func(*structs_gen.Todo)) *structs_gen.Todo { t.Helper() tbl := &structs_gen.Todo{ diff --git a/test/structs/test/testdata/goldie-user.go b/test/structs/test/testdata/goldie-user.go index 2b704b0..233d878 100644 --- a/test/structs/test/testdata/goldie-user.go +++ b/test/structs/test/testdata/goldie-user.go @@ -11,7 +11,7 @@ import ( "time" ) -func CreateUser(t *testing.T, db Inserter, m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { +func CreateUser(t *testing.T, db Inserter[*structs_gen.User], m *structs_gen.User, opts ...func(*structs_gen.User)) *structs_gen.User { t.Helper() tbl := &structs_gen.User{