
# Filtri

Filtri določajo, kateri podatki so vključeni v posnetek. Izločite predpomnilniške tabele, prezrite spremenljive časovne žige ali preskočite začasne vrstice. Filtri se uporabijo med zajemom posnetka in vplivajo na vse nadaljnje operacije (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

Določa, katere tabele so vključene v posnetek. Podpira vzorce glob prek PHP in njegovega `fnmatch()`.

### Izločanje tabel

```php
use Merql\Filter\TableFilter;

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

Vsaka tabela, ki ustreza vzorcu za izločanje, je izpuščena iz posnetka. Nadomestni znak `*` ustreza kateremu koli zaporedju znakov.

### Vključevanje tabel

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

Zajete so samo tabele, ki ustrezajo vzorcu za vključitev. Vse druge so izločene.

### Kako deluje

Metoda `apply()` filtra sprejme seznam imen tabel in vrne filtrirano podmnožico:

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

Če sta prisotna vzorca za vključitev in izločanje (prek ločenih primerkov filtrov), se najprej ovrednoti izločanje. Tabela se ohrani, če ne ustreza nobenemu vzorcu za izločanje in ustreza vsaj enemu vzorcu za vključitev.

## ColumnFilter

Med zajemom iz podatkov vrstic odstrani določene stolpce. Uporabno za spremenljive stolpce, ki se ob vsakem zapisu spremenijo in bi povzročili lažne razlike.

```php
use Merql\Filter\ColumnFilter;

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

### Pogosti primeri uporabe

- `updated_at` / `modified_at` časovni žigi, ki se spremenijo ob vsakem shranjevanju.
- `revision` števci, ki se samodejno povečujejo.
- `session_token` ali druga začasna polja.

### Kako deluje

Filter po izračunu ključa vrstice iz vsake vrstice odstrani poimenovane stolpce:

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

Ključ vrstice (identiteta) se izračuna iz nefiltrirane vrstice. To pomeni, da filter stolpcev nikoli ne vpliva na stolpce identitete. Filtrirajo se samo podatki, uporabljeni za izračun prstnega odtisa in razlik.

## RowFilter

Posamezne vrstice filtrira s predikatno zaprtostjo. Zaprtost prejme ime tabele in celotne podatke vrstice ter vrne `true` za vključitev vrstice ali `false` za njeno izločitev.

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

### Kako deluje

Metoda `shouldInclude()` se med zajemom pokliče za vsako vrstico:

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

Izločene vrstice se ne uporabijo za izračun prstnega odtisa, niso shranjene v posnetku in niso prikazane v razlikah ali združitvah.

## Združevanje filtrov

Filtru `capture()` podajte več filtrov. Uporabi se največ en filter vsake vrste:

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

Vrstni red obdelave:

1. **TableFilter** se izvede najprej in določi, katere tabele bodo zajete.
2. Za vsako tabelo se iz podatkovne zbirke preberejo vrstice.
3. **RowFilter** se izvede za vsako vrstico in izloči tiste, ki ne ustrezajo.
4. Iz nefiltrirane vrstice se izračuna **ključ vrstice** (stolpci identitete ostanejo nedotaknjeni).
5. **ColumnFilter** iz podatkov vrstice odstrani prezrte stolpce.
6. Iz filtriranih podatkov vrstice se izračuna **prstni odtis**.

Ta vrstni red zagotavlja, da so stolpci identitete vedno na voljo za izračun ključa, tudi če jih filter stolpcev pozneje odstrani.

## Filtri in doslednost

Za vse tri posnetke v združitvi (base, ours, theirs) uporabite iste filtre. Če uporabite različne filtre, so lahko vrstice ali stolpci videti dodani ali odstranjeni, čeprav so bili v resnici filtrirani na različne načine.

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