Treci la conținut

Filtre

Filtrele controlează ce date sunt incluse într-un instantaneu. Excludeți tabelele de cache, ignorați coloanele cu marcaje temporale volatile sau omiteți rândurile tranzitorii. Filtrele se aplică în timpul capturării instantaneului și afectează toate operațiunile ulterioare (diff, merge, apply).

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

Controlează ce tabele sunt incluse într-un instantaneu. Acceptă modele glob prin PHP fnmatch().

Excluderea tabelelor

PHP
use Merql\Filter\TableFilter;

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

Orice tabel care corespunde unui model de excludere este omis din instantaneu. Caracterul wildcard * corespunde oricărei secvențe de caractere.

Includerea tabelelor

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

Sunt capturate numai tabelele care corespund unui model de includere. Toate celelalte sunt excluse.

Cum funcționează

Metoda apply() a filtrului primește o listă de nume de tabele și returnează subsetul filtrat:

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']

Când sunt prezente atât modele de includere, cât și de excludere (prin instanțe de filtre separate), excluderea este evaluată prima. Pentru a fi păstrat, un tabel nu trebuie să corespundă niciunui model de excludere și trebuie să corespundă cel puțin unui model de includere.

ColumnFilter

Elimină anumite coloane din datele rândurilor în timpul capturării. Este util pentru coloanele volatile care se modifică la fiecare scriere și ar cauza diferențe false.

PHP
use Merql\Filter\ColumnFilter;

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

Cazuri de utilizare frecvente

  • Marcaje temporale updated_at / modified_at care se modifică la fiecare salvare.
  • Contoare revision care se incrementează automat.
  • session_token sau alte câmpuri tranzitorii.

Cum funcționează

Filtrul elimină coloanele numite din fiecare rând după calcularea cheii rândului:

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']

Cheia rândului (identitatea) este calculată din rândul nefiltrat. Asta înseamnă că filtrul de coloane nu afectează niciodată coloanele de identitate. Sunt filtrate doar datele folosite pentru calcularea amprentei și compararea diferențelor.

RowFilter

Filtrează rânduri individuale folosind o funcție predicate de tip closure. Closure-ul primește numele tabelului și datele complete ale rândului și returnează true pentru a include rândul sau false pentru a-l exclude.

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;
});

Cum funcționează

Metoda shouldInclude() este apelată pentru fiecare rând în timpul capturării:

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

Rândurile excluse nu primesc amprentă, nu sunt stocate în instantaneu și nu apar în diferențe sau îmbinări.

Combinarea filtrelor

Transmiteți mai multe filtre către capture(). Se folosește cel mult un filtru din fiecare tip:

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

Ordinea procesării:

  1. TableFilter rulează prima și stabilește ce tabele să fie capturate.
  2. Pentru fiecare tabel, rândurile sunt citite din baza de date.
  3. RowFilter rulează pentru fiecare rând și exclude rândurile care nu corespund.
  4. Cheia rândului este calculată din rândul nefiltrat (cu coloanele de identitate intacte).
  5. ColumnFilter elimină coloanele ignorate din datele rândului.
  6. Amprenta este calculată din datele filtrate ale rândului.

Această ordine asigură că coloanele de identitate sunt întotdeauna disponibile pentru calcularea cheii, chiar dacă filtrul de coloane le elimină ulterior.

Filtre și consecvență

Folosiți aceleași filtre pentru toate cele trei instantanee dintr-o îmbinare (base, ours, theirs). Dacă se folosesc filtre diferite, poate părea că au fost adăugate sau eliminate rânduri ori coloane, deși acestea au fost doar filtrate în mod diferit.

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);