viewdeps

package
v0.1.25 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 30, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package viewdeps finds, drops, and restores the views and materialized views that transitively depend on a set of tables, so DDL PostgreSQL refuses while a dependent view exists — DROP TABLE, DROP COLUMN, ALTER COLUMN TYPE — can proceed.

Discovery walks pg_depend/pg_rewrite rather than matching view names, so it is complete regardless of how a view is named or which schema it lives in. A name-convention sweep silently misses a view outside the connection's search_path — the DROP resolves to nothing and succeeds — and the blocked DDL then fails much later with a confusing error.

The package deliberately depends only on the standard library so callers can use it with any driver: *sql.DB, *sql.Tx and gorm's connection pool all satisfy Querier as-is.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Restore

func Restore(ctx context.Context, exec Exec, defs []Definition) error

Restore recreates definitions in the order given, which Dependents guarantees is dependency order. The first failure aborts and returns a *RestoreError naming the view and carrying its DDL.

Types

type Definition

type Definition struct {
	View
	// SQL is the view body from pg_get_viewdef. Note this is the *expanded*
	// definition: a view written as "SELECT a.*" comes back with every column
	// listed, so restoring after a column was dropped fails loudly rather than
	// silently changing the view's shape.
	SQL string
	// Indexes are complete CREATE INDEX statements. Materialized views only —
	// and load-bearing, since REFRESH ... CONCURRENTLY requires a unique index.
	Indexes []string
	Owner   string
	Comment string
	Grants  []string
}

Definition is everything needed to recreate a view exactly as it was. It is read from the catalog before the view is dropped, so a view no migration owns survives a schema change instead of blocking it or being lost.

func Capture

func Capture(ctx context.Context, q Querier, views []View) ([]Definition, error)

Capture reads full definitions for views, preserving the given order.

func (Definition) CreateStatements

func (d Definition) CreateStatements() []string

CreateStatements returns the ordered DDL that recreates the view: the view itself, then owner, indexes, comment and grants. Materialized views are created WITH DATA so they are queryable immediately — an unpopulated materialized view errors on every read until someone refreshes it.

type DropOptions

type DropOptions struct {
	// Tables whose dependent views block the pending DDL. Empty is a no-op.
	Tables []Table
	// Query reads the dependency graph. Required.
	Query Querier
	// Exec runs each DROP and each restore statement. Required.
	Exec Exec
	// Owned reports whether the caller recreates this view itself. Owned views
	// are dropped and left to the caller — restoring them from the captured
	// definition would resurrect a stale one. Unowned views are captured before
	// the drop and rebuilt by the returned restore func. Nil owns nothing.
	Owned func(View) bool
	// Logf, when set, receives one line per dropped view.
	Logf func(format string, args ...any)
}

DropOptions configures Sweep.

type Exec

type Exec func(ctx context.Context, stmt string) error

Exec runs a single DDL statement. Callers supply the execution policy: the migrate package wraps each statement in a bounded lock_timeout with retry, and a gorm caller routes through *gorm.DB so an open transaction stays in scope.

type Querier

type Querier interface {
	QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
}

Querier reads the dependency graph. *sql.DB, *sql.Tx, *sql.Conn and gorm's ConnPool all satisfy it without an adapter.

type RestoreError

type RestoreError struct {
	View       View
	Statements []string
	Err        error
}

RestoreError reports a view that was dropped to allow a schema change and could not be recreated. It carries the full DDL so an operator can replay it by hand — the database is otherwise migrated correctly but missing the view.

func (*RestoreError) Error

func (e *RestoreError) Error() string

func (*RestoreError) Unwrap

func (e *RestoreError) Unwrap() error

type Table

type Table struct {
	Schema string
	Name   string
}

Table identifies a relation whose dependents must be cleared. An empty Schema is resolved through the connection's search_path, which is usually what a caller migrating its own database wants; set it only to target a specific schema.

func Tables

func Tables(schema string, names ...string) []Table

Tables builds refs for several relations in one schema. An empty schema resolves through search_path.

func (Table) Qualified

func (t Table) Qualified() string

Qualified renders the table for to_regclass. An empty Schema is left unqualified deliberately: forcing "public" would target the wrong relation whenever the connection runs under a different search_path.

type View

type View struct {
	Schema string
	Name   string
	Kind   string
}

View identifies a live view or materialized view. Kind is pg_class.relkind: "v" for a view, "m" for a materialized view.

func Dependents

func Dependents(ctx context.Context, q Querier, tables []Table) ([]View, error)

Dependents returns every view and materialized view that transitively depends on any of tables, in dependency order: a view always follows everything it reads. Tables that do not exist are ignored; the tables themselves are never returned.

func Lookup

func Lookup(ctx context.Context, q Querier, names ...string) ([]View, error)

Lookup resolves relation names to schema-qualified view refs, skipping names that do not exist or name something that is not a view.

func Sweep

func Sweep(ctx context.Context, opts DropOptions) ([]View, func(context.Context) error, error)

Sweep drops every view that transitively depends on opts.Tables and returns the views it dropped plus a func that restores the unowned ones.

Call the restore func after the schema change, and after whatever recreates the owned views — an unowned view may be built on top of one of them. Restoring is not atomic with the DDL; a failure returns a *RestoreError carrying the DDL so the view can be replayed by hand.

func (View) DropStatement

func (v View) DropStatement() string

DropStatement returns the schema-qualified, identifier-quoted DROP. CASCADE is unconditional: a view built on this one is itself a dependent that has already been captured, so taking it here is both safe and necessary.

func (View) Materialized

func (v View) Materialized() bool

Materialized reports whether the view holds its own copy of the data.

func (View) Qualified

func (v View) Qualified() string

Qualified renders the view schema-qualified. Unlike Table, a View always carries the schema the catalog reported, so this is never ambiguous.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL