
# Satır Kimliği

Satır kimliği, merql'nin anlık görüntüler arasında satırları nasıl eşleştireceğini belirler. base ile ours karşılaştırılırken, bazı sütun değerleri değişmiş olsa bile base içindeki X satırının ours içindeki Y satırıyla aynı mantıksal satır olduğunu bilmesi gerekir. Kimlik kuralı, satır anahtarını hangi sütunların oluşturduğunu belirler.

```php
use Merql\Identity\PrimaryKeyIdentity;

$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"
```

## RowIdentity arayüzü

Tüm kimlik stratejileri iki yöntem uygular:

```php
interface RowIdentity
{
    public function key(array $row): string;
    public function columns(): array;
}
```

`key()`, satır verilerinden benzersiz bir dize tanımlayıcı oluşturur. `columns()`, kimlik için kullanılan sütun adlarını döndürür.

## PrimaryKeyIdentity

Varsayılan strateji. Satırları birincil anahtar sütunlarına göre eşleştirir.

```php
use Merql\Identity\PrimaryKeyIdentity;

// Single-column PK.
$identity = new PrimaryKeyIdentity(['id']);
$key = $identity->key(['id' => 42, 'title' => 'Hello']);
// "42"

// Composite PK.
$identity = new PrimaryKeyIdentity(['tenant_id', 'user_id']);
$key = $identity->key(['tenant_id' => 1, 'user_id' => 99, 'name' => 'Alice']);
// "1\x1F99" (unit separator between parts)
```

Tablonun şemasında tanımlanmış bir birincil anahtarı varsa, merql varsayılan olarak bunu kullanır.

## NaturalKeyIdentity

Otomatik artan birincil anahtarı olmayan tablolarda satırları benzersiz kısıt sütunlarına göre eşleştirir. PK bir UUID olduğunda veya tablo mantıksal kimliği olarak bileşik bir benzersiz kısıt kullandığında yararlıdır.

```php
use Merql\Identity\NaturalKeyIdentity;

$identity = new NaturalKeyIdentity(['email']);
$key = $identity->key(['id' => 1, 'email' => 'alice@example.com', 'name' => 'Alice']);
// "alice@example.com"

$identity = new NaturalKeyIdentity(['country', 'postal_code']);
$key = $identity->key(['country' => 'US', 'postal_code' => '90210', 'city' => 'Beverly Hills']);
// "US\x1F90210"
```

## ContentHashIdentity

Birincil anahtarı ve benzersiz kısıtı olmayan tablolar için yedek yöntemdir. Tüm sütun değerlerinin SHA-256 karmasını hesaplar. İki satır, tüm sütunları eşleşiyorsa aynıdır.

```php
use Merql\Identity\ContentHashIdentity;

$identity = new ContentHashIdentity(['name', 'value']);
$key = $identity->key(['name' => 'color', 'value' => 'blue']);
// "a3f2..." (SHA-256 hash)
```

İçerik karmasıyla kimlik belirlemenin bir kısıtlaması vardır: satırın içeriği değişirse karması da değişir. Bu nedenle satır, güncelleme olarak değil, eski karmanın silinip yeni karmanın eklenmesi olarak görünür. Bu, sabit kimlik sütunları olmadığında kaçınılmaz bir ödünleşimdir.

## IdentityRule

`IdentityRule`, anlık görüntü yakalama ve birleştirme planlarında kullanılan serileştirilebilir kimlik yapılandırmasıdır.

```php
use Merql\Identity\IdentityRule;

$rule = IdentityRule::natural(['option_name']);
$key = $rule->key(['option_name' => 'siteurl']);
// "siteurl"
```

Kural türleri:

| Tür | Anlamı |
|---|---|
| `primary` | Veritabanı birincil anahtar sütunları |
| `natural` | Kararlı benzersiz iş sütunları |
| `composite` | Bileşik mantıksal kimlik sütunları |
| `content` | İçerik karması yedek yöntemi |

`IdentityRule::forSchema($schema)`, varsayılan kuralı belirler:

1. Tablonun birincil anahtarı varsa bu anahtar sütunlarını kullanır.
2. Tablonun benzersiz anahtarları varsa ilk benzersiz anahtarın sütunlarını kullanır.
3. İkisi de yoksa tüm sütunları kullanır (içerik karması yedek yöntemi).

## IdentityRuleSet

Bir ana uygulama, şema varsayılanından daha uygun bir kimlik kuralı biliyorsa `IdentityRuleSet` kullanın.

```php
use Merql\Identity\IdentityRule;
use Merql\Identity\IdentityRuleSet;
use Merql\Snapshot\Snapshotter;

$rules = new IdentityRuleSet([
    'wp_options' => IdentityRule::natural(['option_name']),
    'wp_term_relationships' => IdentityRule::composite(['object_id', 'term_taxonomy_id']),
]);

$snapshotter = new Snapshotter($connection, identityRules: $rules);
$snapshot = $snapshotter->capture('live', ['wp_options', 'wp_term_relationships']);
```

`Snapshotter`, yakalanan her tablo için bir `IdentityRule` belirler. Seçilen sütunlar `TableSnapshot::identityColumns` içinde saklanır ve sonraki tüm diff, birleştirme, plan, SQL ve geri alma işlemlerinde kullanılır.

Statik facade kullanılırken `Merql::init()`'e aynı kural kümesi verilebilir:

```php
use Merql\Merql;

Merql::init($connection, identityRules: $rules);
Merql::snapshot('live', ['wp_options']);
```

Kural kümelerinin dizi serileştirmesi kararlıdır:

```php
$payload = $rules->toArray();
$rules = IdentityRuleSet::fromArray($payload);
```

## Belirsiz Kimlik

Yakalanan iki satır aynı kimlik anahtarını üretirse, bir satır diğerinin üzerine yazılmak yerine yakalama başarısız olur.

```php
use Merql\Exceptions\SnapshotException;

try {
    $snapshotter->capture('live', ['wp_postmeta']);
} catch (SnapshotException $e) {
    // The configured identity rule matched multiple rows.
}
```

Ana uygulamalar, yakalama öncesinde belirsizliği bildirmek istediklerinde ham satırları `IdentityRuleSet::conflictsFor()` ile önceden denetleyebilir:

```php
$conflicts = $rules->conflictsFor(
    'wp_postmeta',
    IdentityRule::natural(['post_id', 'meta_key']),
    $rows,
);
```

WordPress meta tablolarında, `post_id + meta_key` gruplama ve görüntüleme için genellikle kullanışlıdır; ancak yinelenen meta anahtarlarına izin verildiğinden satır kimliği olarak güvenli değildir. Ana uygulama doğal anahtarın benzersiz olduğunu kanıtlayamıyorsa, satır kimliği için tablonun birincil anahtarını kullanın.

## Satır anahtarı kodlaması

Satır anahtarları, birden fazla sütun değerini birim ayırıcıyla (`\x1F`) birleştiren kodlanmış dizelerdir. Çakışmaları önlemek için ayırıcı veya yüzde işareti içeren değerler kaçışlanır:

```php
use Merql\Snapshot\Snapshotter;

// Encode.
$key = Snapshotter::buildRowKey(
    ['tenant_id' => '1', 'user_id' => '99'],
    ['tenant_id', 'user_id'],
);
// "1\x1F99"

// Decode.
$parts = Snapshotter::decodeRowKey($key);
// ['1', '99']
```

Kaçışlama kuralları:

| Özgün | Kaçışlanmış |
|---|---|
| `%` | `%25` |
| `\x1F` (birim ayırıcı) | `%1F` |

Bu sayede `\x1F` içeren bir değer birden fazla anahtar parçasına bölünmez. Kodlama belirleyicidir ve tersine çevrilebilir.

## Otomatik artan kimliklerin ayrışması

Her iki taraf da yeni satırlar eklediğinde, otomatik artan kimlikler dallar arasında farklı olur. ours içindeki #100 satırı, theirs içindeki #100 satırından tamamen farklı bir kayıt olabilir.

merql bunu birincil anahtara göre eşleştirerek yönetir. Her iki taraf da aynı otomatik artan kimliğe sahip bir satır eklediyse bu, `insert_insert` çakışması olarak işaretlenir. Bunu önlemek için eşzamanlı ekleme beklenen tablolarda doğal anahtarları (dallar arasında sabit kalan benzersiz sütunları) kullanın.

```php
// A natural key on (slug) avoids auto-increment collisions.
$identity = new NaturalKeyIdentity(['slug']);
```

## Anlık görüntülerde kimlik

Yakalama sırasında seçilen kimlik sütunları her `TableSnapshot` ile birlikte saklanır:

```php
$tableSnapshot = $snapshot->getTable('posts');
$tableSnapshot->identityColumns;
// ['id']
```

`SqlGenerator` bu sütunları UPDATE ve DELETE ifadeleri için WHERE koşulları oluştururken kullanır. Birleştirme planları da bunları kullanarak incelenmek, seçilmek, korumalı uygulama ve geri alma için çözümlenmiş kimlik değerlerini sunar.
