
# Pilotes de base de données

merql sépare le transport de connexion du dialecte de base de données. Un adaptateur `DatabaseConnection` exécute SQL via PDO ou mysqli, tandis qu'un `Driver` gère les métadonnées propres au moteur de base de données SQL ainsi que la citation des identifiants. Des pilotes intégrés sont fournis pour MySQL et SQLite.

```php
use Merql\Driver\DriverFactory;

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

## L'interface Driver

Chaque pilote implémente cinq méthodes :

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

| Méthode | Fonction |
|---|---|
| `quoteIdentifier` | Mettre entre guillemets un nom de table ou de colonne pour l'utiliser dans SQL. |
| `listTables` | Renvoyer toutes les tables utilisateur de la base de données actuelle. |
| `readSchema` | Lire les noms et types des colonnes, la clé primaire et les clés uniques d'une table. |
| `readForeignKeys` | Renvoyer une correspondance entre les tables enfants et leurs tables parentes. |
| `selectAll` | Construire une requête `SELECT *` pour une table. |

## MysqlDriver

Utilise des requêtes `INFORMATION_SCHEMA` pour les métadonnées et des accents graves pour citer les identifiants.

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

La liste des tables interroge `INFORMATION_SCHEMA.TABLES`, filtré selon la base de données actuelle et le type `BASE TABLE`. La lecture du schéma interroge `INFORMATION_SCHEMA.COLUMNS` pour les colonnes et `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` pour les clés primaires et uniques.

## SqliteDriver

Utilise des requêtes `PRAGMA` pour les métadonnées et des guillemets doubles pour citer les identifiants.

```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` détecte automatiquement le pilote adéquat à partir de `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
```

Si l'identité du pilote de connexion n'est pas reconnue, un `RuntimeException` avec le message `Unsupported database driver: <name>` est levé. merql ne fournit aucun pilote PostgreSQL.

### Enregistrer des pilotes personnalisés

Pour les bases de données autres que MySQL et SQLite, écrivez une classe qui implémente `Driver`, puis enregistrez-la. `PostgresDriver` ci-dessous représente votre propre classe :

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

La classe du pilote doit implémenter l'interface `Driver`. Le premier argument de `register()` est l'identité du pilote de connexion.

### Réinitialiser

Pour les tests, réinitialisez la fabrique à son état par défaut :

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

## Assistant de connexion

La classe `Connection` construit des adaptateurs avec des valeurs par défaut adaptées. Les adaptateurs PDO utilisent les exceptions en cas d'erreur, le mode de récupération associatif, de vraies requêtes préparées et des résultats convertis en chaînes. L'adaptateur mysqli définit `utf8mb4`, utilise le mode d'exception mysqli et les requêtes préparées, puis normalise les valeurs récupérées au même format chaîne ou 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()` accepte tout DSN que PDO peut ouvrir, mais merql ne peut effectuer des instantanés et des applications qu'avec un pilote enregistré. Une connexion `pgsql:` s'ouvre (si `pdo_pgsql` est installé), mais les constructeurs `Merql::init()`, `Snapshotter`, `Applier` et `GuardedApplier` appellent `DriverFactory::create()`, qui lève `RuntimeException: Unsupported database driver: pgsql` à moins que vous n'ayez [enregistré un pilote](#registering-custom-drivers) pour cette connexion ou que vous en fournissiez un.

`Connection::sqlite()` active également automatiquement `PRAGMA foreign_keys = ON`, ce dont SQLite a besoin pour appliquer les clés étrangères.

## Où les pilotes sont utilisés

Les pilotes sont utilisés dans tout merql :

- **Snapshotter** utilise `listTables`, `readSchema` et `selectAll` pour capturer l'état de la base de données.
- **Applier** utilise `readForeignKeys` pour déterminer l'ordre des opérations et transmet le pilote à `SqlGenerator` pour citer les identifiants.
- **SqlGenerator** utilise `quoteIdentifier` pour construire des SQL sûrs.

Si vous transmettez une connexion à `Snapshotter` ou `Applier` sans spécifier de pilote, `DriverFactory::create()` est appelé automatiquement.
