Skip to content

Instantly share code, notes, and snippets.

@n1schal
Last active June 14, 2017 05:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save n1schal/0c45802c7e9fc84f987c1d9c6851f07e to your computer and use it in GitHub Desktop.
Save n1schal/0c45802c7e9fc84f987c1d9c6851f07e to your computer and use it in GitHub Desktop.
//Started along with sync initiation
public void StartConflictLiveQuery()
{
ConflictsLiveQuery = Database.CreateAllDocumentsQuery().ToLiveQuery();
ConflictsLiveQuery.AllDocsMode = AllDocsMode.OnlyConflicts;
ConflictsLiveQuery.Changed += HandleConflicts;
ConflictsLiveQuery.Start();
}
private void HandleConflicts(object sender, QueryChangeEventArgs e)
{
var rows = ConflictsLiveQuery?.Rows;
if (rows == null)
{
return;
}
foreach (var row in rows)
{
var conflicts = row.GetConflictingRevisions().ToArray();
if (conflicts.Length > 1)
{
var defaultWinning = conflicts[0];
var type = defaultWinning.GetProperty("type") as string ?? "";
var id = defaultWinning.GetProperty("_id") as string ?? "";
AppLog.WriteLogD(TAG + "ResolveConflicts", "Id: " + id);
AppLog.WriteLogD(TAG + "ResolveConflicts", "Document Type: " + type);
AppLog.WriteLogD(TAG + "ResolveConflicts", "ConflictsCount: " + conflicts.Length);
switch (type)
{
// Automatic conflict resolution
case "patient":
var props = defaultWinning.UserProperties;
ResolveConflicts(conflicts, props);
break;
// N-way merge conflict resolution
case "user_info":
var merged = NWayMergeConflicts(conflicts);
ResolveConflicts(conflicts, merged);
break;
default:
break;
}
}
}
}
private void ResolveConflicts(SavedRevision[] revs, IDictionary<string, object> props)
{
Database.RunInTransaction(() =>
{
var i = 0;
foreach (var rev in revs)
{
var newRev = rev.CreateRevision();
if (i == 0)
{ // Default winning revision
newRev.SetUserProperties(props);
}
else
{
newRev.IsDeletion = true;
}
try
{
newRev.Save(true);
}
catch (Exception e)
{
AppLog.WriteLogD(TAG, $"Cannot resolve conflicts with error: {e}");
return false;
}
i += 1;
}
return true;
});
}
private IDictionary<string, object> NWayMergeConflicts(SavedRevision[] revs)
{
var parent = FindCommonParent(revs);
if (parent == null)
{
var defaultWinning = revs[0];
var props = defaultWinning.UserProperties;
return props;
}
var mergedProps = parent.UserProperties ?? new Dictionary<string, object>();
var gotDevToken = false;
var gotSubCancelDate = false;
var gotPlanId = false;
var gotSubName = false;
var gotCancelled = false;
var gotHasCard = false;
var gotSubscribed = false;
var gotSubCreateDate = false;
var gotExpireDate = false;
var gotSubId = false;
var gotSubStartDate = false;
var gotPhoto = false;
var gotPhotoName = false;
foreach (var rev in revs)
{
var props = rev.UserProperties;
if (props != null)
{
if (!gotDevToken)
{
var devToken = Lookup<string>(props, "device_token");
if (devToken != Lookup<string>(mergedProps, "device_token"))
{
mergedProps["device_token"] = devToken;
gotDevToken = true;
}
}
if (!gotSubCancelDate)
{
var subCancelDate = Lookup<string>(props, "subscription_cancel_date");
if (subCancelDate != Lookup<string>(mergedProps, "subscription_cancel_date"))
{
mergedProps["subscription_cancel_date"] = subCancelDate;
gotSubCancelDate = true;
}
}
if (!gotPlanId)
{
var planId = Lookup<string>(props, "current_planId");
if (planId != Lookup<string>(mergedProps, "current_planId"))
{
mergedProps["current_planId"] = planId;
gotPlanId = true;
}
}
if (!gotSubName)
{
var currentSub = Lookup<string>(props, "current_subscription");
if (currentSub != Lookup<string>(mergedProps, "current_subscription"))
{
mergedProps["current_subscription"] = currentSub;
gotSubName = true;
}
}
if (!gotCancelled)
{
var hasCancelled = LookupNullable<bool>(props, "has_cancelled_subscription");
if (hasCancelled != LookupNullable<bool>(mergedProps, "has_cancelled_subscription"))
{
mergedProps["has_cancelled_subscription"] = hasCancelled;
gotCancelled = true;
}
}
if (!gotHasCard)
{
var hasCard = LookupNullable<bool>(props, "has_card");
if (hasCard != LookupNullable<bool>(mergedProps, "has_card"))
{
mergedProps["has_card"] = hasCard;
gotHasCard = true;
}
}
if (!gotSubscribed)
{
var hasSubscribed = LookupNullable<bool>(props, "subscribed");
if (hasSubscribed != LookupNullable<bool>(mergedProps, "subscribed"))
{
mergedProps["subscribed"] = hasSubscribed;
gotSubscribed = true;
}
}
if (!gotSubCreateDate)
{
var createDate = Lookup<string>(props, "subscription_created_at");
if (createDate != Lookup<string>(mergedProps, "subscription_created_at"))
{
mergedProps["subscription_created_at"] = createDate;
gotSubCreateDate = true;
}
}
if (!gotExpireDate)
{
var expDate = Lookup<string>(props, "subscription_expire_at");
if (expDate != Lookup<string>(mergedProps, "subscription_expire_at"))
{
mergedProps["subscription_expire_at"] = expDate;
gotExpireDate = true;
}
}
if (!gotSubId)
{
var subId = Lookup<string>(props, "subscription_id");
if (subId != Lookup<string>(mergedProps, "subscription_id"))
{
mergedProps["subscription_id"] = subId;
gotSubId = true;
}
}
if (!gotSubStartDate)
{
var subStartDate = Lookup<string>(props, "subscription_start_date");
if (subStartDate != Lookup<string>(mergedProps, "subscription_start_date"))
{
mergedProps["subscription_start_date"] = subStartDate;
gotSubStartDate = true;
}
}
if (!gotPhoto)
{
var photo = Lookup<string>(props, "photo");
if (photo != Lookup<string>(mergedProps, "photo"))
{
mergedProps["photo"] = photo;
gotPhoto = true;
}
}
if (!gotPhotoName)
{
var photoName = Lookup<string>(props, "photo_name");
if (photoName != Lookup<string>(mergedProps, "photo_name"))
{
mergedProps["photo_name"] = photoName;
gotPhotoName = true;
}
}
if (gotDevToken && gotSubCancelDate && gotPlanId && gotSubName && gotCancelled
&& gotHasCard && gotSubscribed && gotSubCreateDate && gotExpireDate &&
gotSubId && gotSubStartDate && gotPhoto && gotPhotoName)
{
break;
}
}
}
return mergedProps;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment