
# Φίλτρα

Τα φίλτρα ελέγχουν ποια δεδομένα περιλαμβάνονται σε ένα στιγμιότυπο. Εξαιρέστε πίνακες προσωρινής αποθήκευσης, αγνοήστε ασταθείς στήλες χρονοσήμανσης ή παραλείψτε προσωρινές γραμμές. Τα φίλτρα εφαρμόζονται κατά τη λήψη του στιγμιότυπου και επηρεάζουν όλες τις επόμενες λειτουργίες (σύγκριση διαφορών, συγχώνευση, εφαρμογή).

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

Ελέγχει ποιοι πίνακες περιλαμβάνονται σε ένα στιγμιότυπο. Υποστηρίζει μοτίβα glob μέσω του `fnmatch()` του PHP.

### Εξαίρεση πινάκων

```php
use Merql\Filter\TableFilter;

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

Κάθε πίνακας που αντιστοιχεί σε μοτίβο εξαίρεσης παραλείπεται από το στιγμιότυπο. Ο χαρακτήρας μπαλαντέρ `*` αντιστοιχεί σε οποιαδήποτε ακολουθία χαρακτήρων.

### Συμπερίληψη πινάκων

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

Καταγράφονται μόνο οι πίνακες που αντιστοιχούν σε μοτίβο συμπερίληψης. Όλοι οι υπόλοιποι εξαιρούνται.

### Πώς λειτουργεί

Η μέθοδος `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']
```

Όταν υπάρχουν μοτίβα συμπερίληψης και εξαίρεσης (μέσω ξεχωριστών στιγμιοτύπων φίλτρων), η εξαίρεση αξιολογείται πρώτη. Για να διατηρηθεί, ένας πίνακας δεν πρέπει να αντιστοιχεί σε κανένα μοτίβο εξαίρεσης και πρέπει να αντιστοιχεί σε τουλάχιστον ένα μοτίβο συμπερίληψης.

## 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()`. Χρησιμοποιείται το πολύ ένα φίλτρο από κάθε τύπο:

```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. Το **αποτύπωμα** υπολογίζεται από τα φιλτραρισμένα δεδομένα της γραμμής.

Αυτή η σειρά διασφαλίζει ότι οι στήλες ταυτότητας είναι πάντα διαθέσιμες για τον υπολογισμό του κλειδιού, ακόμη κι αν αφαιρεθούν αργότερα από το φίλτρο στηλών.

## Φίλτρα και συνέπεια

Τα ίδια φίλτρα πρέπει να χρησιμοποιούνται και στα τρία στιγμιότυπα μιας συγχώνευσης (βάση, δικό μας, δικό τους). Αν χρησιμοποιηθούν διαφορετικά φίλτρα, μπορεί να φαίνεται ότι προστέθηκαν ή αφαιρέθηκαν γραμμές ή στήλες, ενώ στην πραγματικότητα φιλτραρίστηκαν διαφορετικά.

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