NAME
DBIO::Diff::Base - Base class for DBIO driver diff orchestrators
VERSION
version 0.900004
DESCRIPTION
Base class for driver-specific diff orchestrators (DBIO::PostgreSQL::Diff, DBIO::SQLite::Diff, DBIO::MySQL::Diff). Provides the full public interface; subclasses implement only _build_operations.
ATTRIBUTES
source
The current (live) database model hashref. Required.
target
The desired (deployed from DBIO classes) database model hashref. Required.
operations
ArrayRef of diff operation objects. Built lazily. Each object must respond to as_sql and summary.
METHODS
contract_version
my $v = $class->contract_version;
Returns $CONTRACT_VERSION, the compatibility version of this base class's public interface -- independent of the dist $VERSION and unaffected by a release that changes no contract shape. See "CONTRACT VERSION" above and ADR 0024.
new
my $diff = $class->new(source => $source_model, target => $target_model);
Blesses the argument hash directly; no validation. source and target are the two canonical model hashrefs (see "CANONICAL MODEL" in DBIO::Introspect::Base) to compare.
diff_options
my @names = $class->diff_options;
The names of the options this diff class takes in new beside source, target and extensions. The default is the empty list. A driver whose diff class reads an option (foreign_keys_not_valid on PostgreSQL) returns its name here; "diff" in DBIO::Deploy::Base hands a caller's options on only when they are listed and throws on any other key.
has_changes
if ($diff->has_changes) { ... }
Returns true if there is at least one diff operation.
as_sql
my $sql = $diff->as_sql;
Returns all diff operations concatenated as a SQL migration script.
summary
my $text = $diff->summary;
Returns a human-readable summary of all diff operations.
classify
my $c = $diff->classify;
# { has_changes => 1, class => 'changing',
# counts => { additive => 1, changing => 2, destructive => 0 },
# refused => [] }
Classifies the diff by what it does to what already exists. Always returns a hash reference with these keys, which are part of the documented interface:
- has_changes
-
1 if there is at least one operation, else 0 (as "has_changes").
- class
-
One of
none(no operations),additive,changingordestructive-- the highest severity among the operations, in the order destructive > changing > additive.undefwhen any operation refuses (seerefused): a run that refuses has no classification. - counts
-
Hash reference
{ additive => N, changing => N, destructive => N }, one count per operation.undefwhen any operation refuses. - refused
-
Array reference of the
summarytexts of the operations whoseactionisrefuse; empty when nothing refuses. This is the only key that is filled for a refusing run besideshas_changes(ADR 0060).
Each operation is read through its action (an operation without an action method counts as undef):
refuse-
Goes to
refused, see above. create,add,add_value-
additive.
drop-
destructive -- unless the operation answers true to
replaced, the first half of a drop plus create of the same object, which is changing. - anything else
-
(
alter,modify,change,update,replace,move,own,enable_rls,disable_rls,set_persistence, no action, an unknown action) is changing: the conservative reading of an operation not known to be additive.
Counting is per operation, so a replaced pair counts once as changing (the drop) and once as additive (the create); the class is the maximum, here changing. A pair that a driver emits as drop plus create without marking the drop replaced (the SQLite index and view rebuild) counts as destructive, conservatively.
destructive_operations
my @ops = $diff->destructive_operations;
Returns the operations a run must be released for, in diff order: every operation "classify" counts as destructive (a drop that is not the first half of a drop plus create) and every operation that reports a possibly lossy change through the optional operation method lossy.
An operation may define lossy. It answers true when the change it writes can lose or alter stored data although it is not a drop -- a column type change whose implicit cast can round or truncate is the typical case. An operation without the method is not lossy. "apply" in DBIO::Deploy::Base runs a diff with such an operation only with allow_destructive => 1, as it does for a destructive one. "classify" is not affected: a lossy operation keeps the class of its action.
CONTRACT VERSION
This class exposes an independent compatibility version, distinct from $VERSION (the dist version injected by Dist::Zilla's VersionFromMainModule):
my $v = $class->contract_version;
$CONTRACT_VERSION bumps when the diff orchestrator's public interface (source, target, operations, has_changes, as_sql, summary, classify, destructive_operations) or the operation-object contract (DBIO::Diff::Op) changes. The dist $VERSION bumps on every release, but two core releases at the same contract version remain wire-compatible. Out-of-tree drivers should record the contract version they were last tested against and compare it against core's at load time, warning (or strict-failing under DBIO_STRICT_CONTRACT) when the shapes have drifted. See docs/adr/ for the contract-version policy.
AUTHOR
DBIO & DBIx::Class Authors
COPYRIGHT AND LICENSE
Copyright (C) 2026 DBIO Authors Portions Copyright (C) 2005-2025 DBIx::Class Authors Based on DBIx::Class, heavily modified.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.