Skip to content

Commit b126f17

Browse files
committed
feat: add SQLite support for database-only mode (analyzer.database: only)
This extends the database-only analyzer mode to support SQLite in addition to PostgreSQL: 1. Add EnsureConn, GetColumnNames, and IntrospectSchema methods to the SQLite analyzer for database-only mode functionality 2. Update compiler to handle SQLite database-only mode: - Add sqliteAnalyzer field to Compiler struct - Initialize SQLite analyzer when database-only mode is enabled - Build catalog from SQLite database via PRAGMA table_info 3. Add SQLite end-to-end test case for database-only mode The SQLite database-only mode uses PRAGMA table_info to introspect tables and columns, and prepares queries to get column names for star expansion. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]>
1 parent 850e049 commit b126f17

File tree

10 files changed

+338
-13
lines changed

10 files changed

+338
-13
lines changed

internal/compiler/compile.go

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,17 @@ func (c *Compiler) parseCatalog(schemas []string) error {
6868
func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
6969
ctx := context.Background()
7070

71-
// In database-only mode, initialize the database connection pool before parsing queries
72-
if c.databaseOnlyMode && c.pgAnalyzer != nil {
73-
if err := c.pgAnalyzer.EnsurePool(ctx, c.schema); err != nil {
74-
return nil, fmt.Errorf("failed to initialize database connection: %w", err)
71+
// 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+
}
7582
}
7683
}
7784

@@ -132,14 +139,25 @@ func (c *Compiler) parseQueries(o opts.Parser) (*Result, error) {
132139
}
133140

134141
// In database-only mode, build the catalog from the database after parsing all queries
135-
if c.databaseOnlyMode && c.pgAnalyzer != nil {
136-
// Default to "public" schema if no specific schemas are specified
137-
schemas := []string{"public"}
138-
cat, err := c.pgAnalyzer.IntrospectSchema(ctx, schemas)
139-
if err != nil {
140-
return nil, fmt.Errorf("failed to introspect database schema: %w", err)
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
141160
}
142-
c.catalog = cat
143161
}
144162

145163
return &Result{

internal/compiler/engine.go

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ type Compiler struct {
3535
// pgAnalyzer is the PostgreSQL-specific analyzer used in database-only mode
3636
// for schema introspection
3737
pgAnalyzer *pganalyze.Analyzer
38+
// sqliteAnalyzer is the SQLite-specific analyzer used in database-only mode
39+
// for schema introspection
40+
sqliteAnalyzer *sqliteanalyze.Analyzer
3841
// expander is used to expand SELECT * and RETURNING * in database-only mode
3942
expander *expander.Expander
4043
}
@@ -53,10 +56,32 @@ func NewCompiler(conf config.SQL, combo config.CombinedSettings, parserOpts opts
5356

5457
switch conf.Engine {
5558
case config.EngineSQLite:
56-
c.parser = sqlite.NewParser()
59+
parser := sqlite.NewParser()
60+
c.parser = parser
5761
c.catalog = sqlite.NewCatalog()
5862
c.selector = newSQLiteSelector()
59-
if conf.Database != nil {
63+
64+
if databaseOnlyMode {
65+
// Database-only mode requires a database connection
66+
if conf.Database == nil {
67+
return nil, fmt.Errorf("analyzer.database: only requires database configuration")
68+
}
69+
if conf.Database.URI == "" && !conf.Database.Managed {
70+
return nil, fmt.Errorf("analyzer.database: only requires database.uri or database.managed")
71+
}
72+
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)
84+
} else if conf.Database != nil {
6085
if conf.Analyzer.Database.IsEnabled() {
6186
c.analyzer = analyzer.Cached(
6287
sqliteanalyze.New(*conf.Database),
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"contexts": ["managed-db"],
3+
"env": {
4+
"SQLCEXPERIMENT": "analyzerv2"
5+
}
6+
}

internal/endtoend/testdata/accurate_sqlite/sqlite/stdlib/go/db.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/accurate_sqlite/sqlite/stdlib/go/models.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/accurate_sqlite/sqlite/stdlib/go/query.sql.go

Lines changed: 65 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- name: GetAuthor :one
2+
SELECT * FROM authors WHERE id = ?;
3+
4+
-- name: ListAuthors :many
5+
SELECT * FROM authors;
6+
7+
-- name: CreateAuthor :one
8+
INSERT INTO authors (name, bio) VALUES (?, ?) RETURNING *;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE authors (
2+
id INTEGER PRIMARY KEY,
3+
name TEXT NOT NULL,
4+
bio TEXT
5+
);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: "2"
2+
sql:
3+
- engine: sqlite
4+
schema: "schema.sql"
5+
queries: "query.sql"
6+
database:
7+
managed: true
8+
analyzer:
9+
database: "only"
10+
gen:
11+
go:
12+
package: "querytest"
13+
out: "go"

0 commit comments

Comments
 (0)