feat: Add PostgreSQL Extension Support#437
Conversation
e2bef36 to
60ee1be
Compare
Greptile SummaryThis PR adds PostgreSQL extension support to schema inspection and migration generation. The main changes are:
Confidence Score: 2/5These extension workflows need fixes before merging.
Important Files Changed
Reviews (1): Last reviewed commit: "refactor: streamline extension and colum..." | Re-trigger Greptile |
| for _, ext := range oldIR.Extensions { | ||
| if !newExtSet[ext] { | ||
| diff.droppedExtensions = append(diff.droppedExtensions, ext) |
There was a problem hiding this comment.
This records extensions that disappeared from the desired IR, but the drop generation path never reads droppedExtensions or emits DROP EXTENSION. When the last citext or hstore usage is removed, the migration can remove the dependent schema objects while leaving the extension installed, so the database does not converge to the desired state.
| Source: &ir.Extension{Name: ext}, | ||
| CanRunInTransaction: true, | ||
| } | ||
| collector.collect(context, fmt.Sprintf("CREATE EXTENSION IF NOT EXISTS %s;", ir.QuoteIdentifier(ext))) |
There was a problem hiding this comment.
The IR only carries extname, so this DDL always creates the extension in the default extension schema instead of the schema where the inspected extension objects live. The updated add_column_cross_schema_custom_type fixture installs hstore with CREATE EXTENSION ... SCHEMA utils, but the generated migration emits CREATE EXTENSION IF NOT EXISTS hstore; and then adds a column of type utils.hstore. On a target database without hstore, this creates public.hstore and the later utils.hstore reference still fails.
| if err := i.buildExtensions(ctx, schema, targetSchema); err != nil { | ||
| return nil, fmt.Errorf("failed to build extensions: %w", err) |
There was a problem hiding this comment.
Extension detection only happens after the desired SQL has already been applied to the temporary plan schema. If a desired file contains CREATE TABLE users (email citext); or an EXCLUDE constraint that needs btree_gist, ApplySchema fails with the missing type/operator before BuildIR can inspect dependencies and add the CREATE EXTENSION step. This means the new auto-detection path only works when the planning database already has the needed extension installed or the desired SQL creates it manually.
Summary
btree_gistfor EXCLUDE constraints,citext/hstorefor column types) by queryingpg_dependcatalog dependenciesCREATE EXTENSION IF NOT EXISTSstatements in migration output, ordered before all schema objects to satisfy dependenciesChanges
IR Layer
ir/ir.go: AddedExtensions []stringfield toIRstruct and newExtensionstruct implementingDiffSourceir/inspector.go: NewbuildExtensions()method that queriespg_catalog.pg_dependto find extensions used by constraints, classes, types, and functions in the target schema (excludesplpgsqland extension-internal objects)Diff Layer
internal/diff/diff.go: NewDiffTypeExtension, extension comparison logic inGenerateMigration(), andCREATE EXTENSION IF NOT EXISTSDDL generation at the top ofgenerateCreateSQL()Plan & Dump
internal/plan/schema_plan.go: AddedTypeExtensionto object ordering (first in dependency order)internal/dump/formatter.go: Addedextensionsdirectory to multi-file output and mapping for extension typeTests
ir/inspector_extension_test.go: Tests that empty schemas don't detect extensions, and schemas with EXCLUDE constraints correctly detectbtree_gisttestdata/diff/dependency/extension_btree_gist/: New test fixture for btree_gist extension with EXCLUDE USING gist constraintadd_pk,add_column_cross_schema_custom_typeto include expected extension output