DBIO
view release on metacpan or search on metacpan
docs/adr/0021-constraint-name-optional-canonical-fk-key.md view on Meta::CPAN
So the field is present nearly everywhere; only the **key name** is
unstandardised (`constraint_name` vs `_constraint_name`), and Sybase alone drops
it on the floor. A cross-driver contract field-name is exactly the kind of
family-wide rule that, per the ownership lesson of ADR 0018, belongs in core and
not in any one driver's repo. This ADR is a sibling to 0018 in spirit: it makes
the naming call once, here, with authority over the whole family.
## Decision
1. `constraint_name` becomes an **optional** canonical foreign-key key in the
`DBIO::Introspect::Base` "CANONICAL MODEL" `foreign_keys` section, alongside
the five existing keys. It follows the same "optionally" precedent that the
`columns` section already sets for `is_auto_increment`: a driver that can
introspect a stable server-assigned FK name **should** carry it; a driver
whose engine cannot omits it, and the model stays valid either way. It is not
promoted to a required key.
2. The blessed key name is **`constraint_name`** (bare, no leading underscore).
The `_constraint_name` underscore variants â DB2, Informix, and the
PostgreSQL `table_fk_info` relationship path â are non-conformant and realign
to `constraint_name`.
3. `table_fk_info` (`lib/DBIO/Introspect/Base.pm:267`), the relationship/generation
contract method consumed by `DBIO::Generate`, is **not** changed by this
decision. Nothing on the generation path consumes the FK name today, so
threading it through there would be speculative. This ADR notes it only as a
possible future surface; the decision does not touch it now.
4. The motivating consumer is the **Diff/Deploy** path (ADR 0007). A driver's
`Diff::ForeignKey` reads `model->{foreign_keys}` directly; when
`constraint_name` is present it **should** prefer the real server name for
`DROP`/`ALTER` instead of a deterministically generated name.
## Rationale
The constraint name is already a first-class part of how every driver builds its
FK model â it is the grouping key, and core's helper documents it as such. The
only thing missing was a *blessing* in the canonical model and a single agreed
spelling. Recording it as optional rather than required matches reality: not
every engine exposes a stable, reusable server-side FK identifier, and a driver
that cannot must not be made non-conformant for lacking one. The `is_auto_increment`
precedent in the `columns` section is the established shape for "carry it if you
have it" â reusing that pattern keeps the model honest and avoids forcing drivers
to fabricate a value.
Standardising on the bare name (not `_constraint_name`) follows the rest of the
canonical model, where every section key is bare; the underscore variants were
local accidents, not a deliberate convention, and a single spelling is what makes
a *cross-driver* consumer like Diff able to read the field uniformly. Leaving
`table_fk_info` untouched is simplicity-first: no generation-path code reads the
name, so adding it there would be an abstraction with no caller.
The decision belongs in core because it is a family-wide field-name contract, and
ADR 0018 already established that a family rule recorded in a single driver's repo
carries no authority over the others. Blessing the key here gives every driver â
and the Diff layer that spans them â one source for the rule.
## Consequences
- **Sybase karr #14 is unblocked and becomes purely driver-local.** No core code
change is required; the contract blessing is enough. Sybase stops dropping the
name in `_group_fks_by_constraint`, carries `constraint_name` into
`model->{foreign_keys}`, and has `DBIO::Sybase::Diff::ForeignKey` prefer the
real server name for `DROP` (falling back to the deterministically generated
name only when the name is absent). This is the FK drop/alter fidelity gap that
follows the FK diff op shipped in Sybase karr #11.
- **Drivers using `_constraint_name` realign to bare `constraint_name`** â DB2,
Informix, and the PostgreSQL `table_fk_info` relationship path. Each is tracked
as a per-driver follow-up ticket on that driver's own board (driver-repo work).
- **MSSQL and the PostgreSQL `foreign_keys` section are already conformant** and
need no change.
- **`constraint_name` must NOT be added to the compared field set of the FK
comparator.** `changed_fk_fields` (core; ADR 0019) compares FK *attributes*, not
identity. The constraint name is FK metadata for DROP/ALTER fidelity, not a
semantic attribute of the relationship â adding it to the compared fields would
make two otherwise-identical FKs that happen to carry different server-assigned
names phantom-diff on every upgrade. It is read for DROP targeting, never
compared.
- `table_fk_info` may later carry the name if a generation-path consumer appears;
until then it is deliberately left alone.
Relates to ADR 0007 (native diff/deploy layer), ADR 0018 (family-policy ownership
pattern), and ADR 0019 (FK comparator and desired-state skip); and to Sybase karr
#11 (FK diff op shipped) and #14 (this follow-up).
( run in 1.682 second using v1.01-cache-2.11-cpan-5e09290becf )