
# Başlarken

Bu kılavuzda kurulum, veritabanına bağlanma, anlık görüntü alma, farkları hesaplama ve üç yönlü birleştirme adımları anlatılır.

## Kurulum

```bash
composer require merql/merql
```

merql için PHP 8.2+ ile `ext-mbstring` ve `ext-zlib` gerekir (ikisi de `pitmaster/pitmaster` bağımlılığı tarafından zorunlu tutulur). Kullandığınız adaptörün uzantısına da ihtiyacınız vardır: PDO adaptörü için `ext-pdo_sqlite` ile birlikte `ext-pdo` veya `ext-pdo_mysql`; mysqli adaptörü içinse `ext-mysqli` gerekir. Composer yalnızca bunları önerir; bu nedenle ihtiyacınız olanın kurulu olduğunu kontrol edin.

Paket, CLI öğesini `vendor/bin/merql` olarak kurar. CLI için merql 0.4.1 veya sonraki sürümünü kullanın; önceki sürümlerde merql bağımlılık olarak kurulduğunda ikili dosya yükleyiciyi bulamıyordu.

## Veritabanına bağlanma

merql, küçük bir bağlantı adaptörü arayüzü üzerinden çalışır. Yerleşik adaptörler PDO ve mysqli için, yerleşik lehçe sürücüleri ise MySQL ve SQLite için sağlanır.

```php
use Merql\Connection;

// SQLite (in-memory or file-based, through PDO).
$connection = Connection::sqlite(':memory:');
$connection = Connection::sqlite('/path/to/database.sqlite');

// MySQL through PDO.
$connection = Connection::mysql('127.0.0.1', 'my_database', 'root', 'password');

// MySQL through mysqli.
$connection = Connection::mysqli('127.0.0.1', 'my_database', 'root', 'password');

// Any MySQL or SQLite PDO DSN.
$connection = Connection::fromDsn('mysql:host=127.0.0.1;dbname=my_database;charset=utf8mb4', 'root', 'password');
```

`fromDsn()`, PDO'nun desteklediği her DSN'yi açabilir; ancak merql yalnızca MySQL ve SQLite için lehçe sürücüleriyle birlikte gelir. `pgsql:` gibi başka bir altyapıda bağlantı açılır, ancak onun için bir sürücü kaydedene kadar `Merql::init()`, `Unsupported database driver: pgsql` hatasını verir. Bkz. [Veritabanı Sürücüleri](https://merql.inline0.dev/tr/docs/apply/drivers).

## Anlık görüntü alma

Bir anlık görüntü, her tablonun her satırını (veya tabloların bir alt kümesini) parmak izleri ve veriler olarak kaydeder. Parmak izleri değişikliklerin hızla algılanmasını sağlar; fark gerektiğinde tam satır verileri kullanılabilir.

```php
use Merql\Merql;

Merql::init($connection);

// Snapshot all tables.
$snapshot = Merql::snapshot('baseline');

// Snapshot specific tables.
$snapshot = Merql::snapshot('baseline', ['posts', 'comments', 'users']);
```

Anlık görüntüler varsayılan olarak `.merql/snapshots/` içinde JSON dosyaları şeklinde saklanır. Bu konumu değiştirebilirsiniz:

```php
use Merql\Snapshot\SnapshotStore;

SnapshotStore::setDirectory('/var/data/merql-snapshots');
```

## Fark hesaplama

Bir fark, iki anlık görüntüyü karşılaştırır ve ekleme, güncelleme ve silmelerden oluşan bir değişiklik kümesi döndürür. Her iki anlık görüntü de önceden alınmış olmalıdır; burada `current`, veritabanı değiştikten sonra alınan ikinci anlık görüntüdür.

```php
$changeset = Merql::diff('baseline', 'current');

echo "Inserts: " . count($changeset->inserts()) . "\n";
echo "Updates: " . count($changeset->updates()) . "\n";
echo "Deletes: " . count($changeset->deletes()) . "\n";

// Inspect changes for a single table.
$postChanges = $changeset->forTable('posts');

// Check per-column diffs on updates.
foreach ($changeset->updates() as $update) {
    echo "Row {$update->rowKey} in {$update->table}:\n";
    foreach ($update->columnDiffs as $diff) {
        echo "  {$diff->column}: {$diff->oldValue} -> {$diff->newValue}\n";
    }
}
```

## Üç yönlü birleştirme

Temel işlem budur. Adlandırılmış üç anlık görüntüyü (base, ours, theirs) alır ve iki değişiklik kümesini birleştirir.

Base, iki kopyanın da başladığı durumdur. Ours ve theirs, bağımsız olarak değiştirildikten sonraki iki kopyadır; bu nedenle her biri bulunduğu veritabanından alınmalıdır. Örneğin, bir korumalı alan canlı veritabanından kopyalandığında:

```php
use Merql\Connection;
use Merql\Merql;

$live    = Connection::sqlite('/data/live.sqlite');
$sandbox = Connection::sqlite('/data/sandbox.sqlite');

Merql::init($live);
Merql::snapshot('base');      // before the sandbox is copied from live

// ... copy live.sqlite to sandbox.sqlite, then both databases change ...

Merql::init($sandbox);
Merql::snapshot('ours');      // the sandbox with our edits
Merql::init($live);
Merql::snapshot('theirs');    // live with its own changes

$result = Merql::merge('base', 'ours', 'theirs');

echo "Operations: {$result->operationCount()}\n";
echo "Conflicts:  {$result->conflictCount()}\n";
echo "Clean:      " . ($result->isClean() ? 'yes' : 'no') . "\n";
```

Üç anlık görüntünün tamamını tek bir veritabanından sırayla almayın. Theirs, ours'un değişikliklerini zaten içerir ve ours'un eklediği her satır `insert_insert` çakışması olarak görünür.

`Merql::merge()` sütun düzeyinde birleştirme yapar. TEXT ve JSON değerlerinin içini de birleştirmek için `ThreeWayMerge` öğesini bir `CellMergeConfig` ile kullanın; bkz. [Hücre Düzeyinde Birleştirme](https://merql.inline0.dev/tr/docs/merge/cell-level).

### Çakışmaları ele alma

Her iki taraf da aynı sütunu farklı değerlere değiştirdiğinde merql bir çakışma bildirir. Çakışmaları otomatik olarak çözebilir veya elle inceleyebilirsiniz.

```php
use Merql\Merge\ConflictPolicy;
use Merql\Merge\ConflictResolver;

if (!$result->isClean()) {
    // Auto-resolve: one side wins.
    $resolved = ConflictResolver::resolve($result, ConflictPolicy::TheirsWins);

    // Or inspect each conflict.
    foreach ($result->conflicts() as $conflict) {
        echo "Conflict on {$conflict->table()} row {$conflict->rowKey()}:\n";
        echo "  Type:   {$conflict->type()}\n";
        echo "  Column: {$conflict->column()}\n";
        echo "  Ours:   " . var_export($conflict->oursValue(), true) . "\n";
        echo "  Theirs: " . var_export($conflict->theirsValue(), true) . "\n";
    }
}
```

## Birleştirmeyi uygulama

Temiz bir birleştirme sonucu (çözülmemiş çakışma yok) elde ettiğinizde, bunu `Merql::init()` öğesine geçirilen veritabanına uygulayın.

Birleştirme sonucundaki işlemler, base durumunu birleştirilmiş duruma dönüştürür ve her iki tarafın değişikliklerini de içerir. `Merql::apply()` bunların her birini yürütür; bu nedenle base durumunu hâlâ koruyan bir veritabanına sorunsuz uygulanır. Bir tarafın değişikliklerini zaten içeren bir veritabanına uygulandığında, o tarafın eklemeleri mevcut bir satırla çakışır, işlem başarısız olur ve birleştirmenin tamamı geri alınır. Bir tarafın değişikliklerini diğer tarafın bulunduğu veritabanına (örneğin, korumalı alan düzenlemelerini canlı veritabanına) aktarmak için yalnızca eksik işlemleri [Korumalı Uygulama](https://merql.inline0.dev/tr/docs/apply/guarded) ile uygulayın.

```php
$applied = Merql::apply($result);

echo "Rows affected: {$applied->rowsAffected()}\n";

if ($applied->hasErrors()) {
    foreach ($applied->errors() as $error) {
        echo "Error: {$error}\n";
    }
}
```

Uygulayıcı tüm işlemleri bir işlem içine alır. Herhangi bir ifade başarısız olursa birleştirmenin tamamı geri alınır ve hata `errors()` içinde döndürülür. Bu durumda `rowsAffected()` başarısızlıktan önce çalıştırılan ifadeleri, geri alınmış olsalar bile saymaya devam eder ([#4](https://github.com/inline0/merql/issues/4)); önce `hasErrors()` öğesini kontrol edin.

## Deneme çalıştırması

Birleştirmenin oluşturacağı SQL öğesini çalıştırmadan önizleyin.

```php
use Merql\Apply\DryRun;

$statements = DryRun::generate($result);

foreach ($statements as $sql) {
    echo "{$sql};\n";
}
```

## İki yönlü yama

Yalnızca bir base ve bir dizi değişikliğiniz varsa (eşzamanlı "ours" değişiklikleri yoksa) `patch()` kullanın. Bu, ours'un base'den değişmediği birleştirmeyle eşdeğerdir.

```php
$result = Merql::patch('base', 'changes');
// Always clean: no concurrent edits means no conflicts.
Merql::apply($result);
```

## CLI kullanımı

Bu işlemlerin tümü komut satırından da kullanılabilir. Tüm ayrıntılar için [CLI Başvurusu](https://merql.inline0.dev/tr/docs/cli) bölümüne bakın.

```bash
export MERQL_DB_DSN="sqlite:mydb.sqlite"

vendor/bin/merql snapshot base
# ... change the database ...
vendor/bin/merql snapshot current
vendor/bin/merql diff base current
```

Üç yönlü birleştirme için her anlık görüntüyü ilgili durumu barındıran veritabanından alın, ardından birleştirin:

```bash
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot base
MERQL_DB_DSN="sqlite:/data/sandbox.sqlite" vendor/bin/merql snapshot ours
MERQL_DB_DSN="sqlite:/data/live.sqlite" vendor/bin/merql snapshot theirs
vendor/bin/merql merge base ours theirs --dry-run
```

## Tabloları ve sütunları filtreleme

Anlık görüntülerden tabloları (önbellek veya oturum tabloları gibi) çıkarabilir ve değişken sütunları (`updated_at` zaman damgaları gibi) yok sayabilirsiniz.

```php
use Merql\Filter\TableFilter;
use Merql\Filter\ColumnFilter;
use Merql\Snapshot\Snapshotter;

$snapshotter = new Snapshotter($connection);

$snapshot = $snapshotter->capture('baseline', filters: [
    TableFilter::exclude(['sessions', 'cache_*']),
    ColumnFilter::ignore(['updated_at', 'modified_date']),
]);
```

## Sonraki adımlar

- Komut satırı arayüzünün tamamı için [CLI Başvurusu](https://merql.inline0.dev/tr/docs/cli) bölümüne bakın.
- Her sınıf ve yöntemin ayrıntılı belgeleri için [PHP API Başvurusu](https://merql.inline0.dev/tr/docs/api) bölümüne bakın.
