Skip to content

Commit

Permalink
fix: Support some placeholders (#43)
Browse files Browse the repository at this point in the history
  • Loading branch information
ginokent authored Aug 12, 2024
2 parents f8e328c + 4f684f1 commit 14c5359
Show file tree
Hide file tree
Showing 17 changed files with 322 additions and 286 deletions.
94 changes: 94 additions & 0 deletions internal/arcgen/lang/go/dialect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package arcgengo

import (
"strconv"
"strings"

"github.com/kunitsucom/arcgen/internal/config"
)

func columnValuesPlaceholder(columns []string) string {
switch config.Dialect() {
case "mysql", "sqlite3":
// ?, ?, ?, ...
return "?" + strings.Repeat(", ?", len(columns)-1)
case "postgres", "cockroach":
// $1, $2, $3, ...
var s strings.Builder
s.WriteString("$1")
for i := 2; i <= len(columns); i++ {
s.WriteString(", $")
s.WriteString(strconv.Itoa(i))
}
return s.String()
case "spanner":
// @column_1, @column_2, @column_3, ...
var s strings.Builder
s.WriteString("@" + columns[0])
for i := 2; i <= len(columns); i++ {
s.WriteString(", @")
s.WriteString(columns[i-1])
}
return s.String()
case "oracle":
// :column_1, :column_2, :column_3, ...
var s strings.Builder
s.WriteString(":" + columns[0])
for i := 2; i <= len(columns); i++ {
s.WriteString(", :")
s.WriteString(columns[i-1])
}
return s.String()
default:
// ?, ?, ?, ...
return "?" + strings.Repeat(", ?", len(columns)-1)
}
}

//nolint:unparam,cyclop
func whereColumnsPlaceholder(columns []string, op string) string {
switch config.Dialect() {
case "mysql", "sqlite3":
// column1 = ? AND column2 = ? AND column3 = ...
return strings.Join(columns, " = ? "+op+" ") + " = ?"
case "postgres", "cockroach":
// column1 = $1 AND column2 = $2 AND column3 = ...
var s strings.Builder
for i, column := range columns {
if i > 0 {
s.WriteString(" " + op + " ")
}
s.WriteString(column)
s.WriteString(" = $")
s.WriteString(strconv.Itoa(i + 1))
}
return s.String()
case "spanner":
// column1 = @column_1 AND column2 = @column_2 AND column3 = ...
var s strings.Builder
for i, column := range columns {
if i > 0 {
s.WriteString(" " + op + " ")
}
s.WriteString(column)
s.WriteString(" = @")
s.WriteString(column)
}
return s.String()
case "oracle":
// column1 = :column_1 AND column2 = :column_2 AND column3 = ...
var s strings.Builder
for i, column := range columns {
if i > 0 {
s.WriteString(" " + op + " ")
}
s.WriteString(column)
s.WriteString(" = :")
s.WriteString(column)
}
return s.String()
default:
// column1 = ? AND column2 = ? AND column3 = ...
return strings.Join(columns, " = ? "+op+" ") + " = ?"
}
}
6 changes: 3 additions & 3 deletions internal/arcgen/lang/go/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ func generate(arcSrcSetSlice ARCSourceSetSlice) error {
}
}

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

crudFiles := make([]string, 0)
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)
filename := filepath.Join(config.GoORMPackagePath(), 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)
Expand All @@ -84,7 +84,7 @@ func generate(arcSrcSetSlice ARCSourceSetSlice) error {
}

if err := func() error {
filename := filepath.Join(config.GoCRUDPackagePath(), "common"+crudFileExt)
filename := filepath.Join(config.GoORMPackagePath(), "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)
Expand Down
6 changes: 3 additions & 3 deletions internal/arcgen/lang/go/generate_crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func generateCRUDFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, error
astFile := &ast.File{
// package
Name: &ast.Ident{
Name: config.GoCRUDPackageName(),
Name: config.GoORMPackageName(),
},
// methods
Decls: []ast.Decl{},
Expand All @@ -55,7 +55,7 @@ func generateCRUDFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, error
// "context"
// "fmt"
//
// dao "path/to/your/dao"
// orm "path/to/your/orm"
// )
&ast.GenDecl{
Tok: token.IMPORT,
Expand All @@ -67,7 +67,7 @@ func generateCRUDFileContent(buf buffer, arcSrcSet *ARCSourceSet) (string, error
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("fmt")},
},
&ast.ImportSpec{
Name: &ast.Ident{Name: "dao"},
Name: &ast.Ident{Name: importName},
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(structPackagePath)},
},
},
Expand Down
29 changes: 15 additions & 14 deletions internal/arcgen/lang/go/generate_crud_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ func fprintCRUDCommon(osFile osFile, buf buffer, arcSrcSetSlice ARCSourceSetSlic
}

const (
sqlQueryerContextVarName = "sqlContext"
sqlQueryerContextTypeName = "sqlQueryerContext"
importName = "orm"
queryerContextVarName = "queryerContext"
queryerContextTypeName = "QueryerContext"
)

//nolint:cyclop,funlen,gocognit,maintidx
func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice, crudFiles []string) (string, error) {
astFile := &ast.File{
// package
Name: &ast.Ident{
Name: config.GoCRUDPackageName(),
Name: config.GoORMPackageName(),
},
// methods
Decls: []ast.Decl{},
Expand All @@ -60,7 +61,7 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
// "database/sql"
// "log/slog"
//
// dao "path/to/your/dao"
// orm "path/to/your/orm"
// )
&ast.GenDecl{
Tok: token.IMPORT,
Expand All @@ -75,14 +76,14 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("log/slog")},
},
&ast.ImportSpec{
Name: &ast.Ident{Name: "dao"},
Name: &ast.Ident{Name: importName},
Path: &ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(structPackagePath)},
},
},
},
)

// type sqlQueryerContext interface {
// type QueryerContext interface {
// QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
// QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
// ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
Expand All @@ -93,7 +94,7 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
Specs: []ast.Spec{
&ast.TypeSpec{
// Assign: token.Pos(1),
Name: &ast.Ident{Name: sqlQueryerContextTypeName},
Name: &ast.Ident{Name: queryerContextTypeName},
Type: &ast.InterfaceType{
Methods: &ast.FieldList{
List: []*ast.Field{
Expand Down Expand Up @@ -153,7 +154,7 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
Tok: token.TYPE,
Specs: []ast.Spec{
&ast.TypeSpec{
Name: &ast.Ident{Name: config.GoCRUDTypeNameUnexported()},
Name: &ast.Ident{Name: config.GoORMStructName()},
Type: &ast.StructType{Fields: &ast.FieldList{}},
},
},
Expand Down Expand Up @@ -221,7 +222,7 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
)

// type CRUD interface {
// Create{StructName}(ctx context.Context, sqlQueryer sqlQueryerContext, s *{Struct}) error
// Create{StructName}(ctx context.Context, queryerContext QueryerContext, s *{Struct}) error
// ...
// }
methods := make([]*ast.Field, 0)
Expand All @@ -241,7 +242,7 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
if n.Recv != nil && len(n.Recv.List) > 0 {
if t, ok := n.Recv.List[0].Type.(*ast.StarExpr); ok {
if ident, ok := t.X.(*ast.Ident); ok {
if ident.Name == config.GoCRUDTypeNameUnexported() {
if ident.Name == config.GoORMStructName() {
methods = append(methods, &ast.Field{
Names: []*ast.Ident{{Name: n.Name.Name}},
Type: n.Type,
Expand All @@ -261,7 +262,7 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
Tok: token.TYPE,
Specs: []ast.Spec{
&ast.TypeSpec{
Name: &ast.Ident{Name: config.GoCRUDTypeName()},
Name: &ast.Ident{Name: config.GoORMTypeName()},
Type: &ast.InterfaceType{
Methods: &ast.FieldList{List: methods},
},
Expand All @@ -275,9 +276,9 @@ func generateCRUDCommonFileContent(buf buffer, arcSrcSetSlice ARCSourceSetSlice,
// }
astFile.Decls = append(astFile.Decls,
&ast.FuncDecl{
Name: &ast.Ident{Name: "New" + config.GoCRUDTypeName()},
Type: &ast.FuncType{Results: &ast.FieldList{List: []*ast.Field{{Type: &ast.Ident{Name: config.GoCRUDTypeName()}}}}},
Body: &ast.BlockStmt{List: []ast.Stmt{&ast.ReturnStmt{Results: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: &ast.Ident{Name: config.GoCRUDTypeNameUnexported() + "{}"}}}}}},
Name: &ast.Ident{Name: "New" + config.GoORMTypeName()},
Type: &ast.FuncType{Results: &ast.FieldList{List: []*ast.Field{{Type: &ast.Ident{Name: config.GoORMTypeName()}}}}},
Body: &ast.BlockStmt{List: []ast.Stmt{&ast.ReturnStmt{Results: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: &ast.Ident{Name: config.GoORMStructName() + "{}"}}}}}},
},
)

Expand Down
20 changes: 10 additions & 10 deletions internal/arcgen/lang/go/generate_crud_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ func generateCREATEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {

// const Create{StructName}Query = `INSERT INTO {table_name} ({column_name1}, {column_name2}) VALUES ($1, $2)`
//
// func (q *query) Create{StructName}(ctx context.Context, queryer sqlQueryerContext, s *{Struct}) error {
// func (q *query) Create{StructName}(ctx context.Context, queryer QueryerContext, s *{Struct}) error {
// LoggerFromContext(ctx).Debug(Create{StructName}Query)
// if _, err := sqlContext.ExecContext(ctx, Create{StructName}Query, s.{ColumnName1}, s.{ColumnName2}); err != nil {
// return fmt.Errorf("sqlContext.ExecContext: %w", err)
// if _, err := queryerContext.ExecContext(ctx, Create{StructName}Query, s.{ColumnName1}, s.{ColumnName2}); err != nil {
// return fmt.Errorf("queryerContext.ExecContext: %w", err)
// }
// return nil
// }
Expand All @@ -42,13 +42,13 @@ func generateCREATEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {
},
},
&ast.FuncDecl{
Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "q"}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoCRUDTypeNameUnexported()}}}}},
Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "q"}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}},
Name: &ast.Ident{Name: funcName},
Type: &ast.FuncType{
Params: &ast.FieldList{List: []*ast.Field{
{Names: []*ast.Ident{{Name: "ctx"}}, Type: &ast.Ident{Name: "context.Context"}},
{Names: []*ast.Ident{{Name: sqlQueryerContextVarName}}, Type: &ast.Ident{Name: sqlQueryerContextTypeName}},
{Names: []*ast.Ident{{Name: "s"}}, Type: &ast.StarExpr{X: &ast.Ident{Name: "dao." + structName}}},
{Names: []*ast.Ident{{Name: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}},
{Names: []*ast.Ident{{Name: "s"}}, Type: &ast.StarExpr{X: &ast.Ident{Name: importName + "." + structName}}},
}},
Results: &ast.FieldList{List: []*ast.Field{
{Type: &ast.Ident{Name: "error"}},
Expand All @@ -67,13 +67,13 @@ func generateCREATEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {
},
},
&ast.IfStmt{
// if _, err := sqlQueryer.ExecContext(ctx, Create{StructName}Query, s.{ColumnName1}, s.{ColumnName2}); err != nil {
// if _, err := queryerContext.ExecContext(ctx, Create{StructName}Query, s.{ColumnName1}, s.{ColumnName2}); err != nil {
Init: &ast.AssignStmt{
Lhs: []ast.Expr{&ast.Ident{Name: "_"}, &ast.Ident{Name: "err"}},
Tok: token.DEFINE,
Rhs: []ast.Expr{&ast.CallExpr{
Fun: &ast.SelectorExpr{
X: &ast.Ident{Name: sqlQueryerContextVarName},
X: &ast.Ident{Name: queryerContextVarName},
Sel: &ast.Ident{Name: "ExecContext"},
},
Args: append(
Expand All @@ -93,10 +93,10 @@ func generateCREATEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {
// err != nil {
Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}},
Body: &ast.BlockStmt{List: []ast.Stmt{
// return fmt.Errorf("sqlContext.ExecContext: %w", err)
// return fmt.Errorf("queryerContext.ExecContext: %w", err)
&ast.ReturnStmt{Results: []ast.Expr{&ast.CallExpr{
Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}},
Args: []ast.Expr{&ast.Ident{Name: strconv.Quote(sqlQueryerContextVarName + ".ExecContext: %w")}, &ast.Ident{Name: "err"}},
Args: []ast.Expr{&ast.Ident{Name: strconv.Quote(queryerContextVarName + ".ExecContext: %w")}, &ast.Ident{Name: "err"}},
}}},
}},
},
Expand Down
18 changes: 9 additions & 9 deletions internal/arcgen/lang/go/generate_crud_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ func generateDELETEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {

// const Delete{StructName}Query = `DELETE FROM {table_name} WHERE {pk1} = ? [AND {pk2} = ?]`
//
// func (q *query) Delete{StructName}(ctx context.Context, queryer sqlQueryerContext, pk1 pk1type [, pk2 pk2type]) error {
// if _, err := sqlContext.ExecContext(ctx, Delete{StructName}Query, pk1 [, pk2]); err != nil {
// return fmt.Errorf("sqlContext.ExecContext: %w", err)
// func (q *query) Delete{StructName}(ctx context.Context, queryer QueryerContext, pk1 pk1type [, pk2 pk2type]) error {
// if _, err := queryerContext.ExecContext(ctx, Delete{StructName}Query, pk1 [, pk2]); err != nil {
// return fmt.Errorf("queryerContext.ExecContext: %w", err)
// }
// return nil
// }
Expand All @@ -47,13 +47,13 @@ func generateDELETEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {
},
},
&ast.FuncDecl{
Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "q"}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoCRUDTypeNameUnexported()}}}}},
Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "q"}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}},
Name: &ast.Ident{Name: funcName},
Type: &ast.FuncType{
Params: &ast.FieldList{List: append(
[]*ast.Field{
{Names: []*ast.Ident{{Name: "ctx"}}, Type: &ast.Ident{Name: "context.Context"}},
{Names: []*ast.Ident{{Name: sqlQueryerContextVarName}}, Type: &ast.Ident{Name: sqlQueryerContextTypeName}},
{Names: []*ast.Ident{{Name: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}},
},
func() []*ast.Field {
var fields []*ast.Field
Expand All @@ -80,13 +80,13 @@ func generateDELETEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {
},
},
&ast.IfStmt{
// if _, err := sqlContext.ExecContext(ctx, Delete{StructName}Query, pk1 [, pk2]); err != nil {
// if _, err := queryerContext.ExecContext(ctx, Delete{StructName}Query, pk1 [, pk2]); err != nil {
Init: &ast.AssignStmt{
Lhs: []ast.Expr{&ast.Ident{Name: "_"}, &ast.Ident{Name: "err"}},
Tok: token.DEFINE,
Rhs: []ast.Expr{&ast.CallExpr{
Fun: &ast.SelectorExpr{
X: &ast.Ident{Name: sqlQueryerContextVarName},
X: &ast.Ident{Name: queryerContextVarName},
Sel: &ast.Ident{Name: "ExecContext"},
},
Args: append(
Expand All @@ -107,10 +107,10 @@ func generateDELETEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) {
// err != nil {
Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}},
Body: &ast.BlockStmt{List: []ast.Stmt{
// return fmt.Errorf("sqlContext.ExecContext: %w", err)
// return fmt.Errorf("queryerContext.ExecContext: %w", err)
&ast.ReturnStmt{Results: []ast.Expr{&ast.CallExpr{
Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}},
Args: []ast.Expr{&ast.Ident{Name: strconv.Quote(sqlQueryerContextVarName + ".ExecContext: %w")}, &ast.Ident{Name: "err"}},
Args: []ast.Expr{&ast.Ident{Name: strconv.Quote(queryerContextVarName + ".ExecContext: %w")}, &ast.Ident{Name: "err"}},
}}},
}},
},
Expand Down
Loading

0 comments on commit 14c5359

Please sign in to comment.