
# Duomenų bazių tvarkyklės

merql atskiria prisijungimo transportą nuo duomenų bazės dialekto. `DatabaseConnection` adapteris vykdo SQL per PDO arba mysqli, o `Driver` tvarko konkrečiam duomenų bazės varikliui skirtus metaduomenis SQL ir identifikatorių kabučių žymėjimą. Integruotos tvarkyklės pateikiamos MySQL ir SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Sąsaja „Driver“

Kiekviena tvarkyklė įgyvendina penkis metodus:

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

| Metodas | Paskirtis |
|---|---|
| `quoteIdentifier` | Cituoti lentelės arba stulpelio pavadinimą, kad jį būtų galima naudoti SQL. |
| `listTables` | Grąžinti visas naudotojo lenteles dabartinėje duomenų bazėje. |
| `readSchema` | Nuskaityti lentelės stulpelių pavadinimus, tipus, pirminį raktą ir unikaliuosius raktus. |
| `readForeignKeys` | Grąžinti antrinės lentelės ir pirminės lentelės priklausomybių žemėlapį. |
| `selectAll` | Sudaryti lentelės užklausą `SELECT *`. |

## MysqlDriver

Metaduomenims naudoja `INFORMATION_SCHEMA` užklausas, o identifikatorius apgaubia atvirkštiniais apostrofais.

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

Lentelių sąrašo užklausos vykdomos `INFORMATION_SCHEMA.TABLES`, filtruojant pagal dabartinę duomenų bazę ir tipą `BASE TABLE`. Skaitant schemą, stulpeliams užklausiama `INFORMATION_SCHEMA.COLUMNS`, o pirminiams ir unikaliesiems raktams – `INFORMATION_SCHEMA.KEY_COLUMN_USAGE`.

## SqliteDriver

Metaduomenims naudoja `PRAGMA` užklausas, o identifikatorius apgaubia dvigubomis kabutėmis.

```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` automatiškai aptinka tinkamą tvarkyklę pagal `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
```

Jei prisijungimo tvarkyklės tapatybė neatpažįstama, išmetamas `RuntimeException` su pranešimu `Unsupported database driver: <name>`. merql neturi PostgreSQL tvarkyklės.

### Pasirinktinių tvarkyklių registravimas

Jei naudojate kitas duomenų bazes nei MySQL ir SQLite, parašykite klasę, kuri įgyvendina `Driver`, ir ją užregistruokite. Toliau pateiktas `PostgresDriver` žymi jūsų klasę:

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

Tvarkyklės klasė turi įgyvendinti sąsają `Driver`. Pirmasis `register()` argumentas yra prisijungimo tvarkyklės tapatybė.

### Atkūrimas

Testuodami atkurkite gamyklos numatytąją būseną:

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

## Prisijungimo pagalbinė priemonė

Klasė `Connection` kuria adapterius su tinkamais numatytaisiais nustatymais. PDO adapteriai klaidų atveju išmeta išimtis, naudoja asociatyvų gavimo režimą, tikrus paruoštus sakinius ir grąžina tekstines reikšmes. mysqli adapteris nustato `utf8mb4`, naudoja mysqli išimčių režimą ir paruoštus sakinius, o gautas reikšmes normalizuoja į tą patį eilutės arba null formatą.

```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()` priima bet kurį DSN, kurį gali atidaryti PDO, tačiau merql gali kurti momentines kopijas ir pritaikyti pakeitimus tik per užregistruotą tvarkyklę. Prisijungimas `pgsql:` atidaromas (jei įdiegta `pdo_pgsql`), bet konstruktoriai `Merql::init()`, `Snapshotter`, `Applier` ir `GuardedApplier` iškviečia `DriverFactory::create()`, kuris išmeta `RuntimeException: Unsupported database driver: pgsql`, nebent [užregistravote tvarkyklę](#registering-custom-drivers) šiai duomenų bazei arba ją perdavėte.

`Connection::sqlite()` taip pat automatiškai įjungia `PRAGMA foreign_keys = ON`, kurio SQLite reikia svetimųjų raktų užtikrinimui.

## Kur naudojamos tvarkyklės

merql tvarkyklės naudojamos įvairiose vietose:

- **Momentinių kopijų kūrimo priemonė** naudoja `listTables`, `readSchema` ir `selectAll` duomenų bazės būsenai užfiksuoti.
- **Pritaikymo priemonė** naudoja `readForeignKeys` operacijų tvarkai nustatyti, o tvarkyklę perduoda `SqlGenerator`, kad būtų teisingai pažymėti identifikatoriai.
- **SQL generatorius** naudoja `quoteIdentifier` saugioms SQL užklausoms sudaryti.

Jei perduodate prisijungimą į `Snapshotter` arba `Applier` nenurodydami tvarkyklės, automatiškai iškviečiama `DriverFactory::create()`.
