diff --git a/internal/arcgen/lang/go/generate_orm_create.go b/internal/arcgen/lang/go/generate_orm_create.go index 7ba54ad..2771fd0 100644 --- a/internal/arcgen/lang/go/generate_orm_create.go +++ b/internal/arcgen/lang/go/generate_orm_create.go @@ -17,100 +17,102 @@ func generateCREATEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { tableInfo := arcSrc.extractFieldNamesAndColumnNames() columnNames := tableInfo.Columns.ColumnNames() - // const Create{StructName}Query = `INSERT INTO {table_name} ({column_name1}, {column_name2}) VALUES ($1, $2)` - // - // func (orm *_ORM) Create{StructName}(ctx context.Context, queryer QueryerContext, s *{Struct}) error { - // LoggerFromContext(ctx).Debug(Create{StructName}Query) - // if _, err := queryerContext.ExecContext(ctx, Create{StructName}Query, s.{ColumnName1}, s.{ColumnName2}); err != nil { - // return fmt.Errorf("queryerContext.ExecContext: %w", orm.HandleError(err)) - // } - // return nil - // } - funcName := "Create" + structName - queryName := funcName + "Query" - astFile.Decls = append(astFile.Decls, - &ast.GenDecl{ - Tok: token.CONST, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{{Name: queryName}}, - Values: []ast.Expr{&ast.BasicLit{ - Kind: token.STRING, - Value: "`INSERT INTO " + tableName + " (" + strings.Join(columnNames, ", ") + ") VALUES (" + columnValuesPlaceholder(columnNames, 1) + ")`", - }}, + { + // const Create{StructName}Query = `INSERT INTO {table_name} ({column_name1}, {column_name2}) VALUES ($1, $2)` + // + // func (orm *_ORM) Create{StructName}(ctx context.Context, queryer QueryerContext, s *{Struct}) error { + // LoggerFromContext(ctx).Debug(Create{StructName}Query) + // if _, err := queryerContext.ExecContext(ctx, Create{StructName}Query, s.{ColumnName1}, s.{ColumnName2}); err != nil { + // return fmt.Errorf("queryerContext.ExecContext: %w", orm.HandleError(err)) + // } + // return nil + // } + funcName := "Create" + structName + queryName := funcName + "Query" + astFile.Decls = append(astFile.Decls, + &ast.GenDecl{ + Tok: token.CONST, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{{Name: queryName}}, + Values: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: "`INSERT INTO " + tableName + " (" + strings.Join(columnNames, ", ") + ") VALUES (" + columnValuesPlaceholder(columnNames, 1) + ")`", + }}, + }, }, }, - }, - &ast.FuncDecl{ - Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, 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: 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"}}, - }}, - }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - &ast.ExprStmt{ - // LoggerFromContext(ctx).Debug(queryName) - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, - Sel: &ast.Ident{Name: "Debug"}, - }, - Args: []ast.Expr{&ast.Ident{Name: queryName}}, - }, - }, - &ast.IfStmt{ - // 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{ + &ast.FuncDecl{ + Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, 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: 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"}}, + }}, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + // LoggerFromContext(ctx).Debug(queryName) + X: &ast.CallExpr{ Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: queryerContextVarName}, - Sel: &ast.Ident{Name: "ExecContext"}, + X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, + Sel: &ast.Ident{Name: "Debug"}, }, - Args: append( - []ast.Expr{ - &ast.Ident{Name: "ctx"}, - &ast.Ident{Name: queryName}, + Args: []ast.Expr{&ast.Ident{Name: queryName}}, + }, + }, + &ast.IfStmt{ + // 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: queryerContextVarName}, + Sel: &ast.Ident{Name: "ExecContext"}, }, - func() []ast.Expr { - var args []ast.Expr - for _, c := range tableInfo.Columns { - args = append(args, &ast.SelectorExpr{X: &ast.Ident{Name: "s"}, Sel: &ast.Ident{Name: c.FieldName}}) - } - return args - }()...), + Args: append( + []ast.Expr{ + &ast.Ident{Name: "ctx"}, + &ast.Ident{Name: queryName}, + }, + func() []ast.Expr { + var args []ast.Expr + for _, c := range tableInfo.Columns { + args = append(args, &ast.SelectorExpr{X: &ast.Ident{Name: "s"}, Sel: &ast.Ident{Name: c.FieldName}}) + } + return args + }()...), + }}, + }, + // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }}}, }}, }, - // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, - }}}, - }}, - }, - &ast.ReturnStmt{ - Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, + &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + }, }, }, }, }, - }, - ) + ) + } } } diff --git a/internal/arcgen/lang/go/generate_orm_delete.go b/internal/arcgen/lang/go/generate_orm_delete.go index 41c9987..0ff19bc 100644 --- a/internal/arcgen/lang/go/generate_orm_delete.go +++ b/internal/arcgen/lang/go/generate_orm_delete.go @@ -9,122 +9,234 @@ import ( "github.com/kunitsucom/arcgen/internal/config" ) -//nolint:funlen +//nolint:funlen,maintidx func generateDELETEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { for _, arcSrc := range arcSrcSet.ARCSourceSlice { structName := arcSrc.extractStructName() tableName := arcSrc.extractTableNameFromCommentGroup() tableInfo := arcSrc.extractFieldNamesAndColumnNames() - // const Delete{StructName}Query = `DELETE FROM {table_name} WHERE {pk1} = ? [AND {pk2} = ?]` - // - // 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 - // } - funcName := "Delete" + structName + "ByPK" - queryName := funcName + "Query" - pkColumns := tableInfo.Columns.PrimaryKeys() - pkColumnNames := func() (pkColumnNames []string) { - for _, c := range pkColumns { - pkColumnNames = append(pkColumnNames, c.ColumnName) - } - return pkColumnNames - }() - astFile.Decls = append(astFile.Decls, - &ast.GenDecl{ - Tok: token.CONST, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{{Name: queryName}}, - Values: []ast.Expr{&ast.BasicLit{ - Kind: token.STRING, - Value: "`DELETE FROM " + tableName + " WHERE " + whereColumnsPlaceholder(pkColumnNames, "AND", 1) + "`", - }}, - }, - }, - }, - &ast.FuncDecl{ - Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, 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: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}}, + { + // const Delete{StructName}Query = `DELETE FROM {table_name} WHERE {pk1} = ? [AND {pk2} = ?]` + // + // 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 + // } + funcName := "Delete" + structName + "ByPK" + queryName := funcName + "Query" + pkColumns := tableInfo.Columns.PrimaryKeys() + pkColumnNames := func() (pkColumnNames []string) { + for _, c := range pkColumns { + pkColumnNames = append(pkColumnNames, c.ColumnName) + } + return pkColumnNames + }() + astFile.Decls = append(astFile.Decls, + &ast.GenDecl{ + Tok: token.CONST, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{{Name: queryName}}, + Values: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: "`DELETE FROM " + tableName + " WHERE " + whereColumnsPlaceholder(pkColumnNames, "AND", 1) + "`", + }}, }, - func() []*ast.Field { - var fields []*ast.Field - for _, c := range pkColumns { - fields = append(fields, &ast.Field{Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, Type: &ast.Ident{Name: c.FieldType}}) - } - return fields - }()..., - )}, - Results: &ast.FieldList{List: []*ast.Field{ - {Type: &ast.Ident{Name: "error"}}, - }}, + }, }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - &ast.ExprStmt{ - // LoggerFromContext(ctx).Debug(queryName) - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, - Sel: &ast.Ident{Name: "Debug"}, - }, - Args: []ast.Expr{&ast.Ident{Name: queryName}}, + &ast.FuncDecl{ + Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, 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: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}}, }, - }, - &ast.IfStmt{ - // 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{ + func() []*ast.Field { + var fields []*ast.Field + for _, c := range pkColumns { + fields = append(fields, &ast.Field{Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, Type: &ast.Ident{Name: c.FieldType}}) + } + return fields + }()..., + )}, + Results: &ast.FieldList{List: []*ast.Field{ + {Type: &ast.Ident{Name: "error"}}, + }}, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + // LoggerFromContext(ctx).Debug(queryName) + X: &ast.CallExpr{ Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: queryerContextVarName}, - Sel: &ast.Ident{Name: "ExecContext"}, + X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, + Sel: &ast.Ident{Name: "Debug"}, }, - Args: append( - []ast.Expr{ - &ast.Ident{Name: "ctx"}, - &ast.Ident{Name: queryName}, + Args: []ast.Expr{&ast.Ident{Name: queryName}}, + }, + }, + &ast.IfStmt{ + // 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: queryerContextVarName}, + Sel: &ast.Ident{Name: "ExecContext"}, }, - func() []ast.Expr { - var args []ast.Expr - for _, c := range pkColumns { - args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) - } - return args - }()..., - ), + Args: append( + []ast.Expr{ + &ast.Ident{Name: "ctx"}, + &ast.Ident{Name: queryName}, + }, + func() []ast.Expr { + var args []ast.Expr + for _, c := range pkColumns { + args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) + } + return args + }()..., + ), + }}, + }, + // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }}}, }}, }, - // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, - }}}, + &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + }, + }, + }, + }, + }, + ) + } + + { + hasManyColumnsByTag := tableInfo.HasManyTagColumnsByTag() + for _, hasManyTag := range tableInfo.HasManyTags { + // const Delete{StructName}By{FieldName}Query = `DELETE FROM {table_name} WHERE {field_name} = $1 [AND {field_name2} = $2 ...]` + // + // func (q *query) Delete{StructName}(ctx context.Context, queryer QueryerContext, {field_name} {field_type} [, {field_name2} {field_type2} ...]) error { + // if _, err := queryerContext.ExecContext(ctx, Delete{StructName}By{FieldName}Query, {field_name} [, {field_name2} ...]); err != nil { + // return fmt.Errorf("queryerContext.ExecContext: %w", err) + // } + // return nil + // } + byHasManyTagFuncName := "Delete" + structName + "By" + hasManyTag + byHasManyTagQueryName := byHasManyTagFuncName + "Query" + hasManyColumns := hasManyColumnsByTag[hasManyTag] + astFile.Decls = append(astFile.Decls, + &ast.GenDecl{ + Tok: token.CONST, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{{Name: byHasManyTagQueryName}}, + Values: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: "`DELETE FROM " + tableName + " WHERE " + whereColumnsPlaceholder(hasManyColumns.ColumnNames(), "AND", 1) + "`", + }}, + }, + }, + }, + &ast.FuncDecl{ + Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}}, + Name: &ast.Ident{Name: byHasManyTagFuncName}, + 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: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}}, + }, + func() []*ast.Field { + var fields []*ast.Field + for _, c := range hasManyColumns { + fields = append(fields, &ast.Field{Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, Type: &ast.Ident{Name: c.FieldType}}) + } + return fields + }()..., + )}, + Results: &ast.FieldList{List: []*ast.Field{ + {Type: &ast.Ident{Name: "error"}}, }}, }, - &ast.ReturnStmt{ - Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + // LoggerFromContext(ctx).Debug(queryName) + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, + Sel: &ast.Ident{Name: "Debug"}, + }, + Args: []ast.Expr{&ast.Ident{Name: byHasManyTagQueryName}}, + }, + }, + &ast.IfStmt{ + // 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: queryerContextVarName}, + Sel: &ast.Ident{Name: "ExecContext"}, + }, + Args: append( + []ast.Expr{ + &ast.Ident{Name: "ctx"}, + &ast.Ident{Name: byHasManyTagQueryName}, + }, + func() []ast.Expr { + var args []ast.Expr + for _, c := range hasManyColumns { + args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) + } + return args + }()..., + ), + }}, + }, + // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }}}, + }}, + }, + &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + }, + }, }, }, }, - }, - }, - ) + ) + } + } } } diff --git a/internal/arcgen/lang/go/generate_orm_read.go b/internal/arcgen/lang/go/generate_orm_read.go index 380a209..7f894b7 100644 --- a/internal/arcgen/lang/go/generate_orm_read.go +++ b/internal/arcgen/lang/go/generate_orm_read.go @@ -17,158 +17,12 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { tableName := arcSrc.extractTableNameFromCommentGroup() tableInfo := arcSrc.extractFieldNamesAndColumnNames() columnNames := tableInfo.Columns.ColumnNames() - pks := tableInfo.Columns.PrimaryKeys() - // const Get{StructName}ByPKQuery = `SELECT {column_name1}, {column_name2} FROM {table_name} WHERE {pk1} = ? [AND ...]` - // - // func (q *query) Get{StructName}ByPK(ctx context.Context, queryer QueryerContext, pk1 pk1type, ...) ({Struct}, error) { - // row := queryer.QueryRowContext(ctx, Get{StructName}Query, pk1, ...) - // var s {Struct} - // if err := row.Scan( - // &s.{ColumnName1}, - // &i.{ColumnName2}, - // ) err != nil { - // return nil, fmt.Errorf("row.Scan: %w", err) - // } - // return &s, nil - // } - byPKFuncName := readOneFuncPrefix + structName + "ByPK" - byPKQueryName := byPKFuncName + "Query" - astFile.Decls = append(astFile.Decls, - &ast.GenDecl{ - Tok: token.CONST, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{{Name: byPKQueryName}}, - Values: []ast.Expr{&ast.BasicLit{ - Kind: token.STRING, - Value: "`SELECT " + strings.Join(columnNames, ", ") + " FROM " + tableName + " WHERE " + whereColumnsPlaceholder(pks.ColumnNames(), "AND", 1) + "`", - }}, - }, - }, - }, - &ast.FuncDecl{ - Name: &ast.Ident{Name: byPKFuncName}, - Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}}, - 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: queryerContextVarName}}, - Type: &ast.Ident{Name: queryerContextTypeName}, - }, - }, - func() []*ast.Field { - fields := make([]*ast.Field, 0) - for _, pk := range pks { - fields = append(fields, &ast.Field{ - Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(pk.FieldName)}}, - Type: &ast.Ident{Name: pk.FieldType}, - }) - } - return fields - }()...), - }, - Results: &ast.FieldList{List: []*ast.Field{ - {Type: &ast.StarExpr{X: &ast.Ident{Name: importName + "." + structName}}}, - {Type: &ast.Ident{Name: "error"}}, - }}, - }, - Body: &ast.BlockStmt{ - // row, err := queryer.QueryRowContext(ctx, Get{StructName}Query, pk1, ...) - List: []ast.Stmt{ - &ast.ExprStmt{ - // LoggerFromContext(ctx).Debug(queryName) - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, - Sel: &ast.Ident{Name: "Debug"}, - }, - Args: []ast.Expr{&ast.Ident{Name: byPKQueryName}}, - }, - }, - &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "row"}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: queryerContextVarName}, Sel: &ast.Ident{Name: "QueryRowContext"}}, - Args: append( - []ast.Expr{ - &ast.Ident{Name: "ctx"}, - &ast.Ident{Name: byPKQueryName}, - }, - func() []ast.Expr { - var args []ast.Expr - for _, pk := range pks { - args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(pk.FieldName)}) - } - return args - }()...), - }}, - }, - // var s {Struct} - &ast.DeclStmt{Decl: &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{{Name: "s"}}, - Type: &ast.Ident{Name: importName + "." + structName}, - }}, - }}, - // if err := row.Scan(&s.{ColumnName1}, &s.{ColumnName2}); err != nil { - &ast.IfStmt{ - Init: &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, - Tok: token.DEFINE, - // row.Scan(&s.{ColumnName1}, &s.{ColumnName2}) - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "row"}, Sel: &ast.Ident{Name: "Scan"}}, - Args: func() []ast.Expr { - var args []ast.Expr - for _, c := range tableInfo.Columns { - args = append(args, &ast.UnaryExpr{ - Op: token.AND, - X: &ast.SelectorExpr{ - X: &ast.Ident{Name: "s"}, - Sel: &ast.Ident{Name: c.FieldName}, - }, - }) - } - return args - }(), - }}, - }, - 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("row.Scan: %w", err) - &ast.ReturnStmt{Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, - &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, - Args: []ast.Expr{&ast.Ident{Name: strconv.Quote("row.Scan: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, - }, - }}, - }}, - }, - // return &s, nil - &ast.ReturnStmt{Results: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: &ast.Ident{Name: "s"}}, &ast.Ident{Name: "nil"}}}, - }, - }, - }, - ) - - hasOneColumnsByTag := tableInfo.HasOneTagColumnsByTag() - for _, hasOneTag := range tableInfo.HasOneTags { - // const Get{StructName}By{FieldName}Query = `SELECT {column_name1}, {column_name2} FROM {table_name} WHERE {column} = ? [AND ...]` + { + // const Get{StructName}ByPKQuery = `SELECT {column_name1}, {column_name2} FROM {table_name} WHERE {pk1} = ? [AND ...]` // - // func (q *queryer) Get{StructName}ByColumn1[AndColumn2](ctx context.Context, queryer QueryerContext, {ColumnName} {ColumnType} [, {Column2Name} {Column2Type}]) ({Struct}Slice, error) { - // row := queryer.QueryRowContext(ctx, Get{StructName}Query, {ColumnName}, {Column2Name}) + // func (q *query) Get{StructName}ByPK(ctx context.Context, queryer QueryerContext, pk1 pk1type, ...) ({Struct}, error) { + // row := queryer.QueryRowContext(ctx, Get{StructName}Query, pk1, ...) // var s {Struct} // if err := row.Scan( // &s.{ColumnName1}, @@ -178,24 +32,24 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { // } // return &s, nil // } - byHasOneTagFuncName := readOneFuncPrefix + structName + "By" + hasOneTag - byHasOneTagQueryName := byHasOneTagFuncName + "Query" - hasOneColumns := hasOneColumnsByTag[hasOneTag] + pks := tableInfo.Columns.PrimaryKeys() + byPKFuncName := readOneFuncPrefix + structName + "ByPK" + byPKQueryName := byPKFuncName + "Query" astFile.Decls = append(astFile.Decls, &ast.GenDecl{ Tok: token.CONST, Specs: []ast.Spec{ &ast.ValueSpec{ - Names: []*ast.Ident{{Name: byHasOneTagQueryName}}, + Names: []*ast.Ident{{Name: byPKQueryName}}, Values: []ast.Expr{&ast.BasicLit{ Kind: token.STRING, - Value: "`SELECT " + strings.Join(columnNames, ", ") + " FROM " + tableName + " WHERE " + whereColumnsPlaceholder(hasOneColumns.ColumnNames(), "AND", 1) + "`", + Value: "`SELECT " + strings.Join(columnNames, ", ") + " FROM " + tableName + " WHERE " + whereColumnsPlaceholder(pks.ColumnNames(), "AND", 1) + "`", }}, }, }, }, &ast.FuncDecl{ - Name: &ast.Ident{Name: byHasOneTagFuncName}, + Name: &ast.Ident{Name: byPKFuncName}, Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}}, Type: &ast.FuncType{ Params: &ast.FieldList{ @@ -211,10 +65,10 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { }, func() []*ast.Field { fields := make([]*ast.Field, 0) - for _, c := range hasOneColumns { + for _, pk := range pks { fields = append(fields, &ast.Field{ - Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, - Type: &ast.Ident{Name: c.FieldType}, + Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(pk.FieldName)}}, + Type: &ast.Ident{Name: pk.FieldType}, }) } return fields @@ -226,7 +80,7 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { }}, }, Body: &ast.BlockStmt{ - // row, err := queryer.QueryRowContext(ctx, Get{StructName}Query, column1, ...) + // row, err := queryer.QueryRowContext(ctx, Get{StructName}Query, pk1, ...) List: []ast.Stmt{ &ast.ExprStmt{ // LoggerFromContext(ctx).Debug(queryName) @@ -235,7 +89,7 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, Sel: &ast.Ident{Name: "Debug"}, }, - Args: []ast.Expr{&ast.Ident{Name: byHasOneTagQueryName}}, + Args: []ast.Expr{&ast.Ident{Name: byPKQueryName}}, }, }, &ast.AssignStmt{ @@ -246,12 +100,12 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { Args: append( []ast.Expr{ &ast.Ident{Name: "ctx"}, - &ast.Ident{Name: byHasOneTagQueryName}, + &ast.Ident{Name: byPKQueryName}, }, func() []ast.Expr { var args []ast.Expr - for _, c := range hasOneColumns { - args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) + for _, pk := range pks { + args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(pk.FieldName)}) } return args }()...), @@ -290,7 +144,7 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { }, Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, Body: &ast.BlockStmt{List: []ast.Stmt{ - // return nil, fmt.Errorf("row.Scan: %w", err) + // return fmt.Errorf("row.Scan: %w", err) &ast.ReturnStmt{Results: []ast.Expr{ &ast.Ident{Name: "nil"}, &ast.CallExpr{ @@ -311,269 +165,421 @@ func generateREADContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { ) } - hasManyColumnsByTag := tableInfo.HasManyTagColumnsByTag() - for _, hasManyTag := range tableInfo.HasManyTags { - // const List{StructName}By{FieldName}Query = `SELECT {column_name1}, {column_name2} FROM {table_name} WHERE {pk1} = ? [AND ...]` - // - // func (q *query) List{StructName}ByColumn1[AndColumn2](ctx context.Context, queryer QueryerContext, {ColumnName} {ColumnType} [, {Column2Name} {Column2Type}]) ({Struct}Slice, error) { - // rows, err := queryer.QueryContext(ctx, List{StructName}Query, {ColumnName}, {Column2Name}) - // if err != nil { - // return nil, fmt.Errorf("queryer.QueryContext: %w", err) - // } - // var ss {Struct}Slice - // for rows.Next() { - // var s {Struct} - // if err := rows.Scan( - // &i.{ColumnName1}, - // &i.{ColumnName2}, - // ); err != nil { - // return nil, fmt.Errorf("rows.Scan: %w", err) - // } - // s = append(s, &i) - // } - // if err := rows.Close(); err != nil { - // return nil, fmt.Errorf("rows.Close: %w", err) - // } - // if err := rows.Err(); err != nil { - // return nil, fmt.Errorf("rows.Err: %w", err) - // } - // return ss, nil - // } - structSliceType := "[]*" + importName + "." + structName - if sliceSuffix := config.GoSliceTypeSuffix(); sliceSuffix != "" { - structSliceType = importName + "." + structName + sliceSuffix - } - byHasOneTagFuncName := readManyFuncPrefix + structName + "By" + hasManyTag - byHasOneTagQueryName := byHasOneTagFuncName + "Query" - hasManyColumns := hasManyColumnsByTag[hasManyTag] - astFile.Decls = append(astFile.Decls, - &ast.GenDecl{ - Tok: token.CONST, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{{Name: byHasOneTagQueryName}}, - Values: []ast.Expr{&ast.BasicLit{ - Kind: token.STRING, - Value: "`SELECT " + strings.Join(columnNames, ", ") + " FROM " + tableName + " WHERE " + whereColumnsPlaceholder(hasManyColumns.ColumnNames(), "AND", 1) + "`", - }}, - }, - }, - }, - &ast.FuncDecl{ - Name: &ast.Ident{Name: byHasOneTagFuncName}, - Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}}, - 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: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}}, - }, - func() []*ast.Field { - fields := make([]*ast.Field, 0) - for _, c := range hasManyColumns { - fields = append(fields, &ast.Field{Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, Type: &ast.Ident{Name: c.FieldType}}) - } - return fields - }()..., - ), + { + hasOneColumnsByTag := tableInfo.HasOneTagColumnsByTag() + for _, hasOneTag := range tableInfo.HasOneTags { + // const Get{StructName}By{FieldName}Query = `SELECT {column_name1}, {column_name2} FROM {table_name} WHERE {column} = ? [AND ...]` + // + // func (q *queryer) Get{StructName}ByColumn1[AndColumn2](ctx context.Context, queryer QueryerContext, {ColumnName} {ColumnType} [, {Column2Name} {Column2Type}]) ({Struct}Slice, error) { + // row := queryer.QueryRowContext(ctx, Get{StructName}Query, {ColumnName}, {Column2Name}) + // var s {Struct} + // if err := row.Scan( + // &s.{ColumnName1}, + // &i.{ColumnName2}, + // ) err != nil { + // return nil, fmt.Errorf("row.Scan: %w", err) + // } + // return &s, nil + // } + byHasOneTagFuncName := readOneFuncPrefix + structName + "By" + hasOneTag + byHasOneTagQueryName := byHasOneTagFuncName + "Query" + hasOneColumns := hasOneColumnsByTag[hasOneTag] + astFile.Decls = append(astFile.Decls, + &ast.GenDecl{ + Tok: token.CONST, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{{Name: byHasOneTagQueryName}}, + Values: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: "`SELECT " + strings.Join(columnNames, ", ") + " FROM " + tableName + " WHERE " + whereColumnsPlaceholder(hasOneColumns.ColumnNames(), "AND", 1) + "`", + }}, + }, }, - Results: &ast.FieldList{List: []*ast.Field{ - {Type: &ast.Ident{Name: structSliceType}}, - {Type: &ast.Ident{Name: "error"}}, - }}, }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - &ast.ExprStmt{ - // LoggerFromContext(ctx).Debug(queryName) - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, - Sel: &ast.Ident{Name: "Debug"}, + &ast.FuncDecl{ + Name: &ast.Ident{Name: byHasOneTagFuncName}, + Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}}, + 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: queryerContextVarName}}, + Type: &ast.Ident{Name: queryerContextTypeName}, }, - Args: []ast.Expr{&ast.Ident{Name: byHasOneTagQueryName}}, }, + func() []*ast.Field { + fields := make([]*ast.Field, 0) + for _, c := range hasOneColumns { + fields = append(fields, &ast.Field{ + Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, + Type: &ast.Ident{Name: c.FieldType}, + }) + } + return fields + }()...), }, - &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "rows"}, &ast.Ident{Name: "err"}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: queryerContextVarName}, Sel: &ast.Ident{Name: "QueryContext"}}, - Args: append( - []ast.Expr{ - &ast.Ident{Name: "ctx"}, - &ast.Ident{Name: byHasOneTagQueryName}, - }, - func() []ast.Expr { - var args []ast.Expr - for _, c := range hasManyColumns { - args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) - } - return args - }()..., - ), - }}, - }, - // if err != nil { - // return nil, fmt.Errorf("queryerContext.QueryContext: %w", err) - // } - &ast.IfStmt{ - Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, - Body: &ast.BlockStmt{List: []ast.Stmt{ - &ast.ReturnStmt{Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, - &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, - Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(queryerContextVarName + ".QueryContext: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, + Results: &ast.FieldList{List: []*ast.Field{ + {Type: &ast.StarExpr{X: &ast.Ident{Name: importName + "." + structName}}}, + {Type: &ast.Ident{Name: "error"}}, + }}, + }, + Body: &ast.BlockStmt{ + // row, err := queryer.QueryRowContext(ctx, Get{StructName}Query, column1, ...) + List: []ast.Stmt{ + &ast.ExprStmt{ + // LoggerFromContext(ctx).Debug(queryName) + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, + Sel: &ast.Ident{Name: "Debug"}, }, + Args: []ast.Expr{&ast.Ident{Name: byHasOneTagQueryName}}, + }, + }, + &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.Ident{Name: "row"}}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: queryerContextVarName}, Sel: &ast.Ident{Name: "QueryRowContext"}}, + Args: append( + []ast.Expr{ + &ast.Ident{Name: "ctx"}, + &ast.Ident{Name: byHasOneTagQueryName}, + }, + func() []ast.Expr { + var args []ast.Expr + for _, c := range hasOneColumns { + args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) + } + return args + }()...), + }}, + }, + // var s {Struct} + &ast.DeclStmt{Decl: &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{&ast.ValueSpec{ + Names: []*ast.Ident{{Name: "s"}}, + Type: &ast.Ident{Name: importName + "." + structName}, }}, }}, + // if err := row.Scan(&s.{ColumnName1}, &s.{ColumnName2}); err != nil { + &ast.IfStmt{ + Init: &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, + Tok: token.DEFINE, + // row.Scan(&s.{ColumnName1}, &s.{ColumnName2}) + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "row"}, Sel: &ast.Ident{Name: "Scan"}}, + Args: func() []ast.Expr { + var args []ast.Expr + for _, c := range tableInfo.Columns { + args = append(args, &ast.UnaryExpr{ + Op: token.AND, + X: &ast.SelectorExpr{ + X: &ast.Ident{Name: "s"}, + Sel: &ast.Ident{Name: c.FieldName}, + }, + }) + } + return args + }(), + }}, + }, + Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, + Body: &ast.BlockStmt{List: []ast.Stmt{ + // return nil, fmt.Errorf("row.Scan: %w", err) + &ast.ReturnStmt{Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, + Args: []ast.Expr{&ast.Ident{Name: strconv.Quote("row.Scan: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }, + }}, + }}, + }, + // return &s, nil + &ast.ReturnStmt{Results: []ast.Expr{&ast.UnaryExpr{Op: token.AND, X: &ast.Ident{Name: "s"}}, &ast.Ident{Name: "nil"}}}, }, - // var ss {Struct}Slice - &ast.DeclStmt{Decl: &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{{Name: "ss"}}, - Type: &ast.Ident{Name: structSliceType}, + }, + }, + ) + } + } + + { + hasManyColumnsByTag := tableInfo.HasManyTagColumnsByTag() + for _, hasManyTag := range tableInfo.HasManyTags { + // const List{StructName}By{FieldName}Query = `SELECT {column_name1}, {column_name2} FROM {table_name} WHERE {pk1} = ? [AND ...]` + // + // func (q *query) List{StructName}ByColumn1[AndColumn2](ctx context.Context, queryer QueryerContext, {ColumnName} {ColumnType} [, {Column2Name} {Column2Type}]) ({Struct}Slice, error) { + // rows, err := queryer.QueryContext(ctx, List{StructName}Query, {ColumnName}, {Column2Name}) + // if err != nil { + // return nil, fmt.Errorf("queryer.QueryContext: %w", err) + // } + // var ss {Struct}Slice + // for rows.Next() { + // var s {Struct} + // if err := rows.Scan( + // &i.{ColumnName1}, + // &i.{ColumnName2}, + // ); err != nil { + // return nil, fmt.Errorf("rows.Scan: %w", err) + // } + // s = append(s, &i) + // } + // if err := rows.Close(); err != nil { + // return nil, fmt.Errorf("rows.Close: %w", err) + // } + // if err := rows.Err(); err != nil { + // return nil, fmt.Errorf("rows.Err: %w", err) + // } + // return ss, nil + // } + structSliceType := "[]*" + importName + "." + structName + if sliceSuffix := config.GoSliceTypeSuffix(); sliceSuffix != "" { + structSliceType = importName + "." + structName + sliceSuffix + } + byHasOneTagFuncName := readManyFuncPrefix + structName + "By" + hasManyTag + byHasOneTagQueryName := byHasOneTagFuncName + "Query" + hasManyColumns := hasManyColumnsByTag[hasManyTag] + astFile.Decls = append(astFile.Decls, + &ast.GenDecl{ + Tok: token.CONST, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{{Name: byHasOneTagQueryName}}, + Values: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: "`SELECT " + strings.Join(columnNames, ", ") + " FROM " + tableName + " WHERE " + whereColumnsPlaceholder(hasManyColumns.ColumnNames(), "AND", 1) + "`", }}, + }, + }, + }, + &ast.FuncDecl{ + Name: &ast.Ident{Name: byHasOneTagFuncName}, + Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, Type: &ast.StarExpr{X: &ast.Ident{Name: config.GoORMStructName()}}}}}, + 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: queryerContextVarName}}, Type: &ast.Ident{Name: queryerContextTypeName}}, + }, + func() []*ast.Field { + fields := make([]*ast.Field, 0) + for _, c := range hasManyColumns { + fields = append(fields, &ast.Field{Names: []*ast.Ident{{Name: util.PascalCaseToCamelCase(c.FieldName)}}, Type: &ast.Ident{Name: c.FieldType}}) + } + return fields + }()..., + ), + }, + Results: &ast.FieldList{List: []*ast.Field{ + {Type: &ast.Ident{Name: structSliceType}}, + {Type: &ast.Ident{Name: "error"}}, }}, - // for rows.Next() { - &ast.ForStmt{ - Cond: &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Next"}}, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + // LoggerFromContext(ctx).Debug(queryName) + X: &ast.CallExpr{ + Fun: &ast.SelectorExpr{ + X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, + Sel: &ast.Ident{Name: "Debug"}, + }, + Args: []ast.Expr{&ast.Ident{Name: byHasOneTagQueryName}}, + }, }, - Body: &ast.BlockStmt{List: []ast.Stmt{ - // var s {Struct} - &ast.DeclStmt{Decl: &ast.GenDecl{ - Tok: token.VAR, - Specs: []ast.Spec{&ast.ValueSpec{ - Names: []*ast.Ident{{Name: "s"}}, - Type: &ast.Ident{Name: importName + "." + structName}, + &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.Ident{Name: "rows"}, &ast.Ident{Name: "err"}}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: queryerContextVarName}, Sel: &ast.Ident{Name: "QueryContext"}}, + Args: append( + []ast.Expr{ + &ast.Ident{Name: "ctx"}, + &ast.Ident{Name: byHasOneTagQueryName}, + }, + func() []ast.Expr { + var args []ast.Expr + for _, c := range hasManyColumns { + args = append(args, &ast.Ident{Name: util.PascalCaseToCamelCase(c.FieldName)}) + } + return args + }()..., + ), + }}, + }, + // if err != nil { + // return nil, fmt.Errorf("queryerContext.QueryContext: %w", err) + // } + &ast.IfStmt{ + Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, + Body: &ast.BlockStmt{List: []ast.Stmt{ + &ast.ReturnStmt{Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, + Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote(queryerContextVarName + ".QueryContext: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }, }}, }}, - // if err := rows.Scan(&s.{ColumnName1}, &s.{ColumnName2}); err != nil { - &ast.IfStmt{ - Init: &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Scan"}}, - Args: func() []ast.Expr { - var args []ast.Expr - for _, c := range tableInfo.Columns { - args = append(args, &ast.UnaryExpr{ - Op: token.AND, - X: &ast.SelectorExpr{ - X: &ast.Ident{Name: "s"}, - Sel: &ast.Ident{Name: c.FieldName}, - }, - }) - } - return args - }(), + }, + // var ss {Struct}Slice + &ast.DeclStmt{Decl: &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{&ast.ValueSpec{ + Names: []*ast.Ident{{Name: "ss"}}, + Type: &ast.Ident{Name: structSliceType}, + }}, + }}, + // for rows.Next() { + &ast.ForStmt{ + Cond: &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Next"}}, + }, + Body: &ast.BlockStmt{List: []ast.Stmt{ + // var s {Struct} + &ast.DeclStmt{Decl: &ast.GenDecl{ + Tok: token.VAR, + Specs: []ast.Spec{&ast.ValueSpec{ + Names: []*ast.Ident{{Name: "s"}}, + Type: &ast.Ident{Name: importName + "." + structName}, }}, + }}, + // if err := rows.Scan(&s.{ColumnName1}, &s.{ColumnName2}); err != nil { + &ast.IfStmt{ + Init: &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Scan"}}, + Args: func() []ast.Expr { + var args []ast.Expr + for _, c := range tableInfo.Columns { + args = append(args, &ast.UnaryExpr{ + Op: token.AND, + X: &ast.SelectorExpr{ + X: &ast.Ident{Name: "s"}, + Sel: &ast.Ident{Name: c.FieldName}, + }, + }) + } + return args + }(), + }}, + }, + Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, + Body: &ast.BlockStmt{List: []ast.Stmt{ + // return nil, fmt.Errorf("rows.Scan: %w", err) + &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, + Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("rows.Scan: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }, + }, + }, + }}, + }, + // ss = append(ss, &s) + &ast.AssignStmt{ + Lhs: []ast.Expr{&ast.Ident{Name: "ss"}}, + Tok: token.ASSIGN, + Rhs: []ast.Expr{ + &ast.CallExpr{ + Fun: &ast.Ident{Name: "append"}, + Args: []ast.Expr{ + &ast.Ident{Name: "ss"}, + &ast.UnaryExpr{Op: token.AND, X: &ast.Ident{Name: "s"}}, + }, + }, + }, }, - Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, - Body: &ast.BlockStmt{List: []ast.Stmt{ - // return nil, fmt.Errorf("rows.Scan: %w", err) + }}, + }, + // if err := rows.Close(); err != nil { + &ast.IfStmt{ + Init: &ast.AssignStmt{ + // err := rows.Close() + Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Close"}}, + }}, + }, + Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + // return nil, fmt.Errorf("rows.Close: %w", err) &ast.ReturnStmt{ Results: []ast.Expr{ &ast.Ident{Name: "nil"}, &ast.CallExpr{ Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, - Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("rows.Scan: %w")}, &ast.CallExpr{ + Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("rows.Close: %w")}, &ast.CallExpr{ Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, }}, }, }, }, - }}, - }, - // ss = append(ss, &s) - &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "ss"}}, - Tok: token.ASSIGN, - Rhs: []ast.Expr{ - &ast.CallExpr{ - Fun: &ast.Ident{Name: "append"}, - Args: []ast.Expr{ - &ast.Ident{Name: "ss"}, - &ast.UnaryExpr{Op: token.AND, X: &ast.Ident{Name: "s"}}, - }, - }, }, }, - }}, - }, - // if err := rows.Close(); err != nil { - &ast.IfStmt{ - Init: &ast.AssignStmt{ - // err := rows.Close() - Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Close"}}, - }}, }, - Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - // return nil, fmt.Errorf("rows.Close: %w", err) - &ast.ReturnStmt{ - Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, - &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, - Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("rows.Close: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, - }, - }, - }, + // if err := rows.Err(); err != nil { + &ast.IfStmt{ + Init: &ast.AssignStmt{ + // err := rows.Err() + Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, + Tok: token.DEFINE, + Rhs: []ast.Expr{&ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Err"}}, + }}, }, - }, - }, - // if err := rows.Err(); err != nil { - &ast.IfStmt{ - Init: &ast.AssignStmt{ - // err := rows.Err() - Lhs: []ast.Expr{&ast.Ident{Name: "err"}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "rows"}, Sel: &ast.Ident{Name: "Err"}}, - }}, - }, - Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - // return nil, fmt.Errorf("rows.Err: %w", err) - &ast.ReturnStmt{ - Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, - &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, - Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("rows.Err: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, + Cond: &ast.BinaryExpr{X: &ast.Ident{Name: "err"}, Op: token.NEQ, Y: &ast.Ident{Name: "nil"}}, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + // return nil, fmt.Errorf("rows.Err: %w", err) + &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: "fmt"}, Sel: &ast.Ident{Name: "Errorf"}}, + Args: []ast.Expr{&ast.BasicLit{Kind: token.STRING, Value: strconv.Quote("rows.Err: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }, }, }, }, }, }, + // return ss, nil + &ast.ReturnStmt{Results: []ast.Expr{&ast.Ident{Name: "ss"}, &ast.Ident{Name: "nil"}}}, }, - // return ss, nil - &ast.ReturnStmt{Results: []ast.Expr{&ast.Ident{Name: "ss"}, &ast.Ident{Name: "nil"}}}, }, }, - }, - ) + ) + } } } } diff --git a/internal/arcgen/lang/go/generate_orm_update.go b/internal/arcgen/lang/go/generate_orm_update.go index 8b55e38..e8393b2 100644 --- a/internal/arcgen/lang/go/generate_orm_update.go +++ b/internal/arcgen/lang/go/generate_orm_update.go @@ -16,116 +16,118 @@ func generateUPDATEContent(astFile *ast.File, arcSrcSet *ARCSourceSet) { tableName := arcSrc.extractTableNameFromCommentGroup() tableInfo := arcSrc.extractFieldNamesAndColumnNames() - // const Update{StructName}Query = `UPDATE {table_name} SET ({column_name1}, {column_name2}) = (?, ?) WHERE {pk1} = ? [AND {pk2} = ?]` - // - // func (q *query) Update{StructName}(ctx context.Context, queryer QueryerContext, s *{Struct}) error { - // if _, err := queryerContext.ExecContext(ctx, Update{StructName}Query, s.{ColumnName1}, s.{ColumnName2}, s.{PK1} [, s.{PK2}]); err != nil { - // return fmt.Errorf("queryerContext.ExecContext: %w", err) - // } - // return nil - // } - funcName := "Update" + structName - queryName := funcName + "Query" - pkColumns := tableInfo.Columns.PrimaryKeys() - nonPKColumns := tableInfo.Columns.NonPrimaryKeys() - nonPKColumnNames := func() (nonPKColumnNames []string) { - for _, c := range nonPKColumns { - nonPKColumnNames = append(nonPKColumnNames, c.ColumnName) - } - return nonPKColumnNames - }() - astFile.Decls = append(astFile.Decls, - &ast.GenDecl{ - Tok: token.CONST, - Specs: []ast.Spec{ - &ast.ValueSpec{ - Names: []*ast.Ident{{Name: queryName}}, - Values: []ast.Expr{&ast.BasicLit{ - Kind: token.STRING, - Value: "`UPDATE " + tableName + " SET (" + strings.Join(nonPKColumnNames, ", ") + ") = (" + columnValuesPlaceholder(nonPKColumnNames, 1) + ") WHERE " + whereColumnsPlaceholder(pkColumns.ColumnNames(), "AND", len(nonPKColumnNames)+1) + "`", - }}, + { + // const Update{StructName}Query = `UPDATE {table_name} SET ({column_name1}, {column_name2}) = (?, ?) WHERE {pk1} = ? [AND {pk2} = ?]` + // + // func (q *query) Update{StructName}(ctx context.Context, queryer QueryerContext, s *{Struct}) error { + // if _, err := queryerContext.ExecContext(ctx, Update{StructName}Query, s.{ColumnName1}, s.{ColumnName2}, s.{PK1} [, s.{PK2}]); err != nil { + // return fmt.Errorf("queryerContext.ExecContext: %w", err) + // } + // return nil + // } + funcName := "Update" + structName + queryName := funcName + "Query" + pkColumns := tableInfo.Columns.PrimaryKeys() + nonPKColumns := tableInfo.Columns.NonPrimaryKeys() + nonPKColumnNames := func() (nonPKColumnNames []string) { + for _, c := range nonPKColumns { + nonPKColumnNames = append(nonPKColumnNames, c.ColumnName) + } + return nonPKColumnNames + }() + astFile.Decls = append(astFile.Decls, + &ast.GenDecl{ + Tok: token.CONST, + Specs: []ast.Spec{ + &ast.ValueSpec{ + Names: []*ast.Ident{{Name: queryName}}, + Values: []ast.Expr{&ast.BasicLit{ + Kind: token.STRING, + Value: "`UPDATE " + tableName + " SET (" + strings.Join(nonPKColumnNames, ", ") + ") = (" + columnValuesPlaceholder(nonPKColumnNames, 1) + ") WHERE " + whereColumnsPlaceholder(pkColumns.ColumnNames(), "AND", len(nonPKColumnNames)+1) + "`", + }}, + }, }, }, - }, - &ast.FuncDecl{ - Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, 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: 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"}}, - }}, - }, - Body: &ast.BlockStmt{ - List: []ast.Stmt{ - &ast.ExprStmt{ - // LoggerFromContext(ctx).Debug(queryName) - X: &ast.CallExpr{ - Fun: &ast.SelectorExpr{ - X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, - Sel: &ast.Ident{Name: "Debug"}, - }, - Args: []ast.Expr{&ast.Ident{Name: queryName}}, - }, - }, - &ast.IfStmt{ - // if _, err := queryerContext.ExecContext(ctx, Update{StructName}Query, s.{ColumnName1}, s.{ColumnName2}, s.{PK1} [, s.{PK2}]); err != nil { - Init: &ast.AssignStmt{ - Lhs: []ast.Expr{&ast.Ident{Name: "_"}, &ast.Ident{Name: "err"}}, - Tok: token.DEFINE, - Rhs: []ast.Expr{&ast.CallExpr{ + &ast.FuncDecl{ + Recv: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: receiverName}}, 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: 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"}}, + }}, + }, + Body: &ast.BlockStmt{ + List: []ast.Stmt{ + &ast.ExprStmt{ + // LoggerFromContext(ctx).Debug(queryName) + X: &ast.CallExpr{ Fun: &ast.SelectorExpr{ - X: &ast.Ident{Name: queryerContextVarName}, - Sel: &ast.Ident{Name: "ExecContext"}, + X: &ast.CallExpr{Fun: &ast.Ident{Name: "LoggerFromContext"}, Args: []ast.Expr{&ast.Ident{Name: "ctx"}}}, + Sel: &ast.Ident{Name: "Debug"}, }, - Args: append( - append( - []ast.Expr{ - &ast.Ident{Name: "ctx"}, - &ast.Ident{Name: queryName}, - }, + Args: []ast.Expr{&ast.Ident{Name: queryName}}, + }, + }, + &ast.IfStmt{ + // if _, err := queryerContext.ExecContext(ctx, Update{StructName}Query, s.{ColumnName1}, s.{ColumnName2}, s.{PK1} [, s.{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: queryerContextVarName}, + Sel: &ast.Ident{Name: "ExecContext"}, + }, + Args: append( + append( + []ast.Expr{ + &ast.Ident{Name: "ctx"}, + &ast.Ident{Name: queryName}, + }, + func() []ast.Expr { + var args []ast.Expr + for _, c := range nonPKColumns { + args = append(args, &ast.SelectorExpr{X: &ast.Ident{Name: "s"}, Sel: &ast.Ident{Name: c.FieldName}}) + } + return args + }()...), func() []ast.Expr { var args []ast.Expr - for _, c := range nonPKColumns { + for _, c := range pkColumns { args = append(args, &ast.SelectorExpr{X: &ast.Ident{Name: "s"}, Sel: &ast.Ident{Name: c.FieldName}}) } return args - }()...), - func() []ast.Expr { - var args []ast.Expr - for _, c := range pkColumns { - args = append(args, &ast.SelectorExpr{X: &ast.Ident{Name: "s"}, Sel: &ast.Ident{Name: c.FieldName}}) - } - return args - }()..., - ), + }()..., + ), + }}, + }, + // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ + Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, + Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, + }}, + }}}, }}, }, - // 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("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(queryerContextVarName + ".ExecContext: %w")}, &ast.CallExpr{ - Fun: &ast.SelectorExpr{X: &ast.Ident{Name: receiverName}, Sel: &ast.Ident{Name: "HandleError"}}, - Args: []ast.Expr{&ast.Ident{Name: "ctx"}, &ast.Ident{Name: "err"}}, - }}, - }}}, - }}, - }, - &ast.ReturnStmt{ - Results: []ast.Expr{ - &ast.Ident{Name: "nil"}, + &ast.ReturnStmt{ + Results: []ast.Expr{ + &ast.Ident{Name: "nil"}, + }, }, }, }, }, - }, - ) + ) + } } }