feat(dml): implement DML statement formatting and tests
CI / Test (push) Failing after 45s
CI / Build snapshot (push) Has been skipped

* Add formatDML function for formatting top-level DML statements
* Introduce tests for various DML scenarios including SELECT, INSERT, UPDATE, and DELETE
* Enhance printer to handle DML statements correctly
This commit is contained in:
2026-06-28 16:20:37 +02:00
parent f378bf4a18
commit a98dee1877
4 changed files with 727 additions and 2 deletions
+18
View File
@@ -52,6 +52,12 @@ func (p *printer) writeItem(n cst.Node) {
switch v := n.(type) {
case *cst.CreateFunction:
p.writeCreateFunction(v)
case *cst.Raw:
if isDMLStart(v.Toks) {
p.b.WriteString(formatDML(v.Toks, p.st))
} else {
p.b.WriteString(verbatimSpan(v.Toks))
}
default:
p.b.WriteString(verbatimSpan(cst.Tokens(n)))
}
@@ -160,6 +166,13 @@ func (p *printer) trailingComments(lead cst.Trivia) {
// tightOps are operators printed without surrounding spaces.
var tightOps = map[string]bool{"::": true, ":": true, "->": true, "->>": true}
// parenKws are keywords that always take a space before '(' because they
// introduce a subquery or a bracketed clause, not a function-call argument list.
var parenKws = map[string]bool{
"as": true, "exists": true, "in": true, "not": true,
"between": true, "like": true, "ilike": true, "similar": true,
}
func needSpace(a, b lexer.Token) bool {
// No space after.
switch a.Kind {
@@ -177,6 +190,11 @@ func needSpace(a, b lexer.Token) bool {
case lexer.LParen:
switch a.Kind {
case lexer.Ident, lexer.QuotedIdent, lexer.RParen, lexer.RBracket, lexer.Param:
// Keywords like AS/EXISTS/IN introduce subqueries or clause groups,
// not function calls — always separate with a space.
if a.Kind == lexer.Ident && parenKws[lowerASCII(a.Text)] {
return true
}
return false // function call / type modifier
}
case lexer.LBracket: