
# Drivere de baze de date

merql separă transportul conexiunii de dialectul bazei de date. Un adaptor `DatabaseConnection` execută SQL prin PDO sau mysqli, în timp ce un `Driver` gestionează metadatele specifice motorului bazei de date SQL și citarea identificatorilor. Driverele incluse sunt disponibile pentru MySQL și SQLite.

```php
use Merql\Driver\DriverFactory;

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

## Interfața Driver

Fiecare driver implementează cinci metode:

```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ă | Scop |
|---|---|
| `quoteIdentifier` | Citează un nume de tabel sau de coloană pentru a fi folosit în SQL. |
| `listTables` | Returnează toate tabelele utilizatorului din baza de date curentă. |
| `readSchema` | Citește numele și tipurile coloanelor, cheia primară și cheile unice ale unui tabel. |
| `readForeignKeys` | Returnează o mapare a dependențelor de la tabelul copil la tabelul părinte. |
| `selectAll` | Construiește o interogare `SELECT *` pentru un tabel. |

## MysqlDriver

Folosește interogări `INFORMATION_SCHEMA` pentru metadate și citarea cu backtick-uri pentru identificatori.

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

Interogările pentru listarea tabelelor folosesc `INFORMATION_SCHEMA.TABLES`, filtrat după baza de date curentă și tipul `BASE TABLE`. Citirea schemei interoghează `INFORMATION_SCHEMA.COLUMNS` pentru coloane și `INFORMATION_SCHEMA.KEY_COLUMN_USAGE` pentru cheile primare și unice.

## SqliteDriver

Folosește interogări `PRAGMA` pentru metadate și citarea cu ghilimele duble pentru identificatori.

```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` detectează automat driverul corect din `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
```

Dacă identitatea driverului conexiunii nu este recunoscută, se aruncă un `RuntimeException` cu mesajul `Unsupported database driver: <name>`. merql nu include niciun driver PostgreSQL.

### Înregistrarea driverelor personalizate

Pentru alte baze de date decât MySQL și SQLite, scrieți o clasă care implementează `Driver` și înregistrați-o. `PostgresDriver` de mai jos reprezintă propria clasă:

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

Clasa driverului trebuie să implementeze interfața `Driver`. Primul argument al funcției `register()` este identitatea driverului conexiunii.

### Resetare

Pentru testare, resetați fabrica la starea implicită:

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

## Ajutor pentru conexiuni

Clasa `Connection` construiește adaptoare cu valori implicite adecvate. Adaptoarele PDO folosesc excepții la erori, modul de preluare asociativă, instrucțiuni pregătite reale și valori preluate convertite în șiruri. Adaptorul mysqli setează `utf8mb4`, folosește modul de excepții mysqli și instrucțiuni pregătite și normalizează valorile preluate la același format șir sau 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()` acceptă orice DSN pe care PDO îl poate deschide, dar merql poate crea instantanee și aplica modificări doar printr-un driver înregistrat. O conexiune `pgsql:` se deschide (dacă `pdo_pgsql` este instalat), dar constructorii `Merql::init()` și `Snapshotter`, `Applier` și `GuardedApplier` apelează `DriverFactory::create()`, care aruncă `RuntimeException: Unsupported database driver: pgsql` dacă nu ați [înregistrat un driver](#registering-custom-drivers) pentru aceasta sau nu ați transmis unul.

`Connection::sqlite()` activează automat și `PRAGMA foreign_keys = ON`, de care SQLite are nevoie pentru aplicarea cheilor străine.

## Unde sunt folosite driverele

Driverele sunt folosite în întregul merql:

- **Snapshotter** folosește `listTables`, `readSchema` și `selectAll` pentru a captura starea bazei de date.
- **Applier** folosește `readForeignKeys` pentru a stabili ordinea operațiilor și transmite driverul către `SqlGenerator` pentru citarea identificatorilor.
- **SqlGenerator** folosește `quoteIdentifier` pentru a construi interogări SQL sigure.

Dacă transmiteți o conexiune către `Snapshotter` sau `Applier` fără a specifica un driver, `DriverFactory::create()` este apelată automat.
