diff --git a/cmd/util/ignoreloader.go b/cmd/util/ignoreloader.go index 59c133b4..d845569d 100644 --- a/cmd/util/ignoreloader.go +++ b/cmd/util/ignoreloader.go @@ -36,6 +36,7 @@ type TomlConfig struct { Sequences SequenceIgnoreConfig `toml:"sequences,omitempty"` Privileges PrivilegeIgnoreConfig `toml:"privileges,omitempty"` DefaultPrivileges DefaultPrivilegeIgnoreConfig `toml:"default_privileges,omitempty"` + Constraints ConstraintIgnoreConfig `toml:"constraints,omitempty"` } // TableIgnoreConfig represents table-specific ignore configuration @@ -80,6 +81,12 @@ type DefaultPrivilegeIgnoreConfig struct { Patterns []string `toml:"patterns,omitempty"` } +// ConstraintIgnoreConfig represents constraint-specific ignore configuration +// Patterns match constraint names, including optionally qualified names +type ConstraintIgnoreConfig struct { + Patterns []string `toml:"patterns,omitempty"` +} + // LoadIgnoreFileWithStructure loads the .pgschemaignore file using the structured TOML format // and converts it to the simple IgnoreConfig structure func LoadIgnoreFileWithStructure() (*ir.IgnoreConfig, error) { @@ -113,6 +120,7 @@ func LoadIgnoreFileWithStructureFromPath(filePath string) (*ir.IgnoreConfig, err Sequences: tomlConfig.Sequences.Patterns, Privileges: tomlConfig.Privileges.Patterns, DefaultPrivileges: tomlConfig.DefaultPrivileges.Patterns, + Constraints: tomlConfig.Constraints.Patterns, } return config, nil diff --git a/ir/ignore.go b/ir/ignore.go index a4f6d638..c7a73590 100644 --- a/ir/ignore.go +++ b/ir/ignore.go @@ -24,6 +24,7 @@ type IgnoreConfig struct { Sequences []string `toml:"sequences,omitempty"` Privileges []string `toml:"privileges,omitempty"` DefaultPrivileges []string `toml:"default_privileges,omitempty"` + Constraints []string `toml:"constraints,omitempty"` } // ShouldIgnoreTable checks if a table should be ignored based on the patterns @@ -114,6 +115,14 @@ func (c *IgnoreConfig) ShouldIgnoreDefaultPrivilege(grantee string) bool { return c.shouldIgnore(grantee, c.DefaultPrivileges) } +// ShouldIgnoreConstraint checks if a constraint should be ignored based on the patterns +func (c *IgnoreConfig) ShouldIgnoreConstraint(constraintName string) bool { + if c == nil { + return false + } + return c.shouldIgnore(constraintName, c.Constraints) +} + // shouldIgnore checks if a name should be ignored based on the patterns // Patterns support wildcards (*) and negation (!) // Negation patterns (starting with !) take precedence over inclusion patterns diff --git a/ir/inspector.go b/ir/inspector.go index 23a0a5c4..574f5a51 100644 --- a/ir/inspector.go +++ b/ir/inspector.go @@ -447,6 +447,18 @@ func (i *Inspector) buildConstraints(ctx context.Context, schema *IR, targetSche constraintType = constraint.ConstraintType.String } + // Check if constraint should be ignored. Prefer a fully qualified + // identifier to avoid unintentionally ignoring same-named constraints + // on unrelated tables, while still supporting bare constraint-name + // matching for backwards compatibility. + if i.ignoreConfig != nil { + qualifiedConstraintName := fmt.Sprintf("%s.%s.%s", schemaName, tableName, constraintName) + if i.ignoreConfig.ShouldIgnoreConstraint(qualifiedConstraintName) || + i.ignoreConfig.ShouldIgnoreConstraint(constraintName) { + continue + } + } + // Extract column name from sql.NullString columnName := "" if constraint.ColumnName.Valid {