Към съдържанието

Сливане на ниво колона

Сливането на ниво колона е основното предимство на merql пред наивното сравнение на ниво ред. Когато и двете страни променят един и същи ред, merql сравнява всяка колона поотделно, вместо да маркира целия ред като конфликт.

Проблемът със сливането на ниво ред

Да разгледаме таблица posts, в която двама души редактират един и същи ред:

Код
Base:    post #42  { title: "Hello",     content: "Body",    status: "draft"   }
Ours:    post #42  { title: "Hello",     content: "Body v2", status: "draft"   }
Theirs:  post #42  { title: "New Title", content: "Body",    status: "publish" }

Сливането на ниво ред установява, че и двете страни са променили реда, и обявява конфликт. Но промените изобщо не се застъпват. Ние редактирахме content, а те — title и status.

Как сливането на ниво колона разрешава проблема

merql прилага едни и същи правила за тристранно сливане към всяка колона поотделно:

Код
title:   base="Hello", ours="Hello",  theirs="New Title"  -> accept theirs
content: base="Body",  ours="Body v2", theirs="Body"      -> accept ours
status:  base="draft", ours="draft",  theirs="publish"    -> accept theirs

Резултат: { title: "New Title", content: "Body v2", status: "publish" }. Чисто сливане, без конфликт.

Как работи

Когато ThreeWayMerge установи, че и двете страни са актуализирали един и същи ред, той предава обработката на ColumnMerge::merge():

PHP
use Merql\Merge\ColumnMerge;

$result = ColumnMerge::merge(
    table: 'posts',
    rowKey: '42',
    base: ['title' => 'Hello', 'content' => 'Body', 'status' => 'draft'],
    ours: ['title' => 'Hello', 'content' => 'Body v2', 'status' => 'draft'],
    theirs: ['title' => 'New Title', 'content' => 'Body', 'status' => 'publish'],
);

// $result['values']    -> merged column values
// $result['conflicts'] -> list of Conflict objects (empty if clean)

За всяка колона се прилагат едни и същи правила:

База Нашето Тяхното Резултат
A A A Запазва се базовата стойност (няма промяна)
A A B Приема се тяхната стойност
A B A Приема се нашата стойност
A B B Приема се (и двете съвпадат)
A B C Конфликт (различни стойности)

Кога все пак възникват конфликти

Конфликт на ниво колона възниква, когато и двете страни променят една и съща колона с различни стойности:

Код
Base:    post #42  { title: "Hello" }
Ours:    post #42  { title: "Welcome" }
Theirs:  post #42  { title: "Greetings" }

И двете страни промениха title с различни стойности. Това е действителен конфликт, който трябва да бъде разрешен.

PHP
$result = ColumnMerge::merge(
    'posts', '42',
    ['title' => 'Hello'],
    ['title' => 'Welcome'],
    ['title' => 'Greetings'],
);

// $result['conflicts'] contains one Conflict:
//   table: "posts", column: "title"
//   oursValue: "Welcome", theirsValue: "Greetings", baseValue: "Hello"

Частични конфликти

Един ред може да съдържа както чисто слети стойности, така и конфликти. Ако една колона се слее без конфликт, а друга породи конфликт, MergeOperation за реда съдържа обединените стойности в колоните без конфликт и нашата стойност (по подразбиране) в колоните с конфликт. Конфликтът се отчита отделно.

Код
Base:    { title: "Hello", content: "Body",    status: "draft" }
Ours:    { title: "Welcome", content: "Body v2", status: "draft" }
Theirs:  { title: "Greetings", content: "Body",    status: "publish" }

Тук title е в конфликт (и двете страни са го променили по различен начин), content се слива без конфликт (променили сме го само ние), а status се слива без конфликт (променили са го само те). Операцията съдържа:

PHP
// values: { title: "Welcome", content: "Body v2", status: "publish" }
// One conflict on the "title" column.

Сравнение на стойности

Стойностите в колоните се сравняват като низове след преобразуване. NULL е отделна стойност:

  • NULL към NULL = няма промяна.
  • NULL към "hello" = актуализация.
  • "hello" към NULL = актуализация.
  • "1" към 1 = няма промяна (и двете се преобразуват в низа "1").

Това съответства на семантиката за извличане на адаптера за връзка MerQL: всички стойности от базата данни се връщат като низове (или NULL).

Сливане на ниво клетка

Когато сливането на ниво колона все пак доведе до конфликт (и двете страни са променили една и съща колона с различни стойности), merql може да слезе едно ниво по-надолу с сливане на ниво клетка. То се прилага към колони TEXT (разлики ред по ред) и колони JSON (разлики ключ по ключ), като разрешава случаи, в които двете страни са редактирали различни части от стойността на една и съща колона.