열 단위 병합
열 단위 병합은 단순한 행 단위 비교에 비해 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" }
행 단위 병합은 양쪽에서 행을 변경했다는 이유로 충돌을 선언합니다. 하지만 변경 사항은 전혀 겹치지 않습니다. ours는 content을 편집했고, theirs는 title과 status를 편집했습니다.
열 단위 병합으로 해결하는 방법
merql은 각 열에 동일한 3방향 병합 규칙을 개별 적용합니다.
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()에 처리를 위임합니다.
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)
각 열에 다음 규칙이 적용됩니다.
| 기준 | ours | theirs | 결과 |
|---|---|---|---|
| A | A | A | 기준값 유지(변경 없음) |
| A | A | B | theirs 적용 |
| A | B | A | ours 적용 |
| A | B | B | 적용(양쪽 일치) |
| A | B | C | 충돌(값이 다름) |
충돌이 계속 발생하는 경우
양쪽에서 같은 열을 서로 다른 값으로 변경하면 열 단위 충돌이 발생합니다.
Base: post #42 { title: "Hello" }
Ours: post #42 { title: "Welcome" }
Theirs: post #42 { title: "Greetings" }
양쪽에서 title을 서로 다른 값으로 변경했습니다. 해결이 필요한 실제 충돌입니다.
$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에는 충돌 없는 열의 병합 값과 충돌한 열의 ours 값(기본값)이 포함됩니다. 충돌은 별도로 보고됩니다.
Base: { title: "Hello", content: "Body", status: "draft" }
Ours: { title: "Welcome", content: "Body v2", status: "draft" }
Theirs: { title: "Greetings", content: "Body", status: "publish" }
여기서 title은 충돌하고(양쪽에서 다르게 변경), content은 충돌 없이 병합되며(ours만 변경), status도 충돌 없이 병합됩니다(theirs만 변경). 작업에는 다음 내용이 포함됩니다.
// 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 열(줄 단위 diff)과 JSON 열(키 단위 diff)에 적용해 양쪽에서 같은 열 값의 서로 다른 부분을 편집한 경우를 해결합니다.