Skip to content

Commit 4668db9

Browse files
committed
refactor: use analyzer interface for database-only mode
- Add EnsureConn and GetColumnNames methods to Analyzer interface - Remove engine-specific pgAnalyzer and sqliteAnalyzer fields from compiler - Use unified analyzer interface for database connection initialization - Keep parsing schema files to build catalog, only use database for star expansion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent b126f17 commit 4668db9

File tree

4 files changed

+30
-69
lines changed

4 files changed

+30
-69
lines changed

internal/analyzer/analyzer.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,21 @@ func (c *CachedAnalyzer) Close(ctx context.Context) error {
110110
return c.a.Close(ctx)
111111
}
112112

113+
func (c *CachedAnalyzer) EnsureConn(ctx context.Context, migrations []string) error {
114+
return c.a.EnsureConn(ctx, migrations)
115+
}
116+
117+
func (c *CachedAnalyzer) GetColumnNames(ctx context.Context, query string) ([]string, error) {
118+
return c.a.GetColumnNames(ctx, query)
119+
}
120+
113121
type Analyzer interface {
114122
Analyze(context.Context, ast.Node, string, []string, *named.ParamSet) (*analysis.Analysis, error)
115123
Close(context.Context) error
124+
// EnsureConn initializes the database connection with the given migrations.
125+
// This is required for database-only mode where we need to connect before analyzing queries.
126+
EnsureConn(ctx context.Context, migrations []string) error
127+
// GetColumnNames returns the column names for a query by preparing it against the database.
128+
// This is used for star expansion in database-only mode.
129+
GetColumnNames(ctx context.Context, query string) ([]string, error)
116130
}

internal/compiler/compile.go

Lines changed: 3 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ func (c *Compiler) parseCatalog(schemas []string) error {
4141
contents := migrations.RemoveRollbackStatements(string(blob))
4242
c.schema = append(c.schema, contents)
4343

44-
// In database-only mode, we only need to collect schema files for migrations
45-
// but don't build the internal catalog from them
46-
if c.databaseOnlyMode {
47-
continue
48-
}
49-
5044
stmts, err := c.parser.Parse(strings.NewReader(contents))
5145
if err != nil {
5246
merr.Add(filename, contents, 0, err)
@@ -69,16 +63,9 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
6963
ctx := context.Background()
7064

7165
// In database-only mode, initialize the database connection before parsing queries
72-
if c.databaseOnlyMode {
73-
if c.pgAnalyzer != nil {
74-
if err := c.pgAnalyzer.EnsurePool(ctx, c.schema); err != nil {
75-
return nil, fmt.Errorf("failed to initialize database connection: %w", err)
76-
}
77-
}
78-
if c.sqliteAnalyzer != nil {
79-
if err := c.sqliteAnalyzer.EnsureConn(ctx, c.schema); err != nil {
80-
return nil, fmt.Errorf("failed to initialize database connection: %w", err)
81-
}
66+
if c.databaseOnlyMode && c.analyzer != nil {
67+
if err := c.analyzer.EnsureConn(ctx, c.schema); err != nil {
68+
return nil, fmt.Errorf("failed to initialize database connection: %w", err)
8269
}
8370
}
8471

@@ -138,28 +125,6 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
138125
return nil, fmt.Errorf("no queries contained in paths %s", strings.Join(c.conf.Queries, ","))
139126
}
140127

141-
// In database-only mode, build the catalog from the database after parsing all queries
142-
if c.databaseOnlyMode {
143-
if c.pgAnalyzer != nil {
144-
// Default to "public" schema if no specific schemas are specified
145-
schemas := []string{"public"}
146-
cat, err := c.pgAnalyzer.IntrospectSchema(ctx, schemas)
147-
if err != nil {
148-
return nil, fmt.Errorf("failed to introspect database schema: %w", err)
149-
}
150-
c.catalog = cat
151-
}
152-
if c.sqliteAnalyzer != nil {
153-
// SQLite uses "main" as the default schema
154-
schemas := []string{"main"}
155-
cat, err := c.sqliteAnalyzer.IntrospectSchema(ctx, schemas)
156-
if err != nil {
157-
return nil, fmt.Errorf("failed to introspect database schema: %w", err)
158-
}
159-
c.catalog = cat
160-
}
161-
}
162-
163128
return &Result{
164129
Catalog: c.catalog,
165130
Queries: q,

internal/compiler/engine.go

Lines changed: 10 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@ type Compiler struct {
3232
// databaseOnlyMode indicates that the compiler should use database-only analysis
3333
// and skip building the internal catalog from schema files (analyzer.database: only)
3434
databaseOnlyMode bool
35-
// pgAnalyzer is the PostgreSQL-specific analyzer used in database-only mode
36-
// for schema introspection
37-
pgAnalyzer *pganalyze.Analyzer
38-
// sqliteAnalyzer is the SQLite-specific analyzer used in database-only mode
39-
// for schema introspection
40-
sqliteAnalyzer *sqliteanalyze.Analyzer
4135
// expander is used to expand SELECT * and RETURNING * in database-only mode
4236
expander *expander.Expander
4337
}
@@ -70,17 +64,11 @@ func NewCompiler(conf config.SQL, combo config.CombinedSettings, parserOpts opts
7064
return nil, fmt.Errorf("analyzer.database: only requires database.uri or database.managed")
7165
}
7266
c.databaseOnlyMode = true
73-
// Create the SQLite analyzer for schema introspection
74-
c.sqliteAnalyzer = sqliteanalyze.New(*conf.Database)
75-
// Use the analyzer wrapped with cache for query analysis
76-
c.analyzer = analyzer.Cached(
77-
c.sqliteAnalyzer,
78-
combo.Global,
79-
*conf.Database,
80-
)
81-
// Create the expander using the sqliteAnalyzer as the column getter
82-
// The parser implements both Parser and format.Dialect interfaces
83-
c.expander = expander.New(c.sqliteAnalyzer, parser, parser)
67+
// Create the SQLite analyzer (implements Analyzer interface)
68+
sqliteAnalyzer := sqliteanalyze.New(*conf.Database)
69+
c.analyzer = analyzer.Cached(sqliteAnalyzer, combo.Global, *conf.Database)
70+
// Create the expander using the analyzer as the column getter
71+
c.expander = expander.New(c.analyzer, parser, parser)
8472
} else if conf.Database != nil {
8573
if conf.Analyzer.Database.IsEnabled() {
8674
c.analyzer = analyzer.Cached(
@@ -109,17 +97,11 @@ func NewCompiler(conf config.SQL, combo config.CombinedSettings, parserOpts opts
10997
return nil, fmt.Errorf("analyzer.database: only requires database.uri or database.managed")
11098
}
11199
c.databaseOnlyMode = true
112-
// Create the PostgreSQL analyzer for schema introspection
113-
c.pgAnalyzer = pganalyze.New(c.client, *conf.Database)
114-
// Use the analyzer wrapped with cache for query analysis
115-
c.analyzer = analyzer.Cached(
116-
c.pgAnalyzer,
117-
combo.Global,
118-
*conf.Database,
119-
)
120-
// Create the expander using the pgAnalyzer as the column getter
121-
// The parser implements both Parser and format.Dialect interfaces
122-
c.expander = expander.New(c.pgAnalyzer, parser, parser)
100+
// Create the PostgreSQL analyzer (implements Analyzer interface)
101+
pgAnalyzer := pganalyze.New(c.client, *conf.Database)
102+
c.analyzer = analyzer.Cached(pgAnalyzer, combo.Global, *conf.Database)
103+
// Create the expander using the analyzer as the column getter
104+
c.expander = expander.New(c.analyzer, parser, parser)
123105
} else if conf.Database != nil {
124106
if conf.Analyzer.Database.IsEnabled() {
125107
c.analyzer = analyzer.Cached(

internal/engine/postgresql/analyzer/analyze.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -482,9 +482,9 @@ func (a *Analyzer) IntrospectSchema(ctx context.Context, schemas []string) (*cat
482482
return cat, nil
483483
}
484484

485-
// EnsurePool initializes the database connection pool if not already done.
486-
// This is useful for accurate mode where we need to connect before analyzing queries.
487-
func (a *Analyzer) EnsurePool(ctx context.Context, migrations []string) error {
485+
// EnsureConn initializes the database connection pool if not already done.
486+
// This is useful for database-only mode where we need to connect before analyzing queries.
487+
func (a *Analyzer) EnsureConn(ctx context.Context, migrations []string) error {
488488
if a.pool != nil {
489489
return nil
490490
}

0 commit comments

Comments
 (0)