Generación de SQL
SqlGenerator convierte un MergeResult en instrucciones SQL parametrizadas. Todos los valores se enlazan como parámetros; nunca se interpolan en la cadena SQL.
use Merql\Apply\SqlGenerator;
$statements = SqlGenerator::generate($result);
foreach ($statements as $stmt) {
echo $stmt['sql'] . "\n";
// INSERT INTO `posts` (`id`, `title`, `status`) VALUES (?, ?, ?)
print_r($stmt['params']);
// [42, 'New Title', 'publish']
}
Use generateGuarded() cuando un plan de fusión revisado solo deba aplicarse si las filas en vivo aún coinciden con una instantánea esperada.
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;
$statements = SqlGenerator::generateGuarded(
$selectedResult,
SnapshotStore::load('theirs'),
);
Formato de las instrucciones
Cada instrucción es una matriz asociativa con dos claves:
[
'sql' => 'INSERT INTO `posts` (`id`, `title`) VALUES (?, ?)',
'params' => [42, 'New Title'],
]
Los identificadores (nombres de tablas y columnas) se entrecomillan según el estilo del controlador de base de datos. MySQL usa acentos graves; SQLite usa comillas dobles. Si no se proporciona ningún controlador, se usan acentos graves de forma predeterminada.
Orden de las operaciones
Las operaciones se agrupan por tipo y se ejecutan en este orden:
- Primero, INSERTs: las filas nuevas deben existir antes de que las actualizaciones puedan hacer referencia a ellas.
- Después, UPDATEs.
- Por último, DELETEs: hay que eliminar las referencias a las filas antes de borrarlas.
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.
Orden de las claves foráneas
Cuando se proporcionan dependencias de claves foráneas, las operaciones de cada grupo se ordenan topológicamente. Las tablas principales se procesan antes que las secundarias en las inserciones y actualizaciones. En las eliminaciones, las tablas secundarias se procesan antes que las principales.
$fkDependencies = [
'comments' => ['posts'], // comments references posts
'post_meta' => ['posts'], // post_meta references posts
];
$statements = SqlGenerator::generate($result, fkDependencies: $fkDependencies);
// INSERTs: posts first, then comments and post_meta
// DELETEs: comments and post_meta first, then posts
ForeignKeyResolver realiza una ordenación topológica del grafo de dependencias. Detecta las dependencias circulares y las interrumpe para evitar bucles infinitos.
Detección automática de claves foráneas
Applier lee automáticamente las relaciones de claves foráneas de la base de datos:
use Merql\Apply\Applier;
$applier = new Applier($connection);
$applied = $applier->apply($result);
// FK dependencies are read from the database via the driver.
Ejemplos de SQL generadas
INSERT
INSERT INTO `posts` (`id`, `title`, `content`, `status`) VALUES (?, ?, ?, ?)
-- params: [42, 'New Post', 'Body text', 'draft']
Se incluyen todas las columnas de los valores de la operación.
UPDATE
UPDATE `posts` SET `title` = ?, `status` = ? WHERE `id` = ?
-- params: ['New Title', 'publish', 42]
Las columnas de identidad (clave principal) se excluyen de la cláusula SET y se usan en la cláusula WHERE. Los valores de WHERE se obtienen al decodificar la clave de la fila.
DELETE
DELETE FROM `posts` WHERE `id` = ?
-- params: [42]
En la cláusula WHERE solo aparecen columnas de identidad.
UPDATE con protección
Las actualizaciones con protección incluyen tanto las cláusulas de identidad como las cláusulas de la fila en vivo esperada.
UPDATE `posts` SET `title` = ? WHERE `id` = ? AND `status` = ?
-- params: ['New Title', 42, 'draft']
Si la fila ya no tiene el status esperado, la instrucción no afecta ninguna fila y la aplicación con protección revierte la transacción.
INSERT con protección
Las inserciones con protección usan NOT EXISTS para evitar insertar una identidad que haya aparecido desde que se creó el plan.
INSERT INTO `posts` (`id`, `title`) SELECT ?, ? WHERE NOT EXISTS (
SELECT 1 FROM `posts` WHERE `id` = ?
)
-- params: [42, 'New Post', 42]
Gestión de NULL
Los valores NULL se pasan como PHP null en la matriz params. El adaptador de conexión gestiona el enlace:
$statements = SqlGenerator::generate($result);
// params might contain: [42, null, 'draft']
// The adapter binds null as SQL NULL
En la salida de una simulación, los valores NULL se muestran como la cadena literal NULL, sin comillas.
Detección de columnas de identidad
SqlGenerator determina qué columnas conforman la identidad de la fila consultando TableSnapshot::identityColumns de la instantánea base. Estas columnas se usan en las cláusulas WHERE de las instrucciones UPDATE y DELETE, y se excluyen de las cláusulas SET de las instrucciones UPDATE.
Si no hay una instantánea base disponible, se usa como alternativa la primera columna de la matriz values. Si la matriz values está vacía, se supone que es id.
Cómo pasar un controlador
Para controlar el entrecomillado de los identificadores, pase una instancia de Driver:
use Merql\Driver\SqliteDriver;
$statements = SqlGenerator::generate(
$result,
driver: new SqliteDriver(),
);
// Uses double-quote quoting: "posts", "title"