コンテンツへスキップ

フィルター

フィルターは、スナップショットに含めるデータを制御します。キャッシュテーブルを除外したり、変化しやすいタイムスタンプ列を無視したり、一時的な行をスキップしたりできます。フィルターはスナップショット取得時に適用され、後続のすべての操作(差分比較、マージ、適用)に影響します。

PHP
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Snapshot\Snapshotter;

$snapshotter = new Snapshotter($connection);

$snapshot = $snapshotter->capture('baseline', filters: [
    TableFilter::exclude(['sessions', 'cache_*']),
    ColumnFilter::ignore(['updated_at', 'modified_date']),
]);

TableFilter

スナップショットに含めるテーブルを制御します。PHPのfnmatch()を使ったglobパターンに対応しています。

テーブルを除外する

PHP
use Merql\Filter\TableFilter;

$filter = TableFilter::exclude(['sessions', 'cache_*', 'wp_*_log']);

除外パターンに一致するテーブルはスナップショットから省かれます。*ワイルドカードは任意の文字列に一致します。

テーブルを含める

PHP
$filter = TableFilter::include(['posts', 'comments', 'users']);

includeパターンに一致するテーブルのみが取得され、それ以外はすべて除外されます。

仕組み

フィルターのapply()メソッドはテーブル名のリストを受け取り、フィルター後のサブセットを返します。

PHP
$allTables = ['posts', 'comments', 'sessions', 'cache_pages', 'users'];

$filter = TableFilter::exclude(['sessions', 'cache_*']);
$filtered = $filter->apply($allTables);
// ['posts', 'comments', 'users']

$filter = TableFilter::include(['posts', 'users']);
$filtered = $filter->apply($allTables);
// ['posts', 'users']

別々のフィルターインスタンスでincludeパターンとexcludeパターンの両方を指定した場合、excludeが先に評価されます。保持するには、テーブルがどのexcludeパターンにも一致せず、少なくとも1つのincludeパターンに一致する必要があります。

ColumnFilter

取得中に行データから特定の列を削除します。書き込みのたびに値が変わり、誤った差分を引き起こす可能性のある変動列に便利です。

PHP
use Merql\Filter\ColumnFilter;

$filter = ColumnFilter::ignore(['updated_at', 'modified_date', 'last_login']);

よくある使用例

  • 保存のたびに変化するupdated_at / modified_atタイムスタンプ。
  • 自動的に増加するrevisionカウンター。
  • session_tokenなどの一時的なフィールド。

仕組み

フィルターは行キーの計算後、各行から指定された列を取り除きます。

PHP
$filter = ColumnFilter::ignore(['updated_at']);

$row = ['id' => 1, 'title' => 'Hello', 'updated_at' => '2026-01-15 10:30:00'];
$filtered = $filter->applyToRow($row);
// ['id' => 1, 'title' => 'Hello']

行キー(識別子)は、フィルター適用前の行から計算されます。そのため、識別列は列フィルターの影響を受けません。フィンガープリントと差分比較に使うデータのみがフィルターされます。

RowFilter

述語クロージャを使って個々の行をフィルタリングします。クロージャはテーブル名と行全体のデータを受け取り、行を含める場合はtrue、除外する場合はfalseを返します。

PHP
use Merql\Filter\RowFilter;

// Exclude draft posts.
$filter = RowFilter::create(function (string $table, array $row): bool {
    if ($table === 'posts' && ($row['status'] ?? '') === 'draft') {
        return false;
    }
    return true;
});

// Exclude rows with NULL email.
$filter = RowFilter::create(function (string $table, array $row): bool {
    if ($table === 'users') {
        return $row['email'] !== null;
    }
    return true;
});

仕組み

取得中、すべての行に対してshouldInclude()メソッドが呼び出されます。

PHP
$include = $filter->shouldInclude('posts', ['id' => 1, 'status' => 'draft']);
// false

除外された行はフィンガープリントが計算されず、スナップショットにも保存されず、差分比較やマージにも表示されません。

フィルターの組み合わせ

capture()に複数のフィルターを渡せます。各フィルタータイプは最大1つまで使用されます。

PHP
$snapshot = $snapshotter->capture('baseline', filters: [
    TableFilter::exclude(['cache_*']),
    ColumnFilter::ignore(['updated_at']),
    RowFilter::create(fn($table, $row) => ($row['active'] ?? '1') === '1'),
]);

処理順序:

  1. TableFilterが最初に実行され、取得するテーブルを決定します。
  2. 各テーブルについて、データベースから行を読み込みます。
  3. RowFilterが各行に適用され、一致しない行を除外します。
  4. フィルター適用前の行(識別列を保持)から行キーを計算します。
  5. ColumnFilterが行データから無視する列を取り除きます。
  6. フィルター後の行データからフィンガープリントを計算します。

この順序により、列フィルターで後から削除される場合でも、キーの計算に識別列を常に利用できます。

フィルターと整合性

マージする3つのスナップショット(base、ours、theirs)すべてに同じフィルターを使ってください。異なるフィルターを使うと、実際にはフィルターの違いだけなのに、行や列が追加または削除されたように見えることがあります。

PHP
// Use the same filter set for all snapshots.
$filters = [
    TableFilter::exclude(['sessions']),
    ColumnFilter::ignore(['updated_at']),
];

$base   = $snapshotter->capture('base', filters: $filters);
$ours   = $snapshotter->capture('ours', filters: $filters);
$theirs = $snapshotter->capture('theirs', filters: $filters);