44#include " CBLHeader.h"
55#include CBL_HEADER(CouchbaseLite.h)
66
7+ #include " Defer.h"
8+ #include " Define.h"
79#include " JSON.h"
810
911using namespace std ;
@@ -12,8 +14,8 @@ using namespace ts::support::json_util;
1214namespace ts ::cbl {
1315 class LocalWinsConflictResolver : public ConflictResolver {
1416 public:
15- explicit LocalWinsConflictResolver (const ConflictResolverSpec &spec) : ConflictResolver(
16- spec) {}
17+ explicit LocalWinsConflictResolver (const ConflictResolverSpec &spec)
18+ : ConflictResolver( spec) {}
1719
1820 const CBLDocument *
1921 resolve (const CBLDocument *localDoc, const CBLDocument *remoteDoc) override {
@@ -25,8 +27,8 @@ namespace ts::cbl {
2527
2628 class RemoteWinsConflictResolver : public ConflictResolver {
2729 public:
28- explicit RemoteWinsConflictResolver (const ConflictResolverSpec &spec) : ConflictResolver(
29- spec) {}
30+ explicit RemoteWinsConflictResolver (const ConflictResolverSpec &spec)
31+ : ConflictResolver( spec) {}
3032
3133 const CBLDocument *
3234 resolve (const CBLDocument *localDoc, const CBLDocument *remoteDoc) override {
@@ -38,8 +40,8 @@ namespace ts::cbl {
3840
3941 class DeleteConflictResolver : public ConflictResolver {
4042 public:
41- explicit DeleteConflictResolver (const ConflictResolverSpec &spec) : ConflictResolver(
42- spec) {}
43+ explicit DeleteConflictResolver (const ConflictResolverSpec &spec)
44+ : ConflictResolver( spec) {}
4345
4446 const CBLDocument *
4547 resolve (const CBLDocument *localDoc, const CBLDocument *remoteDoc) override {
@@ -51,8 +53,9 @@ namespace ts::cbl {
5153
5254 class MergeConflictResolver : public ConflictResolver {
5355 public:
54- explicit MergeConflictResolver (const ConflictResolverSpec &spec) : ConflictResolver(
55- spec) {
56+ explicit MergeConflictResolver (const ConflictResolverSpec &spec)
57+ : ConflictResolver(spec)
58+ {
5659 auto params = ConflictResolver::spec ().params ;
5760 _property = GetValue<string>(params, " property" );
5861 }
@@ -61,31 +64,31 @@ namespace ts::cbl {
6164 resolve (const CBLDocument *localDoc, const CBLDocument *remoteDoc) override {
6265 if (!localDoc || !remoteDoc) { return nullptr ; }
6366
64- auto doc = CBLDocument_MutableCopy (remoteDoc);
67+ auto mergedDoc = CBLDocument_MutableCopy (remoteDoc);
68+ auto mergedValues = FLMutableArray_New ();
6569
66- FLSlice key = FLStr (_property.data ());
67- auto array = FLMutableArray_New ();
68- auto prop = CBLDocument_Properties (localDoc);
69- auto value = FLDict_Get (prop, key );
70- if (value ) {
71- FLMutableArray_AppendValue (array, value );
70+ FLSlice docKey = FLStr (_property.data ());
71+
72+ auto localProps = CBLDocument_Properties (localDoc);
73+ auto localValue = FLDict_Get (localProps, docKey );
74+ if (localValue ) {
75+ FLMutableArray_AppendValue (mergedValues, localValue );
7276 } else {
73- FLMutableArray_AppendNull (array );
77+ FLMutableArray_AppendNull (mergedValues );
7478 }
7579
76- prop = CBLDocument_Properties (remoteDoc);
77- value = FLDict_Get (prop, key );
78- if (value ) {
79- FLMutableArray_AppendValue (array, value );
80+ auto remoteProps = CBLDocument_Properties (remoteDoc);
81+ auto remoteValue = FLDict_Get (remoteProps, docKey );
82+ if (remoteValue ) {
83+ FLMutableArray_AppendValue (mergedValues, remoteValue );
8084 } else {
81- FLMutableArray_AppendNull (array );
85+ FLMutableArray_AppendNull (mergedValues );
8286 }
8387
84- auto props = CBLDocument_MutableProperties (doc);
85- FLMutableDict_SetArray (props, key, array);
86- FLMutableArray_Release (array);
87-
88- return doc;
88+ auto mergedProps = CBLDocument_MutableProperties (mergedDoc);
89+ FLMutableDict_SetArray (mergedProps, docKey, mergedValues);
90+ FLMutableArray_Release (mergedValues);
91+ return mergedDoc;
8992 }
9093
9194 static string name () { return " merge" ; }
@@ -94,6 +97,78 @@ namespace ts::cbl {
9497 string _property;
9598 };
9699
100+ class MergeDictConflictResolver : public ConflictResolver {
101+ public:
102+ explicit MergeDictConflictResolver (const ConflictResolverSpec &spec)
103+ : ConflictResolver(spec)
104+ {
105+ auto params = ConflictResolver::spec ().params ;
106+ _property = GetValue<string>(params, " property" );
107+ }
108+
109+ const CBLDocument *
110+ resolve (const CBLDocument *localDoc, const CBLDocument *remoteDoc) override {
111+ if (!localDoc || !remoteDoc) { return nullptr ; }
112+
113+ auto mergedDoc = CBLDocument_MutableCopy (remoteDoc);
114+ auto mergedProps = CBLDocument_MutableProperties (mergedDoc);
115+
116+ FLSlice docKey = FLS (_property);
117+
118+ auto localProps = CBLDocument_Properties (localDoc);
119+ auto localDict = FLValue_AsDict (FLDict_Get (localProps, docKey)) ;
120+
121+ auto remoteProps = CBLDocument_Properties (remoteDoc);
122+ auto remoteDict = FLValue_AsDict (FLDict_Get (remoteProps, docKey));
123+
124+ if (!localDict || !remoteDict) {
125+ FLMutableDict_SetString (mergedProps, docKey, FLStr (" Both values are not dictionary" ));
126+ return mergedDoc;
127+ }
128+
129+ auto mergedDict = FLMutableDict_New ();
130+ DEFER { FLMutableDict_Release (mergedDict); };
131+
132+ // Merge Local:
133+ {
134+ FLDictIterator iter;
135+ FLDictIterator_Begin (localDict, &iter);
136+ FLValue value;
137+ while (nullptr != (value = FLDictIterator_GetValue (&iter))) {
138+ FLString key = FLDictIterator_GetKeyString (&iter);
139+ FLMutableDict_SetValue (mergedDict, key, value);
140+ FLDictIterator_Next (&iter);
141+ }
142+ }
143+
144+ // Merge Remote:
145+ {
146+ FLDictIterator iter;
147+ FLDictIterator_Begin (remoteDict, &iter);
148+ FLValue value;
149+ while (nullptr != (value = FLDictIterator_GetValue (&iter))) {
150+ FLString key = FLDictIterator_GetKeyString (&iter);
151+ FLValue currentValue = FLDict_Get (mergedDict, key);
152+ if (currentValue && !FLValue_IsEqual (value, currentValue)) {
153+ string error = " Conflicting values found at key named '" + STR (key) + " '" ;
154+ FLMutableDict_SetString (mergedProps, docKey, FLS (error));
155+ return mergedDoc;
156+ }
157+ FLMutableDict_SetValue (mergedDict, key, value);
158+ FLDictIterator_Next (&iter);
159+ }
160+ }
161+
162+ FLMutableDict_SetDict (mergedProps, docKey, mergedDict);
163+ return mergedDoc;
164+ }
165+
166+ static string name () { return " merge-dict" ; }
167+
168+ private:
169+ string _property;
170+ };
171+
97172 ConflictResolver *ConflictResolver::make_resolver (const ConflictResolverSpec &spec) {
98173 if (spec.name == LocalWinsConflictResolver::name ()) {
99174 return new LocalWinsConflictResolver (spec);
@@ -103,6 +178,8 @@ namespace ts::cbl {
103178 return new DeleteConflictResolver (spec);
104179 } else if (spec.name == MergeConflictResolver::name ()) {
105180 return new MergeConflictResolver (spec);
181+ } else if (spec.name == MergeDictConflictResolver::name ()) {
182+ return new MergeDictConflictResolver (spec);
106183 }
107184 return nullptr ;
108185 }
0 commit comments