Skip to content

Commit

Permalink
feat: Add CRUD generator (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
ginokent committed Aug 11, 2024
2 parents 7da8497 + 576f345 commit a64c8e7
Show file tree
Hide file tree
Showing 18 changed files with 1,554 additions and 59 deletions.
62 changes: 58 additions & 4 deletions internal/arcgen/lang/go/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"os"
"path/filepath"
"strings"

errorz "github.com/kunitsucom/util.go/errors"
Expand All @@ -27,15 +28,17 @@ func Generate(ctx context.Context, src string) error {
return nil
}

const rw_r__r__ = 0o644 //nolint:revive,stylecheck // rw-r--r--

//nolint:cyclop,funlen,gocognit
func generate(arcSrcSetSlice ARCSourceSetSlice) error {
for _, arcSrcSet := range arcSrcSetSlice {
const rw_r__r__ = 0o644 //nolint:revive,stylecheck // rw-r--r--
genFileExt := fmt.Sprintf(".%s.gen%s", config.GoColumnTag(), fileExt)

for _, arcSrcSet := range arcSrcSetSlice {
// closure for defer
if err := func() error {
filePathWithoutExt := strings.TrimSuffix(arcSrcSet.Filename, fileExt)
newExt := fmt.Sprintf(".%s.gen%s", config.GoColumnTag(), fileExt)
filename := filePathWithoutExt + newExt
filename := filePathWithoutExt + genFileExt
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, rw_r__r__)
if err != nil {
return errorz.Errorf("os.OpenFile: %w", err)
Expand All @@ -51,10 +54,61 @@ func generate(arcSrcSetSlice ARCSourceSetSlice) error {
}
}

if config.GenerateGoCRUDPackage() {
crudFileExt := ".crud" + genFileExt

if err := func() error {
filename := filepath.Join(config.GoCRUDPackagePath(), "common"+crudFileExt)
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, rw_r__r__)
if err != nil {
return errorz.Errorf("os.OpenFile: %w", err)
}
defer f.Close()

if err := fprintCRUDCommon(f, bytes.NewBuffer(nil), arcSrcSetSlice); err != nil {
return errorz.Errorf("sprint: %w", err)
}

return nil
}(); err != nil {
return errorz.Errorf("f: %w", err)
}

for _, arcSrcSet := range arcSrcSetSlice {
// closure for defer
if err := func() error {
filePathWithoutExt := strings.TrimSuffix(filepath.Base(arcSrcSet.Filename), fileExt)
filename := filepath.Join(config.GoCRUDPackagePath(), filePathWithoutExt+crudFileExt)
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, rw_r__r__)
if err != nil {
return errorz.Errorf("os.OpenFile: %w", err)
}
defer f.Close()
f.Name()

if err := fprintCRUD(
f,
bytes.NewBuffer(nil),
arcSrcSet,
); err != nil {
return errorz.Errorf("sprint: %w", err)
}
return nil
}(); err != nil {
return errorz.Errorf("f: %w", err)
}
}
}

return nil
}

type buffer = interface {
io.Writer
fmt.Stringer
}

type osFile = interface {
io.Writer
Name() string
}
31 changes: 15 additions & 16 deletions internal/arcgen/lang/go/generate_columns.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/kunitsucom/arcgen/pkg/errors"
)

func fprintColumns(osFile io.Writer, buf buffer, arcSrcSet *ARCSourceSet) error {
func fprintColumns(osFile osFile, buf buffer, arcSrcSet *ARCSourceSet) error {
content, err := generateColumnsFileContent(buf, arcSrcSet)
if err != nil {
return errorz.Errorf("generateColumnsFile: %w", err)
Expand Down Expand Up @@ -44,7 +44,7 @@ func generateColumnsFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, er
for _, arcSrc := range arcSrcSet.ARCSourceSlice {
structName := arcSrc.extractStructName()
tableName := arcSrc.extractTableNameFromCommentGroup()
fieldNames, columnNames := arcSrc.extractFieldNamesAndColumnNames()
columnInfos := arcSrc.extractFieldNamesAndColumnNames()

appendAST(
astFile,
Expand All @@ -54,8 +54,7 @@ func generateColumnsFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, er
config.GoMethodNameTable(),
config.GoMethodNameColumns(),
config.GoMethodPrefixColumn(),
fieldNames,
columnNames,
columnInfos,
)
}

Expand All @@ -64,18 +63,18 @@ func generateColumnsFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, er
}

// add header comment
content := arcSrcSet.generateGoFileHeader() + buf.String()
content := arcSrcSet.generateGoFileHeader() + "\n" + buf.String()

// add blank line between methods
content = strings.ReplaceAll(content, "\n}\nfunc ", "\n}\n\nfunc ")

return content, nil
}

func appendAST(file *ast.File, structName string, sliceTypeSuffix string, tableName string, methodNameTable string, methodNameColumns string, methodPrefixColumn string, fieldNames, columnNames []string) {
func appendAST(file *ast.File, structName string, sliceTypeSuffix string, tableName string, methodNameTable string, methodNameColumns string, methodPrefixColumn string, tableInfo *TableInfo) {
file.Decls = append(file.Decls, generateASTTableMethods(structName, sliceTypeSuffix, tableName, methodNameTable)...)

file.Decls = append(file.Decls, generateASTColumnMethods(structName, sliceTypeSuffix, methodNameColumns, methodPrefixColumn, fieldNames, columnNames)...)
file.Decls = append(file.Decls, generateASTColumnMethods(structName, sliceTypeSuffix, methodNameColumns, methodPrefixColumn, tableInfo)...)

return //nolint:gosimple
}
Expand Down Expand Up @@ -207,15 +206,15 @@ func generateASTTableMethods(structName string, sliceTypeSuffix string, tableNam
}

//nolint:funlen
func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodNameColumns string, prefixColumn string, fieldNames, columnNames []string) []ast.Decl {
func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodNameColumns string, prefixColumn string, tableInfo *TableInfo) []ast.Decl {
decls := make([]ast.Decl, 0)

// all column names method
elts := make([]ast.Expr, 0)
for _, columnName := range columnNames {
for _, c := range tableInfo.Columns {
elts = append(elts, &ast.BasicLit{
Kind: token.STRING,
Value: strconv.Quote(columnName),
Value: strconv.Quote(c.ColumnName),
})
}
decls = append(decls,
Expand Down Expand Up @@ -274,7 +273,7 @@ func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodN
)

// each column name methods
for i := range columnNames {
for i := range tableInfo.Columns {
decls = append(decls,
// func (s *StructName) Column1() string {
// return "column1"
Expand All @@ -297,7 +296,7 @@ func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodN
},
},
Name: &ast.Ident{
Name: prefixColumn + fieldNames[i],
Name: prefixColumn + tableInfo.Columns[i].FieldName,
},
Type: &ast.FuncType{
Params: &ast.FieldList{},
Expand All @@ -316,7 +315,7 @@ func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodN
&ast.ReturnStmt{
Results: []ast.Expr{
&ast.Ident{
Name: strconv.Quote(columnNames[i]),
Name: strconv.Quote(tableInfo.Columns[i].ColumnName),
},
},
},
Expand Down Expand Up @@ -381,7 +380,7 @@ func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodN
)

// each column name methods
for i := range columnNames {
for i := range tableInfo.Columns {
decls = append(decls,
// func (s StructNameSlice) Column1() string {
// return "column1"
Expand All @@ -402,7 +401,7 @@ func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodN
},
},
Name: &ast.Ident{
Name: prefixColumn + fieldNames[i],
Name: prefixColumn + tableInfo.Columns[i].FieldName,
},
Type: &ast.FuncType{
Params: &ast.FieldList{},
Expand All @@ -421,7 +420,7 @@ func generateASTColumnMethods(structName string, sliceTypeSuffix string, methodN
&ast.ReturnStmt{
Results: []ast.Expr{
&ast.Ident{
Name: strconv.Quote(columnNames[i]),
Name: strconv.Quote(tableInfo.Columns[i].ColumnName),
},
},
},
Expand Down
5 changes: 5 additions & 0 deletions internal/arcgen/lang/go/generate_columns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var _ buffer = (*testBuffer)(nil)
type testBuffer struct {
WriteFunc func(p []byte) (n int, err error)
StringFunc func() string
NameFunc func() string
}

func (w *testBuffer) Write(p []byte) (n int, err error) {
Expand All @@ -30,6 +31,10 @@ func (w *testBuffer) String() string {
return w.StringFunc()
}

func (w *testBuffer) Name() string {
return w.NameFunc()
}

//nolint:paralleltest
func Test_generate(t *testing.T) {
t.Run("failure,os.OpenFile", func(t *testing.T) {
Expand Down
93 changes: 93 additions & 0 deletions internal/arcgen/lang/go/generate_crud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package arcgengo

import (
"go/ast"
"go/printer"
"go/token"
"io"
"path/filepath"
"strconv"
"strings"

errorz "github.com/kunitsucom/util.go/errors"

"github.com/kunitsucom/arcgen/internal/arcgen/lang/util"
"github.com/kunitsucom/arcgen/internal/config"
"github.com/kunitsucom/arcgen/pkg/errors"
)

func fprintCRUD(osFile osFile, buf buffer, arcSrcSet *ARCSourceSet) error {
content, err := generateCRUDFileContent(buf, arcSrcSet)
if err != nil {
return errorz.Errorf("generateCRUDFileContent: %w", err)
}

// write to file
if _, err := io.WriteString(osFile, content); err != nil {
return errorz.Errorf("io.WriteString: %w", err)
}

return nil
}

//nolint:funlen
func generateCRUDFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, error) {
if arcSrcSet == nil || arcSrcSet.PackageName == "" {
return "", errors.ErrInvalidSourceSet
}
astFile := &ast.File{
// package
Name: &ast.Ident{
Name: config.GoCRUDPackageName(),
},
// methods
Decls: []ast.Decl{},
}

structPackagePath, err := util.GetPackagePath(filepath.Dir(arcSrcSet.Filename))
if err != nil {
return "", errorz.Errorf("GetPackagePath: %w", err)
}

// import
astFile.Decls = append(astFile.Decls,
// import (
// "context"
// "fmt"
//
// dao "path/to/your/dao"
// )
&ast.GenDecl{
Tok: token.IMPORT,
Specs: []ast.Spec{
&ast.ImportSpec{
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("context")},
},
&ast.ImportSpec{
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("fmt")},
},
&ast.ImportSpec{
Name: &ast.Ident{Name: "dao"},
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(structPackagePath)},
},
},
},
)

generateCREATEContent(astFile, arcSrcSet)
generateREADContent(astFile, arcSrcSet)
generateUPDATEContent(astFile, arcSrcSet)
generateDELETEContent(astFile, arcSrcSet)

if err := printer.Fprint(buf, token.NewFileSet(), astFile); err != nil {
return "", errorz.Errorf("printer.Fprint: %w", err)
}

// add header comment
content := arcSrcSet.generateGoFileHeader() + buf.String()

// add blank line between methods
content = strings.ReplaceAll(content, "\n}\nfunc ", "\n}\n\nfunc ")

return content, nil
}
Loading

0 comments on commit a64c8e7

Please sign in to comment.