Skip to content

Commit 95ce348

Browse files
committed
refactor(generator): convert query slice fallbacks to poet statements
Convert the HasSqlcSlices() fallback paths in addQueryOneStd and addQueryManyStd to use poet AST types instead of string building. Only the initial query exec call (writeQueryExecStdCall) remains as RawStmt due to complex dynamic SQL handling. All other statements now use structured poet types: - poet.If for error handling - poet.Defer for rows.Close() - poet.VarDecl and poet.Assign for variable declarations - poet.For for iteration - poet.Return for return statements 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 5b314a6 commit 95ce348

File tree

1 file changed

+100
-48
lines changed

1 file changed

+100
-48
lines changed

internal/codegen/golang/generator.go

Lines changed: 100 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -778,25 +778,49 @@ func (g *CodeGenerator) addQueryOneStd(f *poet.File, q Query) {
778778

779779
// Fall back to RawStmt for slice queries (complex handling)
780780
if q.Arg.HasSqlcSlices() {
781-
var body strings.Builder
782-
g.writeQueryExecStdCall(&body, q, "row :=")
781+
var stmts []poet.Stmt
782+
783+
// Query exec call (complex dynamic SQL handling)
784+
var queryExec strings.Builder
785+
g.writeQueryExecStdCall(&queryExec, q, "row :=")
786+
stmts = append(stmts, poet.RawStmt{Code: queryExec.String()})
787+
788+
// var <name> <type> (if arg and ret are different)
783789
if q.Arg.Pair() != q.Ret.Pair() || q.Arg.DefineType() != q.Ret.DefineType() {
784-
fmt.Fprintf(&body, "\tvar %s %s\n", q.Ret.Name, q.Ret.Type())
790+
stmts = append(stmts, poet.VarDecl{Name: q.Ret.Name, Type: q.Ret.Type()})
785791
}
786-
fmt.Fprintf(&body, "\terr := row.Scan(%s)\n", q.Ret.Scan())
792+
793+
// err := row.Scan(<scan args>)
794+
stmts = append(stmts, poet.Assign{
795+
Left: []string{"err"},
796+
Op: ":=",
797+
Right: []string{fmt.Sprintf("row.Scan(%s)", q.Ret.Scan())},
798+
})
799+
800+
// if err != nil { err = fmt.Errorf(...) }
787801
if g.tctx.WrapErrors {
788-
body.WriteString("\tif err != nil {\n")
789-
fmt.Fprintf(&body, "\t\terr = fmt.Errorf(\"query %s: %%w\", err)\n", q.MethodName)
790-
body.WriteString("\t}\n")
802+
stmts = append(stmts, poet.If{
803+
Cond: "err != nil",
804+
Body: []poet.Stmt{
805+
poet.Assign{
806+
Left: []string{"err"},
807+
Op: "=",
808+
Right: []string{fmt.Sprintf(`fmt.Errorf("query %s: %%w", err)`, q.MethodName)},
809+
},
810+
},
811+
})
791812
}
792-
fmt.Fprintf(&body, "\treturn %s, err\n", q.Ret.ReturnName())
813+
814+
// return <name>, err
815+
stmts = append(stmts, poet.Return{Values: []string{q.Ret.ReturnName(), "err"}})
816+
793817
f.Decls = append(f.Decls, poet.Func{
794818
Comment: g.queryComments(q),
795819
Recv: &poet.Param{Name: "q", Type: "Queries", Pointer: true},
796820
Name: q.MethodName,
797821
Params: params,
798822
Results: []poet.Param{{Type: q.Ret.DefineType()}, {Type: "error"}},
799-
Stmts: []poet.Stmt{poet.RawStmt{Code: body.String()}},
823+
Stmts: stmts,
800824
})
801825
return
802826
}
@@ -854,54 +878,82 @@ func (g *CodeGenerator) addQueryManyStd(f *poet.File, q Query) {
854878

855879
// Fall back to RawStmt for slice queries (complex handling)
856880
if q.Arg.HasSqlcSlices() {
857-
var body strings.Builder
858-
g.writeQueryExecStdCall(&body, q, "rows, err :=")
859-
body.WriteString("\tif err != nil {\n")
860-
if g.tctx.WrapErrors {
861-
fmt.Fprintf(&body, "\t\treturn nil, fmt.Errorf(\"query %s: %%w\", err)\n", q.MethodName)
862-
} else {
863-
body.WriteString("\t\treturn nil, err\n")
864-
}
865-
body.WriteString("\t}\n")
866-
body.WriteString("\tdefer rows.Close()\n")
881+
var stmts []poet.Stmt
882+
883+
// Query exec call (complex dynamic SQL handling)
884+
var queryExec strings.Builder
885+
g.writeQueryExecStdCall(&queryExec, q, "rows, err :=")
886+
stmts = append(stmts, poet.RawStmt{Code: queryExec.String()})
887+
888+
// if err != nil { return nil, err }
889+
errReturn := g.wrapErrorReturn(q, "nil")
890+
stmts = append(stmts, poet.If{
891+
Cond: "err != nil",
892+
Body: []poet.Stmt{poet.Return{Values: errReturn}},
893+
})
894+
895+
// defer rows.Close()
896+
stmts = append(stmts, poet.Defer{Call: "rows.Close()"})
897+
898+
// var items []<type> or items := []<type>{}
867899
if g.tctx.EmitEmptySlices {
868-
fmt.Fprintf(&body, "\titems := []%s{}\n", q.Ret.DefineType())
869-
} else {
870-
fmt.Fprintf(&body, "\tvar items []%s\n", q.Ret.DefineType())
871-
}
872-
body.WriteString("\tfor rows.Next() {\n")
873-
fmt.Fprintf(&body, "\t\tvar %s %s\n", q.Ret.Name, q.Ret.Type())
874-
fmt.Fprintf(&body, "\t\tif err := rows.Scan(%s); err != nil {\n", q.Ret.Scan())
875-
if g.tctx.WrapErrors {
876-
fmt.Fprintf(&body, "\t\t\treturn nil, fmt.Errorf(\"query %s: %%w\", err)\n", q.MethodName)
877-
} else {
878-
body.WriteString("\t\t\treturn nil, err\n")
879-
}
880-
body.WriteString("\t\t}\n")
881-
fmt.Fprintf(&body, "\t\titems = append(items, %s)\n", q.Ret.ReturnName())
882-
body.WriteString("\t}\n")
883-
body.WriteString("\tif err := rows.Close(); err != nil {\n")
884-
if g.tctx.WrapErrors {
885-
fmt.Fprintf(&body, "\t\treturn nil, fmt.Errorf(\"query %s: %%w\", err)\n", q.MethodName)
886-
} else {
887-
body.WriteString("\t\treturn nil, err\n")
888-
}
889-
body.WriteString("\t}\n")
890-
body.WriteString("\tif err := rows.Err(); err != nil {\n")
891-
if g.tctx.WrapErrors {
892-
fmt.Fprintf(&body, "\t\treturn nil, fmt.Errorf(\"query %s: %%w\", err)\n", q.MethodName)
900+
stmts = append(stmts, poet.Assign{
901+
Left: []string{"items"},
902+
Op: ":=",
903+
Right: []string{fmt.Sprintf("[]%s{}", q.Ret.DefineType())},
904+
})
893905
} else {
894-
body.WriteString("\t\treturn nil, err\n")
906+
stmts = append(stmts, poet.VarDecl{
907+
Name: "items",
908+
Type: "[]" + q.Ret.DefineType(),
909+
})
895910
}
896-
body.WriteString("\t}\n")
897-
body.WriteString("\treturn items, nil\n")
911+
912+
// for rows.Next() { ... }
913+
scanErrReturn := g.wrapErrorReturn(q, "nil")
914+
stmts = append(stmts, poet.For{
915+
Range: "rows.Next()",
916+
Body: []poet.Stmt{
917+
poet.VarDecl{Name: q.Ret.Name, Type: q.Ret.Type()},
918+
poet.If{
919+
Init: fmt.Sprintf("err := rows.Scan(%s)", q.Ret.Scan()),
920+
Cond: "err != nil",
921+
Body: []poet.Stmt{poet.Return{Values: scanErrReturn}},
922+
},
923+
poet.Assign{
924+
Left: []string{"items"},
925+
Op: "=",
926+
Right: []string{fmt.Sprintf("append(items, %s)", q.Ret.ReturnName())},
927+
},
928+
},
929+
})
930+
931+
// if err := rows.Close(); err != nil { return nil, err }
932+
closeErrReturn := g.wrapErrorReturn(q, "nil")
933+
stmts = append(stmts, poet.If{
934+
Init: "err := rows.Close()",
935+
Cond: "err != nil",
936+
Body: []poet.Stmt{poet.Return{Values: closeErrReturn}},
937+
})
938+
939+
// if err := rows.Err(); err != nil { return nil, err }
940+
rowsErrReturn := g.wrapErrorReturn(q, "nil")
941+
stmts = append(stmts, poet.If{
942+
Init: "err := rows.Err()",
943+
Cond: "err != nil",
944+
Body: []poet.Stmt{poet.Return{Values: rowsErrReturn}},
945+
})
946+
947+
// return items, nil
948+
stmts = append(stmts, poet.Return{Values: []string{"items", "nil"}})
949+
898950
f.Decls = append(f.Decls, poet.Func{
899951
Comment: g.queryComments(q),
900952
Recv: &poet.Param{Name: "q", Type: "Queries", Pointer: true},
901953
Name: q.MethodName,
902954
Params: params,
903955
Results: []poet.Param{{Type: "[]" + q.Ret.DefineType()}, {Type: "error"}},
904-
Stmts: []poet.Stmt{poet.RawStmt{Code: body.String()}},
956+
Stmts: stmts,
905957
})
906958
return
907959
}

0 commit comments

Comments
 (0)