
# Filtreler

Filtreler, anlık görüntüye hangi verilerin dahil edileceğini belirler. Önbellek tablolarını hariç tutun, değişken zaman damgası sütunlarını yok sayın veya geçici satırları atlayın. Filtreler anlık görüntü yakalanırken uygulanır ve sonraki tüm işlemleri (diff, birleştirme, uygulama) etkiler.

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

Anlık görüntüye hangi tabloların dahil edileceğini belirler. PHP'in `fnmatch()` özelliğiyle glob kalıplarını destekler.

### Tabloları hariç tutma

```php
use Merql\Filter\TableFilter;

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

Hariç tutma kalıbıyla eşleşen her tablo anlık görüntüye alınmaz. `*` joker karakteri herhangi bir karakter dizisiyle eşleşir.

### Tabloları dahil etme

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

Yalnızca dahil etme kalıbıyla eşleşen tablolar yakalanır. Diğer tüm tablolar hariç tutulur.

### Nasıl çalışır

Filtrenin `apply()` yöntemi tablo adlarından oluşan bir liste alır ve filtrelenmiş alt kümeyi döndürür:

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

Ayrı filtre örnekleri aracılığıyla hem dahil etme hem hariç tutma kalıpları belirtildiğinde, önce hariç tutma değerlendirilir. Bir tablonun tutulması için hiçbir hariç tutma kalıbıyla eşleşmemesi ve en az bir dahil etme kalıbıyla eşleşmesi gerekir.

## ColumnFilter

Yakalama sırasında satır verilerinden belirli sütunları kaldırır. Her yazmada değişen ve yanlış diff sonuçlarına yol açabilecek değişken sütunlar için kullanışlıdır.

```php
use Merql\Filter\ColumnFilter;

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

### Yaygın kullanım durumları

- Her kaydetmede değişen `updated_at` / `modified_at` zaman damgaları.
- Otomatik artan `revision` sayaçları.
- `session_token` veya diğer geçici alanlar.

### Nasıl çalışır

Filtre, satır anahtarı hesaplandıktan sonra her satırdan adı belirtilen sütunları çıkarır:

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

Satır anahtarı (kimliği), filtre uygulanmamış satırdan hesaplanır. Bu nedenle kimlik sütunları sütun filtresinden hiçbir zaman etkilenmez. Yalnızca parmak izi ve diff hesaplamasında kullanılan veriler filtrelenir.

## RowFilter

Satırları bir koşul closure'ı ile tek tek filtreler. Closure, tablo adını ve satırın tüm verilerini alır; satırı dahil etmek için `true`, hariç tutmak için `false` döndürür.

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

### Nasıl çalışır

Yakalama sırasında her satır için `shouldInclude()` yöntemi çağrılır:

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

Hariç tutulan satırlara parmak izi hesaplanmaz, bu satırlar anlık görüntüde saklanmaz ve diff ya da birleştirmelerde görünmez.

## Filtreleri birleştirme

`capture()`'e birden fazla filtre geçirin. Her filtre türünden en fazla bir tane kullanılır:

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

İşlem sırası:

1. Önce **TableFilter** çalışır ve hangi tabloların yakalanacağını belirler.
2. Her tablo için veritabanından satırlar okunur.
3. **RowFilter** her satırda çalışarak eşleşmeyen satırları hariç tutar.
4. **row key**, filtre uygulanmamış satırdan hesaplanır (kimlik sütunları korunur).
5. **ColumnFilter**, satır verilerinden yok sayılan sütunları çıkarır.
6. Filtrelenmiş satır verilerinden **fingerprint** hesaplanır.

Bu sıra, sütun filtresi kimlik sütunlarını sonradan çıkarsa bile anahtar hesaplaması için bu sütunların her zaman kullanılabilir olmasını sağlar.

## Filtreler ve tutarlılık

Birleştirmedeki üç anlık görüntünün (base, ours, theirs) tümünde aynı filtreler kullanılmalıdır. Farklı filtreler kullanılırsa, aslında yalnızca farklı biçimde filtrelenmiş satır veya sütunlar eklenmiş ya da kaldırılmış gibi görünebilir.

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