Skip to content

Instantly share code, notes, and snippets.

@mrcampbell
Last active July 19, 2017 18:27
Show Gist options
  • Save mrcampbell/5de70f5c004e28846af47bbd1f286f66 to your computer and use it in GitHub Desktop.
Save mrcampbell/5de70f5c004e28846af47bbd1f286f66 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
namespace SyncableTest
{
class MainClass
{
/// <summary>
/// A common starting place for the Server and Local Database. This is
/// what was the copy that both shared exactly before we went offline.
/// </summary>
public List<Region> baseList = new List<Region>() {
new Region() {
ID = Guid.NewGuid(),
Name="Region #1",
CreatedOn = new DateTimeOffset(DateTime.Now.AddDays(-20)),
UpdatedOn = new DateTimeOffset(DateTime.Now.AddDays(-20))},
new Region() {
ID = Guid.NewGuid(),
Name="Region #2",
CreatedOn = new DateTimeOffset(DateTime.Now.AddDays(-3)),
UpdatedOn = new DateTimeOffset(DateTime.Now.AddDays(-1))},
new Region() {
ID = Guid.NewGuid(),
Name="Region That Was Updated Locally",
CreatedOn = new DateTimeOffset(DateTime.Now.AddDays(-14)),
UpdatedOn = new DateTimeOffset(DateTime.Now.AddDays(-3))},
new Region() {
ID = Guid.NewGuid(),
Name="Region That Was Updated On The Server While We Were Offline",
CreatedOn = new DateTimeOffset(DateTime.Now.AddDays(-40)),
UpdatedOn = new DateTimeOffset(DateTime.Now.AddDays(-7))}
};
/// <summary>
/// Represents a REST call to the server. Objects are modified and
/// created to simulate changes on Server since going offline.
/// </summary>
/// <returns>The Objects Per the Server's Database</returns>
private List<Region> TestListFromServer()
{
List<Region> serverList = new List<Region>();
// copy base before modifying
foreach (Region r in baseList)
{
Region newR = new Region()
{
ID = r.ID,
Name = r.Name,
CreatedOn = r.CreatedOn,
UpdatedOn = r.UpdatedOn
};
serverList.Add(newR);
}
// simulate a server modification since we went offline
serverList.First(r => r.Name == "Region That Was Updated On The Server While We Were Offline")
.UpdatedOn = new DateTimeOffset(DateTime.Now.AddDays(-3));
// simulate an object being created on the server while we were offline
serverList.Add(
new Region()
{
ID = Guid.NewGuid(),
Name = "Region That Was Created While We Were Offline",
CreatedOn = new DateTimeOffset(DateTime.Now),
UpdatedOn = new DateTimeOffset(DateTime.Now)
}
);
return serverList;
}
/// <summary>
/// This represents a query from the local database. Objects are
/// modified and created to simulate changes Locally since going offline.
/// </summary>
/// <returns>The Objects Per the Local Database</returns>
private List<Region> TestListFromLocal()
{
List<Region> localList = new List<Region>();
// copy base before modifying
foreach (Region r in baseList)
{
Region newR = new Region()
{
ID = r.ID,
Name = r.Name,
CreatedOn = r.CreatedOn,
UpdatedOn = r.UpdatedOn
};
localList.Add(newR);
}
// simulate a local modification
localList.First(r => r.Name == "Region That Was Updated Locally")
.UpdatedOn = new DateTimeOffset(DateTime.Now.AddDays(-1));
DateTimeOffset createdOn = new DateTimeOffset(DateTime.Now.AddMinutes(-30));
localList.Add(
new Region()
{
ID = Guid.NewGuid(),
Name = "Region Created Locally",
CreatedOn = createdOn,
UpdatedOn = createdOn
}
);
return localList;
}
/// <summary>
/// Find and return all the objects that are in both lists, but has a
/// more recent UpdatedOn Date in the first list
/// </summary>
/// <param name="first">
/// List of Objects that might have objects that have been updated since last sync
/// </param>
/// <param name="second">
/// List of Objects that might have objects that are stale
/// </param>
private void GetObjectsToBeUpdatedInSecondListFromFirst(List<Region> first, List<Region> second)
{
// get the objects where ID's match, but the UpDatedOn's Don't.
List<Region> diff = first.Where(f => second.Any(s => f.ID == s.ID && f.UpdatedOn > s.UpdatedOn)).ToList();
foreach (Region x in diff)
{
Console.WriteLine(x);
}
}
/// <summary>
/// Find and return all the objects that are unique to the first list
/// (present in the first list, and not in the second list)
/// </summary>
/// <param name="first">
/// List of Objects that may have objects not in Second List
/// </param>
/// <param name="second">
/// List of Objects that may be missing objects found in First List
/// </param>
private void GetObjecstToBeCreatedInSecondListFromFirst(List<Region> first, List<Region> second)
{
// add the objecst where the ID is not found in the second list
List<Region> diff = first.Where(f => !second.Any(s => s.ID == f.ID)).ToList();
foreach (Region x in diff)
{
Console.WriteLine(x);
}
}
/// <summary>
/// This is the Heart of the sync function. This only displays the differences,
/// but in a real setting, it would also issue the commands to update locally and remotely
/// </summary>
private void SyncRegions()
{
List<Region> fromServer = TestListFromServer();
List<Region> fromLocal = TestListFromLocal();
Console.WriteLine("Base List");
foreach(Region r in baseList)
{
Console.WriteLine(r);
}
Console.WriteLine("\nObjects to be Updated on Server from Local");
GetObjectsToBeUpdatedInSecondListFromFirst(fromLocal, fromServer);
Console.WriteLine("\nObjects not on Server but on Local");
GetObjecstToBeCreatedInSecondListFromFirst(fromLocal, fromServer);
Console.WriteLine("\nObjects to be Updated on Local from Server");
GetObjectsToBeUpdatedInSecondListFromFirst(fromServer, fromLocal);
Console.WriteLine("\nObjects not on Local but on Server");
GetObjecstToBeCreatedInSecondListFromFirst(fromServer, fromLocal);
}
/// <summary>
/// A Syncable Version of the Region object found in Redlist.Entities.Core
/// </summary>
public class Region : SyncableObject
{
public string Name { get; set; }
public override string ToString()
{
return string.Format("[Region: \n ID={0}, \n Name={1}, \n CreatedOn={2}, \n UpdatedOn={3}]", ID, Name, CreatedOn, UpdatedOn);
}
}
// A basic, Syncable object
public abstract class SyncableObject
{
public Guid ID { get; set; }
public DateTimeOffset CreatedOn { get; set; }
public DateTimeOffset UpdatedOn { get; set; }
public override string ToString()
{
return string.Format("[SyncableObject: ID={0}, CreatedOn={1}, UpdatedOn={2}]", ID, CreatedOn, UpdatedOn);
}
}
/// <summary>
/// The entry point of the program, where the program control starts and ends.
/// </summary>
/// <param name="args">The command-line arguments.</param>
public static void Main(string[] args)
{
MainClass main = new MainClass();
main.SyncRegions();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment