
# Οδηγοί βάσεων δεδομένων

Το merql διαχωρίζει τη μεταφορά σύνδεσης από τη διάλεκτο βάσης δεδομένων. Ένας προσαρμογέας `DatabaseConnection` εκτελεί SQL μέσω PDO ή mysqli, ενώ ένας `Driver` διαχειρίζεται τα μεταδεδομένα SQL που αφορούν τη μηχανή βάσης δεδομένων και την παράθεση αναγνωριστικών. Παρέχονται ενσωματωμένοι οδηγοί για τα MySQL και SQLite.

```php
use Merql\Driver\DriverFactory;

$driver = DriverFactory::create($connection);
// Auto-detects MySQL or SQLite from the connection driver identity.
```

## Η διεπαφή Driver

Κάθε οδηγός υλοποιεί πέντε μεθόδους:

```php
use Merql\Driver\Driver;

interface Driver
{
    public function quoteIdentifier(string $name): string;
    public function listTables(DatabaseConnection $connection): array;
    public function readSchema(DatabaseConnection $connection, string $table): TableSchema;
    public function readForeignKeys(DatabaseConnection $connection): array;
    public function selectAll(string $table): string;
}
```

| Μέθοδος | Σκοπός |
|---|---|
| `quoteIdentifier` | Παραθέτει το όνομα ενός πίνακα ή μιας στήλης για χρήση σε SQL. |
| `listTables` | Επιστρέφει όλους τους πίνακες χρηστών στην τρέχουσα βάση δεδομένων. |
| `readSchema` | Διαβάζει ονόματα στηλών, τύπους, πρωτεύον κλειδί και μοναδικά κλειδιά για έναν πίνακα. |
| `readForeignKeys` | Επιστρέφει αντιστοίχιση από θυγατρικούς πίνακες σε γονικούς πίνακες. |
| `selectAll` | Δημιουργεί ένα ερώτημα `SELECT *` για έναν πίνακα. |

## MysqlDriver

Χρησιμοποιεί ερωτήματα `INFORMATION_SCHEMA` για μεταδεδομένα και εισαγωγικά ανάστροφης αποστρόφου για αναγνωριστικά.

```php
use Merql\Driver\MysqlDriver;

$driver = new MysqlDriver();

$driver->quoteIdentifier('posts');
// `posts`

$driver->quoteIdentifier('my`table');
// `my``table`

$tables = $driver->listTables($connection);
// ['comments', 'posts', 'users']

$schema = $driver->readSchema($connection, 'posts');
// TableSchema with columns, primaryKey, uniqueKeys

$fks = $driver->readForeignKeys($connection);
// ['comments' => ['posts', 'users']]
```

Τα ερωτήματα καταχώρισης πινάκων χρησιμοποιούν `INFORMATION_SCHEMA.TABLES`, φιλτραρισμένο με βάση την τρέχουσα βάση δεδομένων και τον τύπο `BASE TABLE`. Για την ανάγνωση σχήματος, χρησιμοποιούνται τα `INFORMATION_SCHEMA.COLUMNS` για τις στήλες και τα `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` για πρωτεύοντα και μοναδικά κλειδιά.

## SqliteDriver

Χρησιμοποιεί ερωτήματα `PRAGMA` για μεταδεδομένα και διπλά εισαγωγικά για αναγνωριστικά.

```php
use Merql\Driver\SqliteDriver;

$driver = new SqliteDriver();

$driver->quoteIdentifier('posts');
// "posts"

$driver->quoteIdentifier('my"table');
// "my""table"

$tables = $driver->listTables($connection);
// Queries sqlite_master, excludes sqlite_* internal tables.

$schema = $driver->readSchema($connection, 'posts');
// Uses PRAGMA table_info() and PRAGMA index_list().

$fks = $driver->readForeignKeys($connection);
// Uses PRAGMA foreign_key_list() for each table.
```

## DriverFactory

Το `DriverFactory` εντοπίζει αυτόματα τον σωστό οδηγό από το `DatabaseConnection::driverName()`.

```php
use Merql\Connection;
use Merql\Driver\DriverFactory;

$connection = Connection::mysql('127.0.0.1', 'mydb', 'root', '');
$driver = DriverFactory::create($connection);
// Returns MysqlDriver

$connection = Connection::sqlite(':memory:');
$driver = DriverFactory::create($connection);
// Returns SqliteDriver
```

Αν η ταυτότητα του οδηγού σύνδεσης δεν αναγνωρίζεται, προκαλείται ένα `RuntimeException` με το μήνυμα `Unsupported database driver: <name>`. Το merql δεν διαθέτει οδηγό PostgreSQL.

### Καταχώριση προσαρμοσμένων οδηγών

Για βάσεις δεδομένων πέρα από τα MySQL και SQLite, γράψτε μια κλάση που υλοποιεί το `Driver` και καταχωρίστε την. Το `PostgresDriver` παρακάτω αντιστοιχεί στη δική σας κλάση:

```php
use Merql\Driver\DriverFactory;

DriverFactory::register('pgsql', PostgresDriver::class);

$connection = Connection::fromDsn('pgsql:host=localhost;dbname=mydb', 'user', 'pass');
$driver = DriverFactory::create($connection);
// Returns your PostgresDriver instance.
```

Η κλάση οδηγού πρέπει να υλοποιεί τη διεπαφή `Driver`. Το πρώτο όρισμα του `register()` είναι η ταυτότητα του οδηγού σύνδεσης.

### Επαναφορά

Για δοκιμές, επαναφέρετε το εργοστάσιο στην προεπιλεγμένη κατάστασή του:

```php
DriverFactory::reset();
// Reverts to only MySQL and SQLite drivers.
```

## Βοηθητικό σύνδεσης

Η κλάση `Connection` δημιουργεί προσαρμογείς με εύλογες προεπιλεγμένες ρυθμίσεις. Οι προσαρμογείς PDO χρησιμοποιούν εξαιρέσεις σε περίπτωση σφάλματος, λειτουργία λήψης συσχετιστικού πίνακα, πραγματικές προετοιμασμένες εντολές και ληφθείσες τιμές ως συμβολοσειρές. Ο προσαρμογέας mysqli ορίζει το `utf8mb4`, χρησιμοποιεί τη λειτουργία εξαιρέσεων του mysqli και προετοιμασμένες εντολές, και κανονικοποιεί τις ληφθείσες τιμές στην ίδια μορφή συμβολοσειράς ή null.

```php
use Merql\Connection;

// MySQL.
$connection = Connection::mysql('127.0.0.1', 'my_database', 'root', 'password');
$connection = Connection::mysql('db.example.com', 'mydb', 'user', 'pass', port: 3307);

// MySQLi.
$connection = Connection::mysqli('127.0.0.1', 'my_database', 'root', 'password');

// SQLite.
$connection = Connection::sqlite(':memory:');
$connection = Connection::sqlite('/var/data/app.sqlite');

// Any MySQL or SQLite PDO DSN.
$connection = Connection::fromDsn('mysql:host=127.0.0.1;dbname=mydb;charset=utf8mb4', 'user', 'pass');
```

Το `fromDsn()` δέχεται οποιοδήποτε DSN μπορεί να ανοίξει το PDO, αλλά το merql μπορεί να δημιουργήσει στιγμιότυπα και να εφαρμόσει αλλαγές μόνο μέσω καταχωρισμένου οδηγού. Μια σύνδεση `pgsql:` ανοίγει (όταν είναι εγκατεστημένο το `pdo_pgsql`), αλλά οι κατασκευαστές `Merql::init()`, `Snapshotter`, `Applier` και `GuardedApplier` καλούν το `DriverFactory::create()`, το οποίο προκαλεί το `RuntimeException: Unsupported database driver: pgsql` εκτός αν έχετε [καταχωρίσει έναν οδηγό](#registering-custom-drivers) για αυτήν ή περάσετε έναν.

Το `Connection::sqlite()` ενεργοποιεί επίσης αυτόματα το `PRAGMA foreign_keys = ON`, που απαιτεί το SQLite για την επιβολή ξένων κλειδιών.

## Πού χρησιμοποιούνται οι οδηγοί

Οι οδηγοί χρησιμοποιούνται σε όλο το merql:

- **Snapshotter** χρησιμοποιεί τα `listTables`, `readSchema` και `selectAll` για να αποτυπώσει την κατάσταση της βάσης δεδομένων.
- **Applier** χρησιμοποιεί το `readForeignKeys` για να καθορίσει τη σειρά των λειτουργιών και περνά τον οδηγό στο `SqlGenerator` για την παράθεση αναγνωριστικών.
- **SqlGenerator** χρησιμοποιεί το `quoteIdentifier` για να δημιουργήσει ασφαλή SQL.

Αν περάσετε μια σύνδεση στο `Snapshotter` ή στο `Applier` χωρίς να ορίσετε οδηγό, καλείται αυτόματα το `DriverFactory::create()`.
