Pular para o conteúdo

Drivers de banco de dados

merql separa o transporte da conexão do dialeto do banco de dados. Um adaptador DatabaseConnection executa SQL via PDO ou mysqli, enquanto um Driver lida com metadados SQL específicos do mecanismo de banco de dados e com a citação de identificadores. Há drivers integrados para MySQL e SQLite.

PHP
use Merql\Driver\DriverFactory;

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

A interface Driver

Cada driver implementa cinco métodos:

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;
}
Método Finalidade
quoteIdentifier Coloca entre aspas o nome de uma tabela ou coluna para uso em SQL.
listTables Retorna todas as tabelas de usuário no banco de dados atual.
readSchema Lê os nomes e tipos das colunas, a chave primária e as chaves exclusivas de uma tabela.
readForeignKeys Retorna um mapa das dependências entre tabelas filhas e tabelas pai.
selectAll Cria uma consulta SELECT * para uma tabela.

MysqlDriver

Usa consultas INFORMATION_SCHEMA para os metadados e aspas invertidas para delimitar identificadores.

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

As consultas de listagem de tabelas usam INFORMATION_SCHEMA.TABLES filtrado pelo banco de dados atual e pelo tipo BASE TABLE. As consultas de leitura do esquema usam INFORMATION_SCHEMA.COLUMNS para as colunas e INFORMATION_SCHEMA.KEY_COLUMN_USAGE para as chaves primárias e exclusivas.

SqliteDriver

Usa consultas PRAGMA para os metadados e aspas duplas para delimitar identificadores.

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 detecta automaticamente o driver correto a partir de 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

Se a identidade do driver da conexão não for reconhecida, será lançado um RuntimeException com a mensagem Unsupported database driver: <name>. merql não inclui um driver PostgreSQL.

Registrando drivers personalizados

Para bancos de dados além de MySQL e SQLite, escreva uma classe que implemente Driver e registre-a. PostgresDriver abaixo representa sua própria classe:

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.

A classe do driver deve implementar a interface Driver. O primeiro argumento de register() é a identidade do driver da conexão.

Redefinição

Para testar, redefina a fábrica para seu estado padrão:

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

Auxiliar de conexão

A classe Connection cria adaptadores com padrões sensatos. Os adaptadores PDO usam exceções em caso de erro, modo de busca associativo, prepared statements reais e valores buscados convertidos em strings. O adaptador mysqli define utf8mb4, usa o modo de exceção do mysqli, prepared statements e normaliza os valores buscados para o mesmo formato de string ou 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() aceita qualquer DSN que o PDO possa abrir, mas merql só consegue criar snapshots e aplicar alterações por meio de um driver registrado. Uma conexão pgsql: é aberta (quando pdo_pgsql estiver instalado), mas os construtores Merql::init(), Snapshotter, Applier e GuardedApplier chamam DriverFactory::create(), que lança RuntimeException: Unsupported database driver: pgsql, a menos que você tenha registrado um driver para ela ou informe um.

Connection::sqlite() também ativa PRAGMA foreign_keys = ON automaticamente, requisito de SQLite para aplicar restrições de chaves estrangeiras.

Onde os drivers são usados

Os drivers são usados em todo o merql:

  • Snapshotter usa listTables, readSchema e selectAll para capturar o estado do banco de dados.
  • Applier usa readForeignKeys para determinar a ordem das operações e passa o driver para SqlGenerator para citar identificadores.
  • SqlGenerator usa quoteIdentifier para criar SQL seguros.

Se você passar uma conexão para Snapshotter ou Applier sem especificar um driver, DriverFactory::create() será chamado automaticamente.