Skip to content

Commit fb8d610

Browse files
committed
refactor(generator): convert writeQuerySliceExec to use poet statements
- Add buildQuerySliceExecStmts function that returns []poet.Stmt - Add public RenderStmt function to poet package - Use poet.If with Else, poet.For with Range, poet.Assign, poet.VarDecl - Eliminate manual string building with tabs 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 905a60c commit fb8d610

File tree

2 files changed

+74
-24
lines changed

2 files changed

+74
-24
lines changed

internal/codegen/golang/generator.go

Lines changed: 67 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,37 +1408,56 @@ func (g *CodeGenerator) queryExecStdCallExpr(q Query) string {
14081408
return fmt.Sprintf("%s(ctx, %s%s)", method, q.ConstantName, params)
14091409
}
14101410

1411-
func (g *CodeGenerator) writeQuerySliceExec(body *strings.Builder, q Query, retval, db string, isPGX bool) {
1412-
body.WriteString("\tquery := " + q.ConstantName + "\n")
1413-
body.WriteString("\tvar queryParams []interface{}\n")
1411+
func (g *CodeGenerator) buildQuerySliceExecStmts(q Query, retval, db string) []poet.Stmt {
1412+
var stmts []poet.Stmt
1413+
1414+
stmts = append(stmts, poet.Assign{
1415+
Left: []string{"query"}, Op: ":=", Right: []string{q.ConstantName},
1416+
})
1417+
stmts = append(stmts, poet.VarDecl{Name: "queryParams", Type: "[]interface{}"})
1418+
1419+
// Helper to build slice handling statements
1420+
buildSliceHandling := func(varName, colName string) poet.Stmt {
1421+
return poet.If{
1422+
Cond: fmt.Sprintf("len(%s) > 0", varName),
1423+
Body: []poet.Stmt{
1424+
poet.For{
1425+
Range: fmt.Sprintf("_, v := range %s", varName),
1426+
Body: []poet.Stmt{
1427+
poet.Assign{
1428+
Left: []string{"queryParams"}, Op: "=",
1429+
Right: []string{"append(queryParams, v)"},
1430+
},
1431+
},
1432+
},
1433+
poet.Assign{
1434+
Left: []string{"query"}, Op: "=",
1435+
Right: []string{fmt.Sprintf(`strings.Replace(query, "/*SLICE:%s*/?", strings.Repeat(",?", len(%s))[1:], 1)`, colName, varName)},
1436+
},
1437+
},
1438+
Else: []poet.Stmt{
1439+
poet.Assign{
1440+
Left: []string{"query"}, Op: "=",
1441+
Right: []string{fmt.Sprintf(`strings.Replace(query, "/*SLICE:%s*/?", "NULL", 1)`, colName)},
1442+
},
1443+
},
1444+
}
1445+
}
14141446

14151447
if q.Arg.Struct != nil {
14161448
for _, fld := range q.Arg.Struct.Fields {
14171449
varName := q.Arg.VariableForField(fld)
14181450
if fld.HasSqlcSlice() {
1419-
fmt.Fprintf(body, "\tif len(%s) > 0 {\n", varName)
1420-
fmt.Fprintf(body, "\t\tfor _, v := range %s {\n", varName)
1421-
body.WriteString("\t\t\tqueryParams = append(queryParams, v)\n")
1422-
body.WriteString("\t\t}\n")
1423-
fmt.Fprintf(body, "\t\tquery = strings.Replace(query, \"/*SLICE:%s*/?\" , strings.Repeat(\",?\", len(%s))[1:], 1)\n", fld.Column.Name, varName)
1424-
body.WriteString("\t} else {\n")
1425-
fmt.Fprintf(body, "\t\tquery = strings.Replace(query, \"/*SLICE:%s*/?\" , \"NULL\", 1)\n", fld.Column.Name)
1426-
body.WriteString("\t}\n")
1451+
stmts = append(stmts, buildSliceHandling(varName, fld.Column.Name))
14271452
} else {
1428-
fmt.Fprintf(body, "\tqueryParams = append(queryParams, %s)\n", varName)
1453+
stmts = append(stmts, poet.Assign{
1454+
Left: []string{"queryParams"}, Op: "=",
1455+
Right: []string{fmt.Sprintf("append(queryParams, %s)", varName)},
1456+
})
14291457
}
14301458
}
14311459
} else {
1432-
argName := q.Arg.Name
1433-
colName := q.Arg.Column.Name
1434-
fmt.Fprintf(body, "\tif len(%s) > 0 {\n", argName)
1435-
fmt.Fprintf(body, "\t\tfor _, v := range %s {\n", argName)
1436-
body.WriteString("\t\t\tqueryParams = append(queryParams, v)\n")
1437-
body.WriteString("\t\t}\n")
1438-
fmt.Fprintf(body, "\t\tquery = strings.Replace(query, \"/*SLICE:%s*/?\" , strings.Repeat(\",?\", len(%s))[1:], 1)\n", colName, argName)
1439-
body.WriteString("\t} else {\n")
1440-
fmt.Fprintf(body, "\t\tquery = strings.Replace(query, \"/*SLICE:%s*/?\" , \"NULL\", 1)\n", colName)
1441-
body.WriteString("\t}\n")
1460+
stmts = append(stmts, buildSliceHandling(q.Arg.Name, q.Arg.Column.Name))
14421461
}
14431462

14441463
var method string
@@ -1463,10 +1482,34 @@ func (g *CodeGenerator) writeQuerySliceExec(body *strings.Builder, q Query, retv
14631482
}
14641483
}
14651484

1485+
var callExpr string
14661486
if g.tctx.EmitPreparedQueries {
1467-
fmt.Fprintf(body, "\t%s %s(ctx, nil, query, queryParams...)\n", retval, method)
1487+
callExpr = fmt.Sprintf("%s(ctx, nil, query, queryParams...)", method)
14681488
} else {
1469-
fmt.Fprintf(body, "\t%s %s(ctx, query, queryParams...)\n", retval, method)
1489+
callExpr = fmt.Sprintf("%s(ctx, query, queryParams...)", method)
1490+
}
1491+
1492+
// Parse retval to determine assignment type
1493+
parts := strings.SplitN(retval, " ", 2)
1494+
if len(parts) == 2 {
1495+
lhs := strings.Split(strings.TrimSpace(parts[0]), ",")
1496+
for i := range lhs {
1497+
lhs[i] = strings.TrimSpace(lhs[i])
1498+
}
1499+
op := strings.TrimSpace(parts[1])
1500+
stmts = append(stmts, poet.Assign{Left: lhs, Op: op, Right: []string{callExpr}})
1501+
} else {
1502+
// Simple return or call
1503+
stmts = append(stmts, poet.RawStmt{Code: fmt.Sprintf("\t%s %s\n", retval, callExpr)})
1504+
}
1505+
1506+
return stmts
1507+
}
1508+
1509+
func (g *CodeGenerator) writeQuerySliceExec(body *strings.Builder, q Query, retval, db string, isPGX bool) {
1510+
stmts := g.buildQuerySliceExecStmts(q, retval, db)
1511+
for _, stmt := range stmts {
1512+
body.WriteString(poet.RenderStmt(stmt, "\t"))
14701513
}
14711514
}
14721515

internal/poet/render.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,13 @@ func renderStmts(b *strings.Builder, stmts []Stmt, indent string) {
295295
}
296296
}
297297

298+
// RenderStmt renders a single statement to a string with the given indentation.
299+
func RenderStmt(s Stmt, indent string) string {
300+
var b strings.Builder
301+
renderStmt(&b, s, indent)
302+
return b.String()
303+
}
304+
298305
func renderStmt(b *strings.Builder, s Stmt, indent string) {
299306
switch s := s.(type) {
300307
case RawStmt:

0 commit comments

Comments
 (0)