
# Tietokanta-ajurit

merql erottaa yhteyden siirtotavan tietokantadialektista. `DatabaseConnection`-sovitin suorittaa SQL PDO:n tai mysqli:n kautta, kun taas `Driver` käsittelee tietokantamoottorikohtaisia metatietoja SQL ja tunnisteiden lainausmerkkejä. Sisäänrakennetut ajurit ovat saatavilla kohteille MySQL ja SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Driver-rajapinta

Jokainen ajuri toteuttaa viisi metodia:

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

| Metodi | Tarkoitus |
|---|---|
| `quoteIdentifier` | Lainausmerkitsee taulukon tai sarakkeen nimen käytettäväksi kohteessa SQL. |
| `listTables` | Palauttaa kaikki nykyisen tietokannan käyttäjätaulukot. |
| `readSchema` | Lukee taulukon sarakkeiden nimet ja tyypit sekä ensisijaisen ja uniikit avaimet. |
| `readForeignKeys` | Palauttaa mäppäyksen alitaulukoista ylätason taulukoihin. |
| `selectAll` | Muodostaa taulukolle kyselyn `SELECT *`. |

## MysqlDriver

Käyttää metatietoihin kyselyitä `INFORMATION_SCHEMA` ja tunnisteiden lainausmerkkeinä takamerkkejä.

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

Taulukkoluettelo hakee tietoja kohteesta `INFORMATION_SCHEMA.TABLES`, suodatettuna nykyisen tietokannan ja tyypin `BASE TABLE` mukaan. Skeemaa luettaessa sarakkeet haetaan kohteesta `INFORMATION_SCHEMA.COLUMNS` ja ensisijaiset sekä uniikit avaimet kohteesta `INFORMATION_SCHEMA.KEY_COLUMN_USAGE`.

## SqliteDriver

Käyttää metatietoihin kyselyitä `PRAGMA` ja tunnisteiden lainausmerkkeinä lainausmerkkejä.

```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` tunnistaa oikean ajurin automaattisesti arvosta `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
```

Jos yhteyden ajuritunnistetta ei tunnisteta, heitetään `RuntimeException` viestillä `Unsupported database driver: <name>`. merql ei sisällä ajuria kohteelle PostgreSQL.

### Mukautettujen ajurien rekisteröinti

Jos tietokanta on jokin muu kuin MySQL tai SQLite, kirjoita luokka, joka toteuttaa rajapinnan `Driver`, ja rekisteröi se. Alla oleva `PostgresDriver` tarkoittaa omaa luokkaasi:

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

Ajuriluokan on toteutettava rajapinta `Driver`. Toiminnon `register()` ensimmäinen argumentti on yhteyden ajuritunniste.

### Nollaus

Nollaa tehdas oletustilaansa testausta varten:

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

## Yhteysapuri

Luokka `Connection` luo sovittimet järkevillä oletusarvoilla. PDO-sovittimissa virheet aiheuttavat poikkeuksia, hakutilana on assosiatiivinen taulukko, käytössä ovat aidot valmistellut lauseet ja haetut arvot muunnetaan merkkijonoiksi. mysqli-sovitin asettaa arvon `utf8mb4`, käyttää mysqli-poikkeustilaa ja valmisteltuja lauseita sekä normalisoi haetut arvot samaan merkkijono- tai null-muotoon.

```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()` hyväksyy minkä tahansa DSN:n, jonka PDO voi avata, mutta merql voi ottaa tilannevedoksia ja soveltaa muutoksia vain rekisteröidyn ajurin kautta. `pgsql:`-yhteys avautuu (jos `pdo_pgsql` on asennettu), mutta toimintojen `Merql::init()` sekä `Snapshotter`-, `Applier`- ja `GuardedApplier`-konstruktoreiden kutsuma `DriverFactory::create()` aiheuttaa poikkeuksen `RuntimeException: Unsupported database driver: pgsql`, ellet ole [rekisteröinyt sille ajuria](#registering-custom-drivers) tai välittänyt sellaista parametrina.

`Connection::sqlite()` ottaa myös automaattisesti käyttöön toiminnon `PRAGMA foreign_keys = ON`, jota SQLite tarvitsee vierasavainten valvontaan.

## Missä ajureita käytetään

Ajureita käytetään merql:n eri osissa:

- **Snapshotter** käyttää toimintoja `listTables`, `readSchema` ja `selectAll` tietokannan tilan tallentamiseen.
- **Applier** käyttää toimintoa `readForeignKeys` toimintojen suoritusjärjestyksen määrittämiseen ja välittää ajurin toiminnolle `SqlGenerator` tunnisteiden lainausmerkitsemistä varten.
- **SqlGenerator** käyttää toimintoa `quoteIdentifier` turvallisten SQL-lauseiden muodostamiseen.

Jos välität yhteyden toiminnolle `Snapshotter` tai `Applier` määrittämättä ajuria, toiminto `DriverFactory::create()` kutsutaan automaattisesti.
