
# Datubāzu draiveri

merql nodala savienojuma transportu no datubāzes dialekta. `DatabaseConnection` adapteris izpilda SQL, izmantojot PDO vai mysqli, savukārt `Driver` apstrādā konkrētajam datubāzes dzinējam paredzētos metadatus SQL un identifikatoru citēšanu. Iebūvētie draiveri ir pieejami MySQL un SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Draivera saskarne

Katrs draiveris īsteno piecas metodes:

```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 | Mērķis |
|---|---|
| `quoteIdentifier` | Citēt tabulas vai kolonnas nosaukumu izmantošanai SQL. |
| `listTables` | Atgriezt visas lietotāja tabulas pašreizējā datubāzē. |
| `readSchema` | Nolasīt tabulas kolonnu nosaukumus, tipus, primāro atslēgu un unikālās atslēgas. |
| `readForeignKeys` | Atgriezt atkarību karti, kurā norādīta pakārtotā tabula un tās vecāktabula. |
| `selectAll` | Izveidot tabulas `SELECT *` vaicājumu. |

## MysqlDriver

Metadatiem izmanto `INFORMATION_SCHEMA` vaicājumus, bet identifikatorus citē ar atpakaļpēdiņām.

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

Tabulu uzskaites vaicājumi `INFORMATION_SCHEMA.TABLES`, filtrēti pēc pašreizējās datubāzes un `BASE TABLE` tipa. Shēmas nolasīšanas vaicājumi izmanto `INFORMATION_SCHEMA.COLUMNS` kolonnām un `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` primārajām un unikālajām atslēgām.

## SqliteDriver

Metadatiem izmanto `PRAGMA` vaicājumus, bet identifikatorus citē ar dubultpēdiņām.

```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` automātiski nosaka pareizo draiveri pēc `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
```

Ja savienojuma draivera identifikators nav atpazīts, tiek izmests `RuntimeException` ar ziņojumu `Unsupported database driver: <name>`. merql nav iekļauts PostgreSQL draiveris.

### Pielāgotu draiveru reģistrēšana

Datubāzēm ārpus MySQL un SQLite izveidojiet klasi, kas īsteno `Driver`, un reģistrējiet to. Tālāk `PostgresDriver` apzīmē jūsu klasi:

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

Draivera klasei jāīsteno saskarne `Driver`. Pirmais arguments funkcijai `register()` ir savienojuma draivera identifikators.

### Atiestatīšana

Testēšanai atiestatiet rūpnīcu tās noklusējuma stāvoklī:

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

## Savienojuma palīgklase

Klase `Connection` izveido adapterus ar saprātīgiem noklusējuma iestatījumiem. PDO adapteri kļūdu gadījumā izmanto izņēmumus, asociatīvo izgūšanas režīmu, īstus sagatavotus priekšrakstus un izgūtās vērtības pārveido par virknēm. mysqli adapteris iestata `utf8mb4`, izmanto mysqli izņēmumu režīmu un sagatavotus priekšrakstus, kā arī normalizē izgūtās vērtības tā, lai tās būtu virknes vai 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()` pieņem jebkuru DSN, ko var atvērt PDO, taču merql var izveidot momentuzņēmumu un lietot izmaiņas tikai ar reģistrētu draiveri. Savienojums `pgsql:` tiek atvērts (ja ir instalēts `pdo_pgsql`), taču `Merql::init()` un konstruktoros `Snapshotter`, `Applier` un `GuardedApplier` tiek izsaukts `DriverFactory::create()`, kas izmet `RuntimeException: Unsupported database driver: pgsql`, ja vien tam [nav reģistrēts draiveris](#registering-custom-drivers) vai arī tāds nav padots.

`Connection::sqlite()` arī automātiski iespējo `PRAGMA foreign_keys = ON`, kas SQLite ir nepieciešams ārējo atslēgu pārbaudei.

## Kur tiek izmantoti draiveri

merql draiverus izmanto visur:

- **Snapshotter** izmanto `listTables`, `readSchema` un `selectAll`, lai iegūtu datubāzes stāvokli.
- **Applier** izmanto `readForeignKeys`, lai noteiktu darbību secību, un nodod draiveri funkcijai `SqlGenerator` identifikatoru citēšanai.
- **SqlGenerator** izmanto `quoteIdentifier`, lai izveidotu drošus SQL.

Ja nododat savienojumu funkcijai `Snapshotter` vai `Applier`, nenorādot draiveri, automātiski tiek izsaukts `DriverFactory::create()`.
