Guarded Apply
GuardedApplier applies a clean MergeResult only if the target database still
matches the expected live snapshot. This is useful when a merge plan was
reviewed earlier and live rows may have changed before apply.
use Merql\Merql;
use Merql\Snapshot\SnapshotStore;
$result = Merql::merge('base', 'ours', 'theirs');
$expectedLive = SnapshotStore::load('theirs');
$applied = Merql::applyGuarded($result, $expectedLive);
if ($applied->hasErrors()) {
foreach ($applied->errors() as $error) {
echo $error . "\n";
}
}Preconditions
Guarded SQL adds live-row preconditions to generated statements:
- updates require the target row identity to exist and non-identity column values to match the expected live row,
- deletes require the target row identity to exist and non-identity column values to match the expected live row,
- inserts require that the target identity does not already exist.
If any statement affects zero rows, MerQL treats the plan as stale. The
transaction is rolled back and the returned ApplyResult contains the error.
Selected Apply
Guarded apply works with selected merge results produced from a merge plan.
use Merql\Plan\ChangeGroupSelection;
use Merql\Plan\SelectedMergeResultFactory;
use Merql\Snapshot\SnapshotStore;
$selection = ChangeGroupSelection::fromIds([$plan->changeGroups[0]->id]);
$selected = (new SelectedMergeResultFactory())->fromChangeGroupSelection(
$plan,
$selection,
SnapshotStore::load($plan->baseSnapshot),
);
$applied = Merql::applyGuarded($selected, SnapshotStore::load($plan->theirsSnapshot));This lets a host application stage a subset of reviewed groups and still assert that live rows did not drift after plan creation.
SQL Preview
Use SqlGenerator::generateGuarded() to inspect the guarded statements without
executing them.
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;
$statements = SqlGenerator::generateGuarded(
$selected,
SnapshotStore::load($plan->theirsSnapshot),
);
foreach ($statements as $statement) {
echo $statement['sql'] . "\n";
}The generated statements are still parameterized. Preconditions are expressed
with additional WHERE clauses for updates/deletes and NOT EXISTS checks for
inserts.