Documentation
¶
Overview ¶
Package diff performs pure relational comparison between live and desired database schemas.
Dependency rule: diff is pure. It depends only on internal/schema, internal/scope, and internal/plan. It has zero dependencies on database/sql, context, or dialect rendering.
Index ¶
- func RefuseUnmanagedCatalogRecreates(desired *schema.CatalogSpec, live *CatalogLiveState, targetSchema string) error
- type CatalogLiveState
- type Change
- func CatalogDiff(desired *schema.CatalogSpec, live *CatalogLiveState, targetSchema string) []Change
- func Diff(live, desired *schema.Schema, targetSchema, shadowSchema string, ...) ([]Change, error)
- func DiffWithMappings(live, desired *schema.Schema, targetSchema, shadowSchema string, ...) ([]Change, error)
- func RolesDiff(desired *schema.RolesSpec, live *RoleState, targetSchema string) []Change
- type EventTriggerState
- type LiveRoleAttrs
- type PublicationState
- type ReplicationSlotState
- type RoleACLGrant
- type RoleState
- type SubscriptionState
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RefuseUnmanagedCatalogRecreates ¶
func RefuseUnmanagedCatalogRecreates(desired *schema.CatalogSpec, live *CatalogLiveState, targetSchema string) error
RefuseUnmanagedCatalogRecreates fails closed when a desired publication or event trigger shares a name with an operator-created live object whose definition cannot be reconciled without DROP+CREATE. CatalogDiff never emits that DROP (marker-narrow policy); without this check Sync would silently leave the desired state unconverged.
Types ¶
type CatalogLiveState ¶
type CatalogLiveState struct {
Publications map[string]*PublicationState
EventTriggers map[string]*EventTriggerState
Subscriptions map[string]*SubscriptionState
ReplicationSlots map[string]*ReplicationSlotState
}
CatalogLiveState is the live publication/event-trigger/subscription/slot state inspected from the database catalogs.
type Change ¶
type Change struct {
Type plan.ChangeType
Schema string
Table string
Column *schema.Column
OldColumn *schema.Column
Index *schema.Index
OldIndex *schema.Index
ForeignKey *schema.ForeignKey
Check *schema.CheckConstraint
Enum *schema.Enum
OldEnum *schema.Enum
EnumValue string
OldEnumValue string
TableData *schema.Table
Extension *schema.Extension
Policy *schema.Policy
OldPolicy *schema.Policy
Routine *schema.Routine
Domain *schema.Domain
OldDomain *schema.Domain
RangeType *schema.RangeType
CompositeType *schema.CompositeType
CompositeAttr *schema.CompositeAttribute
Sequence *schema.Sequence
OldSequence *schema.Sequence
Role *schema.Role
Grant *schema.Grant
Publication *schema.Publication
OldPublication *schema.Publication
EventTrigger *schema.EventTrigger
OldEventTrigger *schema.EventTrigger
Subscription *schema.Subscription
OldSubscription *schema.Subscription
ReplicationSlot *schema.ReplicationSlot
Trigger *schema.Trigger
View *schema.View
Replace bool
Destructive bool
IsRenameCandidate bool
OldComment string
// Routine signature drift and dependency rebuild flags
IsSignatureChange bool
IsDependencyRebuild bool
// Structural flags for hazard analysis
ColumnNotNull bool
ColumnHasDefault bool
// Column change flags
TypeChanged bool
TypeNarrowed bool
NullChanged bool
DefaultChanged bool
GeneratedChanged bool
// Unmanaged object dependencies (views, triggers, functions depending on this table/column)
UnmanagedDeps []string
// Partitioning metadata
ParentTable string
PartitionBounds string
ParentHasDefault bool
IsPendingDetach bool
}
Change represents a pure difference between live and desired database schemas.
func CatalogDiff ¶
func CatalogDiff(desired *schema.CatalogSpec, live *CatalogLiveState, targetSchema string) []Change
CatalogDiff computes publication, event-trigger, subscription, and logical-slot sync steps from the desired CatalogSQL state and the live catalog state.
Destructive drops are narrow: publications, event triggers, and subscriptions are dropped only when they carry the grizzle-managed marker comment — including the recreate (DROP+CREATE) path used when definition drift cannot be expressed as ALTER. Operator-created catalog objects without the marker are never swept. Standalone logical slots never auto-sweep (COMMENT ON unsupported); drops require an explicit pg_drop_replication_slot. Objects named in the desired state are managed for create/alter; drops still require the marker.
targetSchema qualifies unqualified table names in desired publications.
func Diff ¶
func Diff(live, desired *schema.Schema, targetSchema, shadowSchema string, filters scope.Filters) ([]Change, error)
Diff compares live and desired schemas using the given scope filters and returns pure changes.
func DiffWithMappings ¶
func DiffWithMappings(live, desired *schema.Schema, targetSchema, shadowSchema string, filters scope.Filters, schemaMappings map[string]string) ([]Change, error)
DiffWithMappings compares live and desired schemas using schemaMappings for normalization and returns pure changes.
func RolesDiff ¶
RolesDiff compares the desired RolesSpec (parsed from RolesSQL) with live role/ACL state and returns pure changes.
Scope rules:
- Roles are created for every desired declaration and for grantees referenced by grants (NOLOGIN group roles), stamped with the managed-role marker comment.
- Live roles carrying the marker that are absent from the desired spec are dropped behind AllowDropRole; operator-created roles are never swept.
- Grants are diffed per (object, grantee): missing privileges GRANT, surplus privileges REVOKE (gated by AllowRevoke). Grants to grantees outside the managed set are operator state and left untouched.
- ACL grants held by roles being dropped are revoked before DROP ROLE so PostgreSQL can remove the role even when explicit ACL dependencies remain.
- Grant-option drift is reconciled by re-grant (option missing) or revoke + re-grant (option unwanted).
targetSchema qualifies unqualified TABLE/SEQUENCE object names so desired grants written against the working schema match the schema-qualified names reported by ACL introspection.
type EventTriggerState ¶
type EventTriggerState struct {
Name string
// Managed marks a live event trigger stamped with the grizzle-managed
// marker comment.
Managed bool
Event string
Tags []string
// Function is the canonical schema-qualified routine identity, including
// identity arguments when inspected from PostgreSQL.
Function string
Enabled bool
}
EventTriggerState is the dialect-independent live event-trigger snapshot consumed by CatalogDiff.
type LiveRoleAttrs ¶
type LiveRoleAttrs struct {
CanLogin bool
ConnLimit int
ValidUntil string
Inherit bool
CreateDB bool
CreateRole bool
HasPassword bool
PasswordMatches bool // true when no desired password or hashes match
Config map[string]string
}
LiveRoleAttrs is the live attribute snapshot for one role.
type PublicationState ¶
type PublicationState struct {
Name string
// Managed marks a live publication stamped with the grizzle-managed
// marker comment. Only managed live-only publications are droppable.
Managed bool
AllTables bool
Tables []string // canonical schema-qualified identities
Schemas []string // canonical identifiers
PublishInsert bool
PublishUpdate bool
PublishDelete bool
PublishTruncate bool
}
PublicationState is the dialect-independent live publication snapshot consumed by CatalogDiff.
type ReplicationSlotState ¶
type ReplicationSlotState struct {
Name string
Plugin string
Temporary bool
// ActivePID is non-nil when a backend holds the slot; drops are refused.
ActivePID *int
// OwnedBySubscription is true when this slot name matches a live
// subscription's subslotname; such slots are not managed separately.
OwnedBySubscription bool
}
ReplicationSlotState is the dialect-independent live logical slot snapshot. Replication slots do not support COMMENT ON; Managed is unused for sweep decisions — live-only slots are never auto-dropped.
type RoleACLGrant ¶
type RoleACLGrant struct {
Grantee string // role name or PUBLIC
ObjectKind string // TABLE, SEQUENCE, DATABASE, SCHEMA, FUNCTION
ObjectName string // canonical, schema-qualified where applicable
Privileges []string // sorted privilege_type values
GrantOptions []string // subset of Privileges held WITH GRANT OPTION
}
RoleACLGrant is one live ACL entry (grantee, object) with its privileges.
type RoleState ¶
type RoleState struct {
// RoleNames maps canonical PostgreSQL role identity -> catalog name
// (non-system roles).
RoleNames map[string]string
// ManagedRoles are canonical names of roles stamped with the
// grizzle-managed marker comment.
ManagedRoles map[string]bool
// RoleAttrs maps canonical role identity -> live attributes.
RoleAttrs map[string]*LiveRoleAttrs
// Grants is the live ACL inventory.
Grants []*RoleACLGrant
}
RoleState is the live role/ACL snapshot consumed by RolesDiff. It is built by the dialect layer (postgres.InspectLiveRoles) so this package stays free of dialect imports.
type SubscriptionState ¶
type SubscriptionState struct {
Name string
// Managed marks a live subscription stamped with the grizzle-managed
// marker comment. Only managed live-only subscriptions are droppable.
Managed bool
ConnInfo string
SlotName string
Publications []string
Enabled bool
}
SubscriptionState is the dialect-independent live subscription snapshot consumed by CatalogDiff.