/
githubmirror
/
sqlc
Обзор
Документация
Войти
/
githubmirror
/
sqlc
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
internal/analyzer/analyzer.go
130 строк
3 KB
Kyle Gray
feat(postgresql): add analyzerv2 experiment for database-only analysis (#4237)
23 дек 2025, 02:11
Не верифицирован
23 дек 2025, 02:11
68b2089
Код
Авторство
О чём код?
package analyzer import ( "context" "encoding/json" "fmt" "hash/fnv" "log/slog" "os" "path/filepath" "google.golang.org/protobuf/proto" "github.com/sqlc-dev/sqlc/internal/analysis" "github.com/sqlc-dev/sqlc/internal/cache" "github.com/sqlc-dev/sqlc/internal/config" "github.com/sqlc-dev/sqlc/internal/info" "github.com/sqlc-dev/sqlc/internal/sql/ast" "github.com/sqlc-dev/sqlc/internal/sql/named" ) type CachedAnalyzer struct { a Analyzer config config.Config configBytes []byte db config.Database } func Cached(a Analyzer, c config.Config, db config.Database) *CachedAnalyzer { return &CachedAnalyzer{ a: a, config: c, db: db, } } // Create a new error here func (c *CachedAnalyzer) Analyze(ctx context.Context, n ast.Node, q string, schema []string, np *named.ParamSet) (*analysis.Analysis, error) { result, rerun, err := c.analyze(ctx, n, q, schema, np) if rerun { if err != nil { slog.Warn("first analysis failed with error", "err", err) } return c.a.Analyze(ctx, n, q, schema, np) } return result, err } func (c *CachedAnalyzer) analyze(ctx context.Context, n ast.Node, q string, schema []string, np *named.ParamSet) (*analysis.Analysis, bool, error) { // Only cache queries for managed databases. We can't be certain the // database is in an unchanged state otherwise if !c.db.Managed { return nil, true, nil } dir, err := cache.AnalysisDir() if err != nil { return nil, true, err } if c.configBytes == nil { c.configBytes, err = json.Marshal(c.config) if err != nil { return nil, true, err } } // Calculate cache key h := fnv.New64() h.Write([]byte(info.Version)) h.Write(c.configBytes) for _, m := range schema { h.Write([]byte(m)) } h.Write([]byte(q)) key := fmt.Sprintf("%x", h.Sum(nil)) path := filepath.Join(dir, key) if _, err := os.Stat(path); err == nil { contents, err := os.ReadFile(path) if err != nil { return nil, true, err } var a analysis.Analysis if err := proto.Unmarshal(contents, &a); err != nil { return nil, true, err } return &a, false, nil } result, err := c.a.Analyze(ctx, n, q, schema, np) if err == nil { contents, err := proto.Marshal(result) if err != nil { slog.Warn("unable to marshal analysis", "err", err) return result, false, nil } if err := os.WriteFile(path, contents, 0644); err != nil { slog.Warn("saving analysis to disk failed", "err", err) return result, false, nil } } return result, false, err } func (c *CachedAnalyzer) Close(ctx context.Context) error { return c.a.Close(ctx) } func (c *CachedAnalyzer) EnsureConn(ctx context.Context, migrations []string) error { return c.a.EnsureConn(ctx, migrations) } func (c *CachedAnalyzer) GetColumnNames(ctx context.Context, query string) ([]string, error) { return c.a.GetColumnNames(ctx, query) } type Analyzer interface { Analyze(context.Context, ast.Node, string, []string, *named.ParamSet) (*analysis.Analysis, error) Close(context.Context) error // EnsureConn initializes the database connection with the given migrations. // This is required for database-only mode where we need to connect before analyzing queries. EnsureConn(ctx context.Context, migrations []string) error // GetColumnNames returns the column names for a query by preparing it against the database. // This is used for star expansion in database-only mode. GetColumnNames(ctx context.Context, query string) ([]string, error) }