Documentation
¶
Overview ¶
Package introspect reads a Postgres schema out of pg_catalog and returns the same *schema.Registry the DSL produces.
That symmetry is the point. A registry from here can be handed to migrate.Diff as the current state, which makes generating a migration and adopting an existing database the same machinery pointed in opposite directions (ADR-0014). It is also the only way to check the diff engine against a real database: render a schema to DDL, apply it, read it back, and the diff between what went in and what came out must be empty.
Why this is not in migrate ¶
migrate does not connect to a database and says so in its own documentation: it produces files, and a runner applies them. This package does connect, so it is separate, and migrate stays a pure function over two data structures.
The connection ¶
Everything here works through a sqlb.Executor, so a pool, a connection or a transaction the caller already holds all work, and reading a catalog uses the same handle as querying a table (ADR-0040).
What cannot be represented ¶
The DSL is narrower than Postgres, and the failure that matters is dropping something quietly — a schema that looks complete, describes the database incorrectly, and produces a migration that reverses work nobody meant to reverse. So every construct this cannot express is collected into a Report rather than skipped. Read it. A Report with entries means the emitted schema is not the whole database.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Options ¶
type Options struct {
// Schema is the Postgres schema to read. Defaults to "public".
Schema string
// Module, when set, produces a module registry (schema.NewModule) and
// strips the module's prefix from every table name it finds, so that a
// database whose tables are called billing_invoices imports as a module
// named billing holding a table called invoices.
//
// Tables without the prefix are left alone and reported, since a module
// registry would silently rename them on the way back out.
Module string
// Only limits the import to the named tables. Empty reads everything,
// which is what an import of a database sqlb is taking over wants.
//
// A drift gate wants the opposite. An incremental adoption declares a
// handful of tables while the database holds dozens, and diffing a
// declaration of five tables against an import of sixty-nine reports the
// other sixty-four as tables to drop — so the gate has to narrow one side,
// and this is where it is narrowed (issue #54). Names are storage names,
// before any module prefix is stripped, because that is what the database
// calls them.
//
// A named table that is not in the database is reported rather than
// ignored: a typo in this list would otherwise silently shrink what the
// gate checks, which is the one failure a gate must not have.
Only []string
// Exclude drops the named tables from the import. It applies after Only,
// so the two compose — read this schema except the queue tables — and it
// is the right shape for the migration-history table every runner keeps,
// which no declaration will ever describe.
Exclude []string
}
Options control what is read and how it is named.
type Report ¶
type Report struct {
Skipped []Skip
}
Report collects everything in the database that the DSL cannot express.
It exists because the dangerous failure here is a quiet one. A schema missing a construct still compiles, still validates, and still produces a migration — one that proposes undoing whatever it failed to see. ADR-0014 names silently dropping as the failure mode to watch for hardest, so nothing is dropped without an entry here.
An empty Report means the registry describes the database completely. A non-empty one means it does not, and the difference is yours to reconcile.
func Registry ¶
func Registry(ctx context.Context, db sqlb.Executor, opts Options) (*schema.Registry, *Report, error)
Registry reads the database and returns the schema it describes, along with a Report of everything that could not be represented.
The registry is validated before it is returned: a registry that does not validate would produce DDL for a schema that cannot exist, and finding that out here beats finding it out from a migration.
Capabilities are not inferred. Nothing in a database says which columns should be filterable or exposed over REST, and guessing would publish columns nobody chose to publish — so everything imports with no capabilities at all and widening them is a deliberate, reviewable edit (ADR-0014).
func (*Report) Err ¶
Err returns an error describing everything skipped, or nil if nothing was.
It is offered rather than returned from Registry because whether an unrepresentable construct is fatal depends on what you are doing. Adopting a database wants to see the list and carry the remainder over by hand; round-tripping a schema this package generated wants any entry at all to be a failure.
type Skip ¶
type Skip struct {
Table string
Object string // the constraint, index or column it concerns
Reason string
// Def is the definition Postgres reports, so the construct can be carried
// across by hand without going back to the database to look it up.
Def string
}
Skip is one construct that did not survive the import, where it was, and what to do about it.