
# Databasedrivere

merql adskiller forbindelsestransport fra databasedialekt. En
`DatabaseConnection`-adapter udfører SQL via PDO eller mysqli, mens en `Driver`
håndterer databasespecifikke metadata-SQL og citering af identifikatorer. Indbyggede
drivere findes til MySQL og SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Grænsefladen Driver

Hver driver implementerer fem metoder:

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

| Metode | Formål |
|---|---|
| `quoteIdentifier` | Citer et tabel- eller kolonnenavn til brug i SQL. |
| `listTables` | Returner alle brugertabeller i den aktuelle database. |
| `readSchema` | Læs kolonnenavne, typer, primærnøgle og unikke nøgler for en tabel. |
| `readForeignKeys` | Returner et kort over afhængigheder mellem underordnede og overordnede tabeller. |
| `selectAll` | Byg en `SELECT *`-forespørgsel til en tabel. |

## MysqlDriver

Bruger `INFORMATION_SCHEMA`-forespørgsler til metadata og backtick-citering af identifikatorer.

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

Forespørgsler til tabeloversigten bruger `INFORMATION_SCHEMA.TABLES` filtreret efter den aktuelle database og typen `BASE TABLE`. Skemalæsningsforespørgsler bruger `INFORMATION_SCHEMA.COLUMNS` til kolonner og `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` til primærnøgler og unikke nøgler.

## SqliteDriver

Bruger `PRAGMA`-forespørgsler til metadata og citering af identifikatorer med dobbelte anførselstegn.

```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` registrerer automatisk den korrekte driver ud fra `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
```

Hvis forbindelsens driveridentitet ikke genkendes, kastes en `RuntimeException` med meddelelsen `Unsupported database driver: <name>`. merql indeholder ingen PostgreSQL-driver.

### Registrering af tilpassede drivere

Til databaser ud over MySQL og SQLite skal du skrive en klasse, der implementerer `Driver`, og registrere den. `PostgresDriver` nedenfor står for din egen 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.
```

Driverklassen skal implementere grænsefladen `Driver`. Det første argument til `register()` er forbindelsens driveridentitet.

### Nulstilling

Til test skal factoryen nulstilles til standardtilstanden:

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

## Forbindelseshjælper

Klassen `Connection` opretter adaptere med fornuftige standardindstillinger. PDO-adaptere bruger
undtagelser ved fejl, associativ hentningstilstand, reelle forberedte sætninger og
hentede værdier som strenge. mysqli-adapteren indstiller `utf8mb4`, bruger mysqli-undtagelsestilstand, forberedte sætninger og normaliserer hentede værdier til samme format med strenge eller 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()` accepterer enhver DSN, som PDO kan åbne, men merql kan kun tage snapshots og anvende ændringer via en registreret driver. En `pgsql:`-forbindelse åbnes (når `pdo_pgsql` er installeret), men konstruktørerne `Merql::init()`, `Snapshotter`, `Applier` og `GuardedApplier` kalder `DriverFactory::create()`, som kaster `RuntimeException: Unsupported database driver: pgsql`, medmindre du har [registreret en driver](#registering-custom-drivers) til den eller angiver en.

`Connection::sqlite()` aktiverer også automatisk `PRAGMA foreign_keys = ON`, som SQLite kræver for at håndhæve fremmednøgler.

## Hvor drivere bruges

Drivere bruges overalt i merql:

- **Snapshotter** bruger `listTables`, `readSchema` og `selectAll` til at registrere databasens tilstand.
- **Udfører** bruger `readForeignKeys` til at bestemme rækkefølgen af operationer og sender driveren til `SqlGenerator` for citering af identifikatorer.
- **SqlGenerator** bruger `quoteIdentifier` til at bygge sikre SQL.

Hvis du sender en forbindelse til `Snapshotter` eller `Applier` uden at angive en driver, kaldes `DriverFactory::create()` automatisk.
