
# Databasdrivrutiner

merql separerar anslutningstransport från databasspråk. En `DatabaseConnection`-adapter kör SQL via PDO eller mysqli, medan en `Driver` hanterar databasmotorspecifika metadata-SQL och citering av identifierare. Inbyggda drivrutiner tillhandahålls för MySQL och SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Gränssnittet Driver

Varje drivrutin implementerar 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;
}
```

| Metod | Syfte |
|---|---|
| `quoteIdentifier` | Citera ett tabell- eller kolumnnamn för användning i SQL. |
| `listTables` | Returnera alla användartabeller i den aktuella databasen. |
| `readSchema` | Läsa kolumnnamn, typer, primärnyckel och unika nycklar för en tabell. |
| `readForeignKeys` | Returnera en mappning från underordnad tabell till överordnade tabellberoenden. |
| `selectAll` | Bygga en `SELECT *`-fråga för en tabell. |

## MysqlDriver

Använder `INFORMATION_SCHEMA`-frågor för metadata och omvända apostrofer för att citera identifierare.

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

Tabellistan hämtar `INFORMATION_SCHEMA.TABLES` filtrerat efter den aktuella databasen och typen `BASE TABLE`. Schemaläsningen hämtar `INFORMATION_SCHEMA.COLUMNS` för kolumner och `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` för primärnycklar och unika nycklar.

## SqliteDriver

Använder `PRAGMA`-frågor för metadata och dubbla citationstecken för att citera identifierare.

```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` identifierar automatiskt rätt drivrutin från `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
```

Om anslutningens drivrutinsidentitet inte känns igen kastas en `RuntimeException` med meddelandet `Unsupported database driver: <name>`. merql levereras inte med någon PostgreSQL-drivrutin.

### Registrera anpassade drivrutiner

För databaser utöver MySQL och SQLite skriver du en klass som implementerar `Driver` och registrerar den. `PostgresDriver` nedan står för din egen klass:

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

Drivrutinsklassen måste implementera gränssnittet `Driver`. Det första argumentet till `register()` är anslutningens drivrutinsidentitet.

### Återställ

För testning återställer du fabriken till standardläget:

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

## Anslutningshjälpare

Klassen `Connection` bygger adaptrar med lämpliga standardinställningar. PDO-adaptrar använder undantag vid fel, associativt hämtningsläge, riktiga förberedda satser och hämtning av värden som strängar. mysqli-adaptern ställer in `utf8mb4`, använder mysqli-undantagsläge och förberedda satser samt normaliserar hämtade värden till samma format med strängar 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()` godtar alla DSN:er som PDO kan öppna, men merql kan endast ta ögonblicksbilder och tillämpa ändringar via en registrerad drivrutin. En anslutning till `pgsql:` öppnas (om `pdo_pgsql` är installerat), men konstruktorerna `Merql::init()`, `Snapshotter`, `Applier` och `GuardedApplier` anropar `DriverFactory::create()`, som kastar `RuntimeException: Unsupported database driver: pgsql` om du inte har [registrerat en drivrutin](#registering-custom-drivers) för den eller skickar med en.

`Connection::sqlite()` aktiverar också automatiskt `PRAGMA foreign_keys = ON`, vilket SQLite kräver för att framtvinga främmande nycklar.

## Var drivrutiner används

Drivrutiner används i hela merql:

- **Snapshotter** använder `listTables`, `readSchema` och `selectAll` för att fånga databasens tillstånd.
- **Applier** använder `readForeignKeys` för att bestämma åtgärdernas ordning och skickar drivrutinen till `SqlGenerator` för citering av identifierare.
- **SqlGenerator** använder `quoteIdentifier` för att bygga säkra SQL.

Om du skickar en anslutning till `Snapshotter` eller `Applier` utan att ange en drivrutin anropas `DriverFactory::create()` automatiskt.
