
# Databázové ovládače

merql oddeľuje prenos pripojenia od dialektu databázy. Adaptér `DatabaseConnection` vykonáva SQL cez PDO alebo mysqli, zatiaľ čo `Driver` spracúva metadáta špecifické pre databázový stroj SQL a uzatváranie identifikátorov do úvodzoviek. Vstavané ovládače sú k dispozícii pre MySQL a SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Rozhranie Driver

Každý ovládač implementuje päť metód:

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

| Metóda | Účel |
|---|---|
| `quoteIdentifier` | Uzavrie názov tabuľky alebo stĺpca do úvodzoviek na použitie v SQL. |
| `listTables` | Vráti všetky používateľské tabuľky v aktuálnej databáze. |
| `readSchema` | Načíta názvy stĺpcov, typy, primárny kľúč a jedinečné kľúče tabuľky. |
| `readForeignKeys` | Vráti mapu závislostí podradených tabuliek od nadradených tabuliek. |
| `selectAll` | Vytvorí dotaz `SELECT *` pre tabuľku. |

## MysqlDriver

Na získanie metadát používa dotazy `INFORMATION_SCHEMA` a na uzatváranie identifikátorov do úvodzoviek používa spätné apostrofy.

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

Dotazy na zoznam tabuliek pracujú s `INFORMATION_SCHEMA.TABLES`, odfiltrovaným podľa aktuálnej databázy a typu `BASE TABLE`. Načítanie schémy používa `INFORMATION_SCHEMA.COLUMNS` pre stĺpce a `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` pre primárne a jedinečné kľúče.

## SqliteDriver

Na získanie metadát používa dotazy `PRAGMA` a na uzatváranie identifikátorov do úvodzoviek používa dvojité úvodzovky.

```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` automaticky určí správny ovládač podľa `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
```

Ak sa identita ovládača pripojenia nerozpozná, vyvolá sa `RuntimeException` so správou `Unsupported database driver: <name>`. merql neobsahuje ovládač PostgreSQL.

### Registrácia vlastných ovládačov

Pre databázy okrem MySQL a SQLite napíšte triedu implementujúcu `Driver` a zaregistrujte ju. `PostgresDriver` nižšie zastupuje vašu vlastnú triedu:

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

Trieda ovládača musí implementovať rozhranie `Driver`. Prvý argument funkcie `register()` je identita ovládača pripojenia.

### Obnovenie predvolených nastavení

Pri testovaní obnovte továrenské nastavenia na predvolené hodnoty:

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

## Pomocná trieda pripojenia

Trieda `Connection` vytvára adaptéry s rozumnými predvolenými nastaveniami. Adaptéry PDO pri chybe vyvolávajú výnimky, používajú asociatívny režim načítania, skutočné pripravené príkazy a prevádzajú načítané hodnoty na reťazce. Adaptér mysqli nastavuje `utf8mb4`, používa režim výnimiek mysqli a pripravené príkazy a normalizuje načítané hodnoty na rovnaký tvar reťazca alebo 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()` prijíma ľubovoľné DSN, ktoré dokáže otvoriť PDO, ale merql môže vytvárať snímky a aplikovať zmeny iba prostredníctvom zaregistrovaného ovládača. Pripojenie `pgsql:` sa otvorí (ak je nainštalovaný `pdo_pgsql`), ale konštruktory `Merql::init()`, `Snapshotter`, `Applier` a `GuardedApplier` volajú `DriverFactory::create()`, ktorá vyvolá `RuntimeException: Unsupported database driver: pgsql`, ak preň nezaregistrujete ovládač pomocou [zaregistrovania ovládača](#registering-custom-drivers) alebo ho sami nezadáte.

`Connection::sqlite()` automaticky zapína aj `PRAGMA foreign_keys = ON`, ktorý SQLite vyžaduje na vynucovanie cudzích kľúčov.

## Kde sa používajú ovládače

Ovládače sa používajú v celom merql:

- **Snapshotter** používa `listTables`, `readSchema` a `selectAll` na zachytenie stavu databázy.
- **Applier** používa `readForeignKeys` na určenie poradia operácií a odovzdáva ovládač komponentu `SqlGenerator` na uzatváranie identifikátorov do úvodzoviek.
- **SqlGenerator** používa `quoteIdentifier` na vytváranie bezpečného SQL.

Ak zadáte pripojenie pre `Snapshotter` alebo `Applier` bez uvedenia ovládača, automaticky sa zavolá `DriverFactory::create()`.
