Gå til indhold

SQL-generering

SqlGenerator konverterer en MergeResult til parameteriserede SQL-sætninger. Alle værdier bindes som parametre og indsættes aldrig direkte i SQL-strengen.

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

Brug generateGuarded(), når en gennemgået fletningsplan kun skal anvendes, hvis live-rækkerne stadig svarer til et forventet øjebliksbillede.

PHP
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;

$statements = SqlGenerator::generateGuarded(
    $selectedResult,
    SnapshotStore::load('theirs'),
);

Sætningsformat

Hver sætning er et associativt array med to nøgler:

PHP
[
    'sql'    => 'INSERT INTO `posts` (`id`, `title`) VALUES (?, ?)',
    'params' => [42, 'New Title'],
]

Identifikatorer (tabel- og kolonnenavne) citeres med databasens drivers citeringsstil. MySQL bruger backticks, SQLite bruger dobbelte anførselstegn. Hvis der ikke angives nogen driver, bruges backticks som standard.

Rækkefølge af handlinger

Handlinger grupperes efter type og udføres i denne rækkefølge:

  1. INSERTs først -- nye rækker skal eksistere, før opdateringer kan referere til dem.
  2. UPDATEs derefter.
  3. DELETEs til sidst -- referencer til rækker skal fjernes, før de slettes.
PHP
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.

Rækkefølge efter fremmednøgler

Når der angives afhængigheder mellem fremmednøgler, sorteres handlingerne i hver gruppe topologisk. Overordnede tabeller behandles før underordnede ved indsættelser og opdateringer. Underordnede tabeller behandles før overordnede ved sletninger.

PHP
$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 udfører en topologisk sortering af afhængighedsgrafen. Cirkulære afhængigheder registreres og brydes for at forhindre uendelige løkker.

Automatisk registrering af fremmednøgler

Applier henter automatisk relationer mellem fremmednøgler fra databasen:

PHP
use Merql\Apply\Applier;

$applier = new Applier($connection);
$applied = $applier->apply($result);
// FK dependencies are read from the database via the driver.

Eksempler på genereret SQL

INSERT

Sql
INSERT INTO `posts` (`id`, `title`, `content`, `status`) VALUES (?, ?, ?, ?)
-- params: [42, 'New Post', 'Body text', 'draft']

Alle kolonner fra handlingens værdier medtages.

UPDATE

Sql
UPDATE `posts` SET `title` = ?, `status` = ? WHERE `id` = ?
-- params: ['New Title', 'publish', 42]

Identitetskolonner (primærnøgle) udelades fra SET-delen og bruges i WHERE-delen. Værdierne i WHERE-delen kommer fra afkodning af rækkenøglen.

DELETE

Sql
DELETE FROM `posts` WHERE `id` = ?
-- params: [42]

Kun identitetskolonner indgår i WHERE-delen.

Beskyttet UPDATE

Beskyttede opdateringer indeholder både identitetsbetingelser og betingelser for den forventede live-række.

Sql
UPDATE `posts` SET `title` = ? WHERE `id` = ? AND `status` = ?
-- params: ['New Title', 42, 'draft']

Hvis rækken ikke længere har den forventede status, påvirker sætningen nul rækker, og beskyttet anvendelse ruller transaktionen tilbage.

Beskyttet INSERT

Beskyttede indsættelser bruger NOT EXISTS for at undgå at indsætte en identitet, der er dukket op, siden planen blev oprettet.

Sql
INSERT INTO `posts` (`id`, `title`) SELECT ?, ? WHERE NOT EXISTS (
  SELECT 1 FROM `posts` WHERE `id` = ?
)
-- params: [42, 'New Post', 42]

Håndtering af NULL

NULL-værdier videregives som PHP null i params-arrayet. Forbindelsesadapteren håndterer bindingen:

PHP
$statements = SqlGenerator::generate($result);
// params might contain: [42, null, 'draft']
// The adapter binds null as SQL NULL

I output fra en prøvekørsel vises NULL-værdier som den bogstavelige streng NULL uden anførselstegn.

Registrering af identitetskolonner

SqlGenerator afgør, hvilke kolonner der udgør rækkeidentiteten, ved at se på TableSnapshot::identityColumns i grundøjebliksbilledet. Disse kolonner bruges i WHERE-betingelser for UPDATE- og DELETE-sætninger og udelades fra SET-betingelser i UPDATEs.

Hvis der ikke er et grundøjebliksbillede til rådighed, bruges den første kolonne i værdiarrayet som reserve. Hvis værdiarrayet er tomt, antages id.

Angivelse af en driver

Hvis du vil styre citeringen af identifikatorer, skal du angive en Driver-instans:

PHP
use Merql\Driver\SqliteDriver;

$statements = SqlGenerator::generate(
    $result,
    driver: new SqliteDriver(),
);
// Uses double-quote quoting: "posts", "title"