
# SQL Oluşturma

`SqlGenerator`, bir `MergeResult` öğesini parametreli SQL ifadelerine dönüştürür. Tüm değerler parametre olarak bağlanır; SQL dizgesine asla eklenmez.

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

Gözden geçirilmiş bir birleştirme planının yalnızca canlı
satırlar beklenen anlık görüntüyle eşleşmeye devam ediyorsa uygulanması gerektiğinde `generateGuarded()` kullanın.

```php
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;

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

## İfade biçimi

Her ifade, iki anahtarı olan ilişkisel bir dizidir:

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

Tanımlayıcılar (tablo ve sütun adları), veritabanı sürücüsünün tırnaklama biçimiyle tırnak içine alınır. MySQL ters tırnak, SQLite çift tırnak kullanır. Sürücü belirtilmezse varsayılan olarak ters tırnak kullanılır.

## İşlem sıralaması

İşlemler türe göre gruplandırılır ve şu sırayla yürütülür:

1. Önce **INSERT** işlemleri -- güncellemelerin başvurabilmesi için yeni satırlar önce oluşturulmalıdır.
2. İkinci olarak **UPDATE** işlemleri.
3. Son olarak **DELETE** işlemleri -- silinmeden önce satırlara yapılan başvurular kaldırılmalıdır.

```php
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.
```

## Yabancı anahtar sıralaması

Yabancı anahtar bağımlılıkları sağlandığında, her grup içindeki işlemler topolojik olarak sıralanır. Ekleme ve güncelleme işlemlerinde üst tablolar alt tablolardan önce işlenir. Silme işlemlerinde alt tablolar üst tablolardan önce işlenir.

```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` bağımlılık grafiğinde topolojik sıralama yapar. Döngüsel bağımlılıklar algılanır ve sonsuz döngüleri önlemek için kırılır.

### Otomatik yabancı anahtar algılama

`Applier`, yabancı anahtar ilişkilerini veritabanından otomatik olarak okur:

```php
use Merql\Apply\Applier;

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

## Oluşturulan SQL örnekleri

### INSERT

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

İşlem değerlerindeki tüm sütunlar dahil edilir.

### UPDATE

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

Kimlik sütunları (birincil anahtar) SET ifadesinin dışında bırakılır ve WHERE ifadesinde kullanılır. WHERE ifadesinin değerleri satır anahtarının kodu çözülerek elde edilir.

### DELETE

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

WHERE ifadesinde yalnızca kimlik sütunları yer alır.

### Korumalı UPDATE

Korumalı güncellemeler hem kimlik koşullarını hem de beklenen canlı satır koşullarını içerir.

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

Satır artık beklenen `status` değerine sahip değilse, ifade sıfır satırı etkiler
ve korumalı uygulama işlemi geri alır.

### Korumalı INSERT

Korumalı eklemeler, plan oluşturulduktan sonra ortaya çıkan bir kimliğe ekleme yapılmasını önlemek için `NOT EXISTS` kullanır.

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

## NULL işleme

NULL değerler, parametreler dizisinde PHP `null` olarak iletilir. Bağlamayı bağlantı adaptörü yönetir:

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

Deneme çalıştırması çıktısında NULL değerler, tırnak işareti olmadan `NULL` değişmez dizgesi olarak gösterilir.

## Kimlik sütununu algılama

`SqlGenerator`, satır kimliğini oluşturan sütunları temel anlık görüntünün `TableSnapshot::identityColumns` değerine bakarak belirler. Bu sütunlar UPDATE ve DELETE ifadelerinin WHERE koşullarında kullanılır; UPDATE işlemlerinin SET koşullarından çıkarılır.

Temel anlık görüntü yoksa, değerler dizisindeki ilk sütun yedek olarak kullanılır. Değerler dizisi boşsa `id` varsayılır.

## Sürücü geçirme

Tanımlayıcıların nasıl tırnak içine alınacağını denetlemek için bir `Driver` örneği geçirin:

```php
use Merql\Driver\SqliteDriver;

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