Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
refactor: use parseCmd global instead of NewCmdParse function
Match the style of other commands in cmd.go by using a global variable
and registering flags in init().

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
  • Loading branch information
claude committed Dec 22, 2025
commit 1e7caf229f7f2fb79bcf712db8384d0d34b69514
3 changes: 2 additions & 1 deletion internal/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ func init() {
initCmd.Flags().BoolP("v1", "", false, "generate v1 config yaml file")
initCmd.Flags().BoolP("v2", "", true, "generate v2 config yaml file")
initCmd.MarkFlagsMutuallyExclusive("v1", "v2")
parseCmd.Flags().StringP("dialect", "d", "", "SQL dialect to use (postgresql, mysql, or sqlite)")
}

// Do runs the command logic.
Expand All @@ -44,7 +45,7 @@ func Do(args []string, stdin io.Reader, stdout io.Writer, stderr io.Writer) int
rootCmd.AddCommand(diffCmd)
rootCmd.AddCommand(genCmd)
rootCmd.AddCommand(initCmd)
rootCmd.AddCommand(NewCmdParse())
rootCmd.AddCommand(parseCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(verifyCmd)
rootCmd.AddCommand(pushCmd)
Expand Down
138 changes: 66 additions & 72 deletions internal/cmd/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@ import (
"github.com/sqlc-dev/sqlc/internal/sql/ast"
)

func NewCmdParse() *cobra.Command {
cmd := &cobra.Command{
Use: "parse [file]",
Short: "Parse SQL and output the AST as JSON (experimental)",
Long: `Parse SQL from a file or stdin and output the abstract syntax tree as JSON.
var parseCmd = &cobra.Command{
Use: "parse [file]",
Short: "Parse SQL and output the AST as JSON (experimental)",
Long: `Parse SQL from a file or stdin and output the abstract syntax tree as JSON.

This command is experimental and requires the 'parsecmd' experiment to be enabled.
Enable it by setting: SQLCEXPERIMENT=parsecmd
Expand All @@ -32,77 +31,72 @@ Examples:

# Parse SQLite SQL
SQLCEXPERIMENT=parsecmd sqlc parse --dialect sqlite queries.sql`,
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
env := ParseEnv(cmd)
if !env.Experiment.ParseCmd {
return fmt.Errorf("parse command requires the 'parsecmd' experiment to be enabled.\nSet SQLCEXPERIMENT=parsecmd to use this command")
}

dialect, err := cmd.Flags().GetString("dialect")
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
env := ParseEnv(cmd)
if !env.Experiment.ParseCmd {
return fmt.Errorf("parse command requires the 'parsecmd' experiment to be enabled.\nSet SQLCEXPERIMENT=parsecmd to use this command")
}

dialect, err := cmd.Flags().GetString("dialect")
if err != nil {
return err
}
if dialect == "" {
return fmt.Errorf("--dialect flag is required (postgresql, mysql, or sqlite)")
}

// Determine input source
var input io.Reader
if len(args) == 1 {
file, err := os.Open(args[0])
if err != nil {
return err
}
if dialect == "" {
return fmt.Errorf("--dialect flag is required (postgresql, mysql, or sqlite)")
}

// Determine input source
var input io.Reader
if len(args) == 1 {
file, err := os.Open(args[0])
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
input = file
} else {
// Check if stdin has data
stat, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("failed to stat stdin: %w", err)
}
if (stat.Mode() & os.ModeCharDevice) != 0 {
return fmt.Errorf("no input provided. Specify a file path or pipe SQL via stdin")
}
input = cmd.InOrStdin()
}

// Parse SQL based on dialect
var stmts []ast.Statement
switch dialect {
case "postgresql", "postgres", "pg":
parser := postgresql.NewParser()
stmts, err = parser.Parse(input)
case "mysql":
parser := dolphin.NewParser()
stmts, err = parser.Parse(input)
case "sqlite":
parser := sqlite.NewParser()
stmts, err = parser.Parse(input)
default:
return fmt.Errorf("unsupported dialect: %s (use postgresql, mysql, or sqlite)", dialect)
return fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
input = file
} else {
// Check if stdin has data
stat, err := os.Stdin.Stat()
if err != nil {
return fmt.Errorf("parse error: %w", err)
return fmt.Errorf("failed to stat stdin: %w", err)
}

// Output AST as JSON
stdout := cmd.OutOrStdout()
encoder := json.NewEncoder(stdout)
encoder.SetIndent("", " ")

for _, stmt := range stmts {
if err := encoder.Encode(stmt.Raw); err != nil {
return fmt.Errorf("failed to encode AST: %w", err)
}
if (stat.Mode() & os.ModeCharDevice) != 0 {
return fmt.Errorf("no input provided. Specify a file path or pipe SQL via stdin")
}
input = cmd.InOrStdin()
}

// Parse SQL based on dialect
var stmts []ast.Statement
switch dialect {
case "postgresql", "postgres", "pg":
parser := postgresql.NewParser()
stmts, err = parser.Parse(input)
case "mysql":
parser := dolphin.NewParser()
stmts, err = parser.Parse(input)
case "sqlite":
parser := sqlite.NewParser()
stmts, err = parser.Parse(input)
default:
return fmt.Errorf("unsupported dialect: %s (use postgresql, mysql, or sqlite)", dialect)
}
if err != nil {
return fmt.Errorf("parse error: %w", err)
}

// Output AST as JSON
stdout := cmd.OutOrStdout()
encoder := json.NewEncoder(stdout)
encoder.SetIndent("", " ")

for _, stmt := range stmts {
if err := encoder.Encode(stmt.Raw); err != nil {
return fmt.Errorf("failed to encode AST: %w", err)
}
}

return nil
},
}

cmd.Flags().StringP("dialect", "d", "", "SQL dialect to use (postgresql, mysql, or sqlite)")

return cmd
return nil
},
}
Loading