SQL 생성
SqlGenerator은 MergeResult을 매개변수화된 SQL 문으로 변환합니다. 모든 값은 매개변수로 바인딩되며 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']
}
검토한 병합 계획을 라이브 행이 여전히 예상 스냅샷과 일치할 때만 적용하려면 generateGuarded()을 사용하세요.
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;
$statements = SqlGenerator::generateGuarded(
$selectedResult,
SnapshotStore::load('theirs'),
);
문 형식
각 문은 두 키가 있는 연관 배열입니다:
[
'sql' => 'INSERT INTO `posts` (`id`, `title`) VALUES (?, ?)',
'params' => [42, 'New Title'],
]
식별자(테이블 및 열 이름)는 데이터베이스 드라이버의 인용 방식으로 인용됩니다. MySQL은 백틱을 사용하고 SQLite은 큰따옴표를 사용합니다. 드라이버를 지정하지 않으면 백틱 인용을 기본값으로 사용합니다.
작업 순서
작업은 유형별로 그룹화되어 다음 순서로 실행됩니다:
- 먼저 INSERT합니다. 업데이트에서 참조할 새 행이 먼저 있어야 합니다.
- 다음으로 UPDATE합니다.
- 마지막으로 DELETE합니다. 삭제 전에 참조 관계를 해제해야 합니다.
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.
외래 키 순서
외래 키 종속성이 제공되면 각 그룹 내 작업을 위상 정렬합니다. 삽입과 업데이트에서는 부모 테이블을 자식 테이블보다 먼저 처리하고, 삭제에서는 자식 테이블을 부모 테이블보다 먼저 처리합니다.
$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은 종속성 그래프를 위상 정렬합니다. 무한 루프를 방지하기 위해 순환 종속성을 감지하고 해소합니다.
자동 외래 키 감지
Applier은 데이터베이스에서 외래 키 관계를 자동으로 읽어옵니다.
use Merql\Apply\Applier;
$applier = new Applier($connection);
$applied = $applier->apply($result);
// FK dependencies are read from the database via the driver.
생성되는 SQL 예시
INSERT
INSERT INTO `posts` (`id`, `title`, `content`, `status`) VALUES (?, ?, ?, ?)
-- params: [42, 'New Post', 'Body text', 'draft']
작업 값에 있는 모든 열이 포함됩니다.
UPDATE
UPDATE `posts` SET `title` = ?, `status` = ? WHERE `id` = ?
-- params: ['New Title', 'publish', 42]
식별 열(기본 키)은 SET 절에서 제외되고 WHERE 절에 사용됩니다. WHERE 절의 값은 행 키를 디코딩해 가져옵니다.
DELETE
DELETE FROM `posts` WHERE `id` = ?
-- params: [42]
WHERE 절에는 식별 열만 나타납니다.
보호된 UPDATE
보호된 업데이트에는 식별 조건과 예상되는 현재 행 조건이 모두 포함됩니다.
UPDATE `posts` SET `title` = ? WHERE `id` = ? AND `status` = ?
-- params: ['New Title', 42, 'draft']
행에 더 이상 예상한 status이 없으면 문이 영향을 미치는 행은 0개이며
보호된 적용은 트랜잭션을 롤백합니다.
보호된 INSERT
보호된 삽입은 NOT EXISTS을 사용해 계획 생성 후 나타난 식별 값에 삽입하지 않도록 합니다.
INSERT INTO `posts` (`id`, `title`) SELECT ?, ? WHERE NOT EXISTS (
SELECT 1 FROM `posts` WHERE `id` = ?
)
-- params: [42, 'New Post', 42]
NULL 처리
NULL 값은 params 배열에서 PHP null로 전달됩니다. 바인딩은 연결 어댑터가 처리합니다.
$statements = SqlGenerator::generate($result);
// params might contain: [42, null, 'draft']
// The adapter binds null as SQL NULL
드라이 런 출력에서 NULL 값은 따옴표 없는 리터럴 문자열 NULL로 표시됩니다.
식별 열 감지
SqlGenerator은 기본 스냅샷의 TableSnapshot::identityColumns을 살펴 행 식별자를 구성하는 열을 판별합니다. 이 열은 UPDATE 및 DELETE 문의 WHERE 절에 사용되고, UPDATE의 SET 절에서는 제외됩니다.
기본 스냅샷을 사용할 수 없으면 값 배열의 첫 번째 열을 대체값으로 사용합니다. 값 배열이 비어 있으면 id으로 간주합니다.
드라이버 전달
식별자 인용 방식을 제어하려면 Driver 인스턴스를 전달합니다.
use Merql\Driver\SqliteDriver;
$statements = SqlGenerator::generate(
$result,
driver: new SqliteDriver(),
);
// Uses double-quote quoting: "posts", "title"