Commit edd5bb27 authored by HankG's avatar HankG

Add ability to merge Persons and Persons Lists

parent a169e258
......@@ -54,6 +54,26 @@ namespace MySocialPortalLib.Model
&& SocialMediaSystemName == other.SocialMediaSystemName;
}
public SocialMediaAccountData Copy()
{
var newValue = new SocialMediaAccountData
{
Id = this.Id,
Active = this.Active,
ProfileId = this.ProfileId,
ProfilePhotoPath = this.ProfilePhotoPath,
ProfileUrl = this.ProfileUrl,
RealName = this.RealName,
SocialMediaSystemName = this.SocialMediaSystemName
};
foreach (var (k,v) in AdditionalProperties)
{
newValue.AdditionalProperties[k] = v;
}
return newValue;
}
protected bool Equals(SocialMediaAccountData other)
{
if (other == null)
......
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using MySocialPortalLib.Model;
namespace MySocialPortalLibTest.Util
{
public static class PersonDatabaseMergingUtils
{
public static (IList<Person> newPersons, IList<Person> mergedPersons, IList<Person> unchangedPersons) Merge(
IList<Person> list1,
IList<Person> list2)
{
var originalList1 = new List<Person>(list1);
var originalList2 = new List<Person>(list2);
var mergedPersons = new List<Person>();
var newPersons = new List<Person>();
var unchangedPerson = new List<Person>();
var list1Dictionary = originalList1.ToImmutableDictionary(p => p.Id, p => p, StringComparer.InvariantCulture);
var list2Dictionary = originalList2.ToImmutableDictionary(p => p.Id, p => p, StringComparer.InvariantCulture);
var commonIds = list1Dictionary.Keys.Intersect(list2Dictionary.Keys);
foreach (var id in commonIds)
{
var person1 = list1Dictionary[id];
var person2 = list2Dictionary[id];
originalList1.Remove(person1);
originalList2.Remove(person2);
person1.Merge(person2);
mergedPersons.Add(person1);
}
var socialNetworkNameDict1 = originalList1.ToSocialNetworkUsernameKeyedDictionary();
var socialNetworkNameDict2 = originalList2.ToSocialNetworkUsernameKeyedDictionary();
var commonNetworkIds = socialNetworkNameDict1.Keys.Intersect(socialNetworkNameDict2.Keys);
foreach (var networkId in commonNetworkIds)
{
var person1 = socialNetworkNameDict1[networkId];
var person2 = socialNetworkNameDict2[networkId];
originalList1.Remove(person1);
originalList2.Remove(person2);
person1.Merge(person2);
if (!mergedPersons.Contains(person1))
{
mergedPersons.Add(person1);
}
}
return (originalList2, mergedPersons, originalList1);
}
public static void Merge(this Person person1, Person person2)
{
person1.Emails.AddIfNew(person2.Emails);
person1.Addresses.AddIfNew(person2.Addresses);
person1.Websites.AddIfNew(person2.Websites);
person1.PhoneNumbers.AddIfNew(person2.PhoneNumbers);
person1.SocialMediaAccounts.AddIfNew(person2.SocialMediaAccounts);
foreach (var k in person2.AdditionalProperties.Keys)
{
person1.AdditionalProperties[k] = person2.AdditionalProperties[k];
}
}
public static void AddIfNew(this List<LabeledValue<string>> currentSet, LabeledValue<string> newValue)
{
var sameValue = currentSet.Find(v => v.Label == newValue.Label);
if (sameValue == null)
{
currentSet.Add(newValue);
return;
}
sameValue.Value = string.IsNullOrWhiteSpace(sameValue.Value) ? newValue.Value : sameValue.Value;
}
public static void AddIfNew(this List<LabeledValue<string>> currentSet, List<LabeledValue<string>> newValues)
{
newValues.ForEach(v => currentSet.AddIfNew(v));
}
public static void AddIfNew(this Dictionary<string, SocialMediaAccountData> currentSet,
Dictionary<string, SocialMediaAccountData> newValues)
{
foreach (var (key, value) in newValues)
{
if (currentSet.TryGetValue(key, out var smd))
{
smd.Merge(value);
continue;
}
currentSet.Add(key, value);
}
}
public static void Merge(this SocialMediaAccountData cv, SocialMediaAccountData nv,
bool flushAdditionalProps = false)
{
cv.Active = nv.Active;
if (!string.IsNullOrEmpty(nv.ProfileId))
{
cv.ProfileId = nv.ProfileId;
}
if (!string.IsNullOrEmpty(nv.ProfileUrl))
{
cv.ProfileUrl = nv.ProfileUrl;
}
if (!string.IsNullOrEmpty(nv.RealName))
{
cv.RealName = nv.RealName;
}
if (!string.IsNullOrEmpty(nv.ProfilePhotoPath))
{
cv.ProfilePhotoPath = nv.ProfilePhotoPath;
}
if (!string.IsNullOrEmpty(nv.SocialMediaSystemName))
{
cv.SocialMediaSystemName = nv.SocialMediaSystemName;
}
if (flushAdditionalProps)
{
cv.AdditionalProperties.Clear();
}
foreach (var (k,v) in nv.AdditionalProperties)
{
cv.AdditionalProperties[k] = v;
}
}
private static IDictionary<string, Person> ToSocialNetworkUsernameKeyedDictionary(this IEnumerable<Person> persons)
{
var results = new Dictionary<string, Person>();
foreach (var p in persons)
{
foreach (var (network, smd) in p.SocialMediaAccounts)
{
if (string.IsNullOrWhiteSpace(network) || string.IsNullOrWhiteSpace(smd.ProfileId))
{
continue;
}
var key = $"{network}{smd.ProfileId}";
results[key] = p;
}
}
return results;
}
}
}
\ No newline at end of file
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.Json;
......@@ -18,6 +19,29 @@ namespace MySocialPortalLibTest.Model
Assert.True(d.AllEquals(fromJson));
}
[Fact]
public void TestCopy()
{
var emptySma = new SocialMediaAccountData();
Assert.True(emptySma.AllEquals(emptySma.Copy()));
var sma = new SocialMediaAccountData
{
Active = false,
ProfileId = Guid.NewGuid().ToString(),
ProfileUrl = Guid.NewGuid().ToString(),
RealName = Guid.NewGuid().ToString(),
ProfilePhotoPath = Guid.NewGuid().ToString(),
SocialMediaSystemName = Guid.NewGuid().ToString()
};
sma.AdditionalProperties[Guid.NewGuid().ToString()] = Guid.NewGuid().ToString();
sma.AdditionalProperties[Guid.NewGuid().ToString()] = Guid.NewGuid().ToString();
var smaCopy = sma.Copy();
Assert.True(sma.AllEquals(smaCopy));
sma.AdditionalProperties.Clear();
Assert.False(sma.AllEquals(smaCopy));
}
}
public class SocialMediaAccountDataDataGenerator : IEnumerable<object[]>
......
using System;
using System.Collections.Generic;
using System.Linq;
using MySocialPortalLib.Model;
using Xunit;
namespace MySocialPortalLibTest.Util
{
public class PersonDbMergingUtilsTest
{
[Fact]
public void TestLabeledValueMergeSingle()
{
var values = new List<LabeledValue<string>>
{
new LabeledValue<string>("Label1", "Value1"),
new LabeledValue<string>("Label2", "Value2"),
};
var value3 = new LabeledValue<string>("Label3", "Value3");
values.AddIfNew(value3);
Assert.Equal(3, values.Count);
var newValue2 = new LabeledValue<string>("Label2", "NewValue2");
values.AddIfNew(newValue2);
Assert.Equal(3, values.Count);
Assert.False(newValue2.Equals(values[1]));
values[1].Value = "";
values.AddIfNew(newValue2);
Assert.Equal(3, values.Count);
Assert.True(newValue2.Equals(values[1]));
}
[Fact]
public void TestLabeledValueMergeMultiple()
{
var values1 = new List<LabeledValue<string>>
{
new LabeledValue<string>("Label1", "Value1"),
new LabeledValue<string>("Label2", "Value2"),
new LabeledValue<string>("Label3", "")
};
var values2 = new List<LabeledValue<string>>
{
new LabeledValue<string>("Label2", "NewValue2"),
new LabeledValue<string>("Label3", "NewValue3"),
new LabeledValue<string>("Label4", "NewValue4")
};
values1.AddIfNew(values2);
Assert.Equal(4, values1.Count);
Assert.Equal("Value2", values1[1].Value);
Assert.Equal("NewValue3", values1[2].Value);
}
[Fact]
public void TestSocialMediaAccountDataMerge()
{
var emptySma = new SocialMediaAccountData();
var fullSma = GenerateFullSocialMediaData();
var originalSma = fullSma.Copy();
fullSma.Merge(emptySma, false);
Assert.False(originalSma.AllEquals(fullSma));
fullSma.Active = originalSma.Active;
Assert.True(originalSma.AllEquals(fullSma));
emptySma.Merge(fullSma);
Assert.False(originalSma.AllEquals(emptySma));
emptySma.Id = fullSma.Id;
Assert.True(originalSma.AllEquals(emptySma));
var newKey = "Value1Key";
var fullSma2 = GenerateFullSocialMediaData();
fullSma.AdditionalProperties[newKey] = "Value1Fullsma1";
fullSma2.AdditionalProperties[newKey] = "Value1Fullsma2";
fullSma.Merge(fullSma2);
Assert.Equal(5, fullSma.AdditionalProperties.Count);
Assert.Equal("Value1Fullsma2", fullSma.AdditionalProperties[newKey]);
fullSma.Merge(fullSma2, true);
Assert.Equal(3, fullSma.AdditionalProperties.Count);
originalSma.AdditionalProperties.Keys.ToList().ForEach(k => Assert.DoesNotContain(k, fullSma.AdditionalProperties.Keys));
}
[Fact]
public void TestSocialMediaDictionaryMerge()
{
var socialDictionary1 = new Dictionary<string, SocialMediaAccountData>
{
{"Network1", new SocialMediaAccountData {SocialMediaSystemName = "Network1"}},
{"Network2", new SocialMediaAccountData {SocialMediaSystemName = "Network2"}}
};
var socialDictionary2 = new Dictionary<string, SocialMediaAccountData>
{
{"Network2", new SocialMediaAccountData {SocialMediaSystemName = "Network2"}},
{"Network3", new SocialMediaAccountData {SocialMediaSystemName = "Network3"}}
};
socialDictionary1.AddIfNew(socialDictionary2);
Assert.Equal(3, socialDictionary1.Count);
}
[Fact]
public void TestPersonsListMerge()
{
var personList1 = new List<Person>
{
new Person
{
Id = "1234",
Name = "Jane Smith",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network1", new SocialMediaAccountData()}
}
},
new Person
{
Name = "John Gooding",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network1", new SocialMediaAccountData{ProfileId = "johngooding", SocialMediaSystemName = "Network1"}},
{"Network3", new SocialMediaAccountData{ProfileId = "john_gooding", SocialMediaSystemName = "Network3"}}
}
},
new Person
{
Name = "Lisa Lopez",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network1", new SocialMediaAccountData{ProfileId = "lisalopez", SocialMediaSystemName = "Network1"}},
}
}
};
var personList2 = new List<Person>
{
new Person
{
Id = "1234",
Name = "Jane A. Smith",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network2", new SocialMediaAccountData()}
}
},
new Person
{
Name = "JohnG",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network1", new SocialMediaAccountData{ProfileId = "johngooding", SocialMediaSystemName = "Network1"}},
{"Network2", new SocialMediaAccountData{ProfileId = "johng", SocialMediaSystemName = "Network2"}},
{"Network3", new SocialMediaAccountData{ProfileId = "john_gooding", SocialMediaSystemName = "Network3"}}
}
},
new Person
{
Name = "Johnathan G. Gooding IV",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network3", new SocialMediaAccountData{ProfileId = "john_gooding", SocialMediaSystemName = "Network3"}},
{"Network4", new SocialMediaAccountData{ProfileId = "johng4", SocialMediaSystemName = "Network4"}}
}
},
new Person
{
Name = "Kathy Morningside",
SocialMediaAccounts = new Dictionary<string, SocialMediaAccountData>
{
{"Network1", new SocialMediaAccountData{ProfileId = "kathym", SocialMediaSystemName = "Network1"}},
}
}
};
var (newPeople, mergedPeople, unchangedPeople) = PersonDatabaseMergingUtils.Merge(personList1, personList2);
Assert.Equal(2, mergedPeople.Count);
Assert.Equal(personList1[0].Name, mergedPeople[0].Name);
Assert.Equal(2, mergedPeople[0].SocialMediaAccounts.Count);
Assert.Equal(personList1[1].Name, mergedPeople[1].Name);
Assert.Equal(4, mergedPeople[1].SocialMediaAccounts.Count);
Assert.Equal(1, newPeople.Count);
Assert.Equal(newPeople.First(), personList2.Last());
Assert.Equal(1, unchangedPeople.Count);
Assert.Equal(unchangedPeople.First(), personList1.Last());
}
private SocialMediaAccountData GenerateFullSocialMediaData()
{
var fullSma = new SocialMediaAccountData
{
Active = false,
ProfileId = Guid.NewGuid().ToString(),
ProfileUrl = Guid.NewGuid().ToString(),
RealName = Guid.NewGuid().ToString(),
ProfilePhotoPath = Guid.NewGuid().ToString(),
SocialMediaSystemName = Guid.NewGuid().ToString()
};
fullSma.AdditionalProperties[Guid.NewGuid().ToString()] = Guid.NewGuid().ToString();
fullSma.AdditionalProperties[Guid.NewGuid().ToString()] = Guid.NewGuid().ToString();
return fullSma;
}
}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment