
# Databasedrivers

merql scheidt het transport van verbindingen van de databasespecifieke dialecten. Een adapter van `DatabaseConnection` voert SQL uit via PDO of mysqli, terwijl een `Driver` databasespecifieke metagegevens SQL verwerkt en identifiers voorziet van aanhalingstekens. Er zijn ingebouwde drivers voor MySQL en SQLite.

```php
use Merql\Driver\DriverFactory;

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

## De Driver-interface

Elke driver implementeert vijf methoden:

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

| Methode | Doel |
|---|---|
| `quoteIdentifier` | Voorzie een tabel- of kolomnaam van aanhalingstekens voor gebruik in SQL. |
| `listTables` | Geef alle gebruikerstabellen in de huidige database terug. |
| `readSchema` | Lees kolomnamen, typen, primaire sleutel en unieke sleutels voor een tabel uit. |
| `readForeignKeys` | Geef een koppeling terug van onderliggende tabel naar bovenliggende tabel. |
| `selectAll` | Bouw een `SELECT *`-query voor een tabel. |

## MysqlDriver

Gebruikt `INFORMATION_SCHEMA`-queries voor metagegevens en backticks voor identifiers.

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

De query voor tabellijsten raadpleegt `INFORMATION_SCHEMA.TABLES`, gefilterd op de huidige database en het type `BASE TABLE`. Het schema wordt uitgelezen met queries naar `INFORMATION_SCHEMA.COLUMNS` voor kolommen en naar `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` voor primaire en unieke sleutels.

## SqliteDriver

Gebruikt `PRAGMA`-queries voor metagegevens en dubbele aanhalingstekens voor identifiers.

```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` detecteert automatisch de juiste driver op basis van `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
```

Als de driveridentiteit van de verbinding niet wordt herkend, wordt een `RuntimeException` met het bericht `Unsupported database driver: <name>` opgegooid. merql bevat geen PostgreSQL-driver.

### Aangepaste drivers registreren

Schrijf voor andere databases dan MySQL en SQLite een klasse die `Driver` implementeert en registreer deze. `PostgresDriver` staat hieronder voor uw eigen klasse:

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

De driverklasse moet de interface `Driver` implementeren. Het eerste argument van `register()` is de driveridentiteit van de verbinding.

### Opnieuw instellen

Stel voor tests de factory terug op de standaardstatus:

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

## Verbindingshelper

De klasse `Connection` bouwt adapters met verstandige standaardinstellingen. PDO-adapters gebruiken uitzonderingen bij fouten, de associatieve fetchmodus, echte prepared statements en fetches als strings. De mysqli-adapter stelt `utf8mb4` in, gebruikt de uitzonderingsmodus van mysqli, prepared statements en normaliseert opgehaalde waarden naar dezelfde vorm: een string of 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()` accepteert elke DSN die PDO kan openen, maar merql kan alleen snapshots maken en toepassen via een geregistreerde driver. Een `pgsql:`-verbinding wordt geopend (als `pdo_pgsql` is geïnstalleerd), maar de constructors `Merql::init()`, `Snapshotter`, `Applier` en `GuardedApplier` roepen `DriverFactory::create()` aan. Die genereert `RuntimeException: Unsupported database driver: pgsql`, tenzij u hiervoor een driver hebt [geregistreerd](#registering-custom-drivers) of er zelf een meegeeft.

`Connection::sqlite()` schakelt ook automatisch `PRAGMA foreign_keys = ON` in, wat SQLite nodig heeft om foreign key-beperkingen af te dwingen.

## Waar drivers worden gebruikt

Drivers worden overal in merql gebruikt:

- **Snapshotter** gebruikt `listTables`, `readSchema` en `selectAll` om de databasestatus vast te leggen.
- **Applier** gebruikt `readForeignKeys` om de volgorde van bewerkingen te bepalen en geeft de driver door aan `SqlGenerator` om identifiers te citeren.
- **SqlGenerator** gebruikt `quoteIdentifier` om veilige SQL op te bouwen.

Als u een verbinding doorgeeft aan `Snapshotter` of `Applier` zonder een driver op te geven, wordt `DriverFactory::create()` automatisch aangeroepen.
