@@ -5,21 +5,44 @@ import (
55 "fmt"
66 "io"
77 "os"
8+ "strings"
89
910 "github.com/spf13/cobra"
1011
1112 "github.com/sqlc-dev/sqlc/internal/engine/clickhouse"
1213 "github.com/sqlc-dev/sqlc/internal/engine/dolphin"
1314 "github.com/sqlc-dev/sqlc/internal/engine/postgresql"
1415 "github.com/sqlc-dev/sqlc/internal/engine/sqlite"
16+ "github.com/sqlc-dev/sqlc/internal/metadata"
17+ "github.com/sqlc-dev/sqlc/internal/source"
1518 "github.com/sqlc-dev/sqlc/internal/sql/ast"
1619)
1720
21+ // dialectParser is the subset of the engine parsers that the parse command
22+ // needs: parsing SQL into statements and reporting the dialect's comment syntax
23+ // (used to extract the sqlc query name and command).
24+ type dialectParser interface {
25+ Parse (io.Reader ) ([]ast.Statement , error )
26+ CommentSyntax () source.CommentSyntax
27+ }
28+
29+ // parsedStatement is the JSON representation of a single parsed statement. The
30+ // name and cmd are extracted from the sqlc query annotation (e.g.
31+ // "-- name: GetAuthor :one") and are omitted when the statement has none.
32+ type parsedStatement struct {
33+ Name string `json:"name,omitempty"`
34+ Cmd string `json:"cmd,omitempty"`
35+ AST * ast.RawStmt `json:"ast"`
36+ }
37+
1838var parseCmd = & cobra.Command {
1939 Use : "parse [file]" ,
2040 Short : "Parse SQL and output the AST as JSON" ,
2141 Long : `Parse SQL from a file or stdin and output the abstract syntax tree as JSON.
2242
43+ Each statement is reported with its sqlc query name and command (when the
44+ statement carries a "-- name:" annotation) alongside the AST.
45+
2346Examples:
2447 # Parse a SQL file with PostgreSQL dialect
2548 sqlc parse --dialect postgresql schema.sql
@@ -63,38 +86,56 @@ Examples:
6386 input = cmd .InOrStdin ()
6487 }
6588
66- // Parse SQL based on dialect
67- var stmts []ast. Statement
89+ // Select the parser for the requested dialect
90+ var parser dialectParser
6891 switch dialect {
6992 case "postgresql" , "postgres" , "pg" :
70- parser := postgresql .NewParser ()
71- stmts , err = parser .Parse (input )
93+ parser = postgresql .NewParser ()
7294 case "mysql" :
73- parser := dolphin .NewParser ()
74- stmts , err = parser .Parse (input )
95+ parser = dolphin .NewParser ()
7596 case "sqlite" :
76- parser := sqlite .NewParser ()
77- stmts , err = parser .Parse (input )
97+ parser = sqlite .NewParser ()
7898 case "clickhouse" :
79- parser := clickhouse .NewParser ()
80- stmts , err = parser .Parse (input )
99+ parser = clickhouse .NewParser ()
81100 default :
82101 return fmt .Errorf ("unsupported dialect: %s (use postgresql, mysql, sqlite, or clickhouse)" , dialect )
83102 }
103+
104+ // Read the full source so each statement's name and command can be
105+ // extracted from its annotation comment.
106+ src , err := io .ReadAll (input )
107+ if err != nil {
108+ return fmt .Errorf ("failed to read input: %w" , err )
109+ }
110+
111+ stmts , err := parser .Parse (strings .NewReader (string (src )))
84112 if err != nil {
85113 return fmt .Errorf ("parse error: %w" , err )
86114 }
87115
116+ commentSyntax := metadata .CommentSyntax (parser .CommentSyntax ())
117+
88118 // Output the AST as a single JSON document
89- raws := make ([]* ast. RawStmt , 0 , len (stmts ))
119+ out := make ([]parsedStatement , 0 , len (stmts ))
90120 for _ , stmt := range stmts {
91- raws = append (raws , stmt .Raw )
121+ ps := parsedStatement {AST : stmt .Raw }
122+ rawSQL , err := source .Pluck (string (src ), stmt .Raw .StmtLocation , stmt .Raw .StmtLen )
123+ if err != nil {
124+ return fmt .Errorf ("failed to read statement source: %w" , err )
125+ }
126+ name , cmd , err := metadata .ParseQueryNameAndType (rawSQL , commentSyntax )
127+ if err != nil {
128+ return fmt .Errorf ("failed to parse query annotation: %w" , err )
129+ }
130+ ps .Name = name
131+ ps .Cmd = cmd
132+ out = append (out , ps )
92133 }
93134
94135 stdout := cmd .OutOrStdout ()
95136 encoder := json .NewEncoder (stdout )
96137 encoder .SetIndent ("" , " " )
97- if err := encoder .Encode (raws ); err != nil {
138+ if err := encoder .Encode (out ); err != nil {
98139 return fmt .Errorf ("failed to encode AST: %w" , err )
99140 }
100141
0 commit comments