public void ImportAsReplace_TopicDataWithRelationships_DeletesOrphanedRelationships() { var rootTopic = TopicFactory.Create("Root", "Container"); var topic = TopicFactory.Create("Test", "Container", rootTopic); var relatedTopic1 = TopicFactory.Create("Related1", "Container", rootTopic); var relatedTopic2 = TopicFactory.Create("Related2", "Container", rootTopic); var relatedTopic3 = TopicFactory.Create("Related3", "Container", rootTopic); var topicData = new TopicData() { Key = topic.Key, UniqueKey = topic.GetUniqueKey(), ContentType = topic.ContentType }; var relationshipData = new KeyValuesPair() { Key = "Related" }; topic.Relationships.SetValue("Related", relatedTopic1); topic.Relationships.SetValue("Related", relatedTopic2); topic.Relationships.SetValue("Cousin", relatedTopic3); topicData.Relationships.Add(relationshipData); relationshipData.Values.Add(relatedTopic1.GetUniqueKey()); topic.Import( topicData, new() { Strategy = ImportStrategy.Replace } ); Assert.AreEqual(relatedTopic1, topic.Relationships.GetValues("Related")?.FirstOrDefault()); Assert.AreEqual<int>(1, topic.Relationships.GetValues("Related").Count); Assert.AreEqual<int>(0, topic.Relationships.GetValues("Cousin").Count); }
public void Import_TopicDataWithRelationships_MaintainsExisting() { var rootTopic = TopicFactory.Create("Root", "Container"); var topic = TopicFactory.Create("Test", "Container", rootTopic); var relatedTopic1 = TopicFactory.Create("Related1", "Container", rootTopic); var relatedTopic2 = TopicFactory.Create("Related2", "Container", rootTopic); var topicData = new TopicData() { Key = topic.Key, UniqueKey = topic.GetUniqueKey(), ContentType = topic.ContentType }; var relationshipData = new KeyValuesPair() { Key = "Related" }; topic.Relationships.SetValue("Related", relatedTopic1); topicData.Relationships.Add(relationshipData); relationshipData.Values.Add(relatedTopic2.GetUniqueKey()); topic.Import(topicData); Assert.AreEqual(relatedTopic1, topic.Relationships.GetValues("Related")?.FirstOrDefault()); Assert.AreEqual(relatedTopic2, topic.Relationships.GetValues("Related")?.LastOrDefault()); }
public void Serialize_KeyValuesPair_ReturnsExpectedResults() { var keyValuesPair = new KeyValuesPair() { Key = "Test" }; keyValuesPair.Values.Add("Root:Web"); var expected = $"{{" + $"\"Key\":\"{keyValuesPair.Key}\"," + $"\"Values\":[\"Root:Web\"]" + $"}}"; var json = JsonSerializer.Serialize(keyValuesPair); Assert.AreEqual<string>(expected, json); }
public void Deserialize_RelationshipData_ReturnsExpectedResults() { var sourceData = new KeyValuesPair() { Key = "Test" }; sourceData.Values.Add("Root:Web"); var json = $"{{" + $"\"Key\":\"{sourceData.Key}\"," + $"\"Relationships\":[\"Root:Web\"]" + $"}}"; var keyValuesPair = JsonSerializer.Deserialize<KeyValuesPair>(json); Assert.AreEqual<string?>(sourceData.Key, keyValuesPair?.Key); Assert.AreEqual<int?>(sourceData.Values.Count, keyValuesPair?.Values.Count); Assert.AreEqual<string?>(sourceData.Values.FirstOrDefault(), keyValuesPair?.Values.FirstOrDefault()); }
/*========================================================================================================================== | EXPORT \-------------------------------------------------------------------------------------------------------------------------*/ /// <summary> /// Exports a <see cref="Topic"/> entity—and, potentially, its descendants—into a <see cref="TopicData"/> data transfer /// object. /// </summary> /// <param name="topic">The source <see cref="Topic"/> to operate off of.</param> /// <param name="options">An optional <see cref="ExportOptions"/> object to specify export settings.</param> public static TopicData Export(this Topic topic, [NotNull]ExportOptions? options = null) { /*------------------------------------------------------------------------------------------------------------------------ | Validate topic \-----------------------------------------------------------------------------------------------------------------------*/ Contract.Requires(topic, nameof(topic)); /*------------------------------------------------------------------------------------------------------------------------ | Establish default options \-----------------------------------------------------------------------------------------------------------------------*/ if (options is null) { options = new(); } options.ExportScope ??= topic.GetUniqueKey(); /*------------------------------------------------------------------------------------------------------------------------ | Set primary properties \-----------------------------------------------------------------------------------------------------------------------*/ var topicData = new TopicData { Key = topic.Key, UniqueKey = topic.GetUniqueKey(), ContentType = topic.ContentType }; /*------------------------------------------------------------------------------------------------------------------------ | Set attributes \-----------------------------------------------------------------------------------------------------------------------*/ var attributes = topic.Attributes.Where(a => !ReservedAttributeKeys.Any(r => r.Equals(a.Key, StringComparison.OrdinalIgnoreCase) ) ); foreach (var attribute in attributes) { var attributeValue = getAttributeValue(attribute); if (String.IsNullOrEmpty(attributeValue)) { continue; } topicData.Attributes.Add( new() { Key = attribute.Key, Value = attributeValue, LastModified = attribute.LastModified } ); } /*------------------------------------------------------------------------------------------------------------------------ | Set topic references \-----------------------------------------------------------------------------------------------------------------------*/ foreach (var reference in topic.References) { if ( !options.IncludeExternalAssociations && !(reference.Value?.GetUniqueKey().StartsWith(options.ExportScope, StringComparison.InvariantCultureIgnoreCase)?? true) ) { continue; } topicData.References.Add( new() { Key = reference.Key, Value = reference.Value?.GetUniqueKey(), LastModified = reference.LastModified } ); } /*------------------------------------------------------------------------------------------------------------------------ | Set relationships \-----------------------------------------------------------------------------------------------------------------------*/ foreach (var relationship in topic.Relationships) { var relationshipData = new KeyValuesPair() { Key = relationship.Key, }; foreach (var relatedTopic in relationship.Values) { if ( options.IncludeExternalAssociations || relatedTopic.GetUniqueKey().StartsWith(options.ExportScope, StringComparison.InvariantCultureIgnoreCase) ) { relationshipData.Values.Add(relatedTopic.GetUniqueKey()); } } if (relationshipData.Values.Count > 0) { topicData.Relationships.Add(relationshipData); } } /*------------------------------------------------------------------------------------------------------------------------ | Recurse over children \-----------------------------------------------------------------------------------------------------------------------*/ foreach (var childTopic in topic.Children) { if ( options.IncludeChildTopics || topic.ContentType is "List" || options.IncludeNestedTopics && childTopic.ContentType is "List" ) { topicData.Children.Add( childTopic.Export(options) ); } } /*------------------------------------------------------------------------------------------------------------------------ | Return topic \-----------------------------------------------------------------------------------------------------------------------*/ return topicData; /*------------------------------------------------------------------------------------------------------------------------ | Get attribute value \-----------------------------------------------------------------------------------------------------------------------*/ string? getAttributeValue(AttributeRecord attribute) => options.TranslateLegacyTopicReferences && attribute.Key.EndsWith("ID", StringComparison.InvariantCultureIgnoreCase)? GetUniqueKey(topic, attribute.Value, options) : attribute.Value; }
public void Deserialize_TopicGraph_ReturnsExpectedResults() { var lastModified = new DateTime(2021, 02, 16, 16, 06, 25); var sourceTopicData = new TopicData() { Key = "Test", UniqueKey = "Root:Test", ContentType = "Container" }; var sourceRelationshipData= new KeyValuesPair() { Key = "Test" }; var sourceAttributeData = new RecordData() { Key = "Test", LastModified = lastModified }; var sourceReferenceData = new RecordData() { Key = "Test", Value = "Root:Reference", LastModified = lastModified }; var sourceChildTopicData = new TopicData() { Key = "Child", UniqueKey = "Root:Test:Child", ContentType = "Container" }; sourceRelationshipData.Values.Add("Root:Web"); sourceTopicData.Relationships.Add(sourceRelationshipData); sourceTopicData.Attributes.Add(sourceAttributeData); sourceTopicData.Children.Add(sourceChildTopicData); var json = $"{{" + $"\"Key\":\"{sourceTopicData.Key}\"," + $"\"UniqueKey\":\"{sourceTopicData.UniqueKey}\"," + $"\"ContentType\":\"{sourceTopicData.ContentType}\"," + $"\"Attributes\":[" + $"{{" + $"\"Key\":\"{sourceAttributeData.Key}\"," + $"\"Value\":null," + $"\"LastModified\":\"{sourceAttributeData.LastModified:s}\"" + $"}}"+ $"]," + $"\"Relationships\":[" + $"{{" + $"\"Key\":\"{sourceRelationshipData.Key}\"," + $"\"Values\":[\"Root:Web\"]" + $"}}" + $"]," + $"\"References\":[" + $"{{" + $"\"Key\":\"{sourceReferenceData.Key}\"," + $"\"Value\":\"{sourceReferenceData.Value}\"," + $"\"LastModified\":\"{sourceReferenceData.LastModified:s}\"" + $"}}"+ $"]," + $"\"Children\":[" + $"{{" + $"\"Key\":\"{sourceChildTopicData.Key}\"," + $"\"UniqueKey\":\"{sourceChildTopicData.UniqueKey}\"," + $"\"ContentType\":\"{sourceChildTopicData.ContentType}\"," + $"\"Attributes\":[]," + $"\"Relationships\":[]," + $"\"Children\":[]" + $"}}" + $"]" + $"}}"; var topicData = JsonSerializer.Deserialize<TopicData>(json); var relationshipData = topicData?.Relationships.FirstOrDefault(); var referenceData = topicData?.References.FirstOrDefault(); var attributeData = topicData?.Attributes.FirstOrDefault(); var childTopicData = topicData?.Children.FirstOrDefault(); Assert.AreEqual<string?>(sourceTopicData.Key, topicData?.Key); Assert.AreEqual<string?>(sourceTopicData.UniqueKey, topicData?.UniqueKey); Assert.AreEqual<string?>(sourceTopicData.ContentType, topicData?.ContentType); Assert.AreEqual<int>(1, sourceTopicData.Relationships.Count); Assert.AreEqual<int>(1, sourceTopicData.Attributes.Count); Assert.AreEqual<int>(1, sourceTopicData.Children.Count); Assert.AreEqual<string?>(sourceRelationshipData.Key, relationshipData?.Key); Assert.AreEqual<int?>(sourceRelationshipData.Values.Count, relationshipData?.Values.Count); Assert.AreEqual<string?>(sourceRelationshipData.Values.FirstOrDefault(), relationshipData?.Values.FirstOrDefault()); Assert.AreEqual<string?>(sourceReferenceData.Key, referenceData?.Key); Assert.AreEqual<string?>(sourceReferenceData.Value, referenceData?.Value); Assert.AreEqual<DateTime?>(sourceReferenceData.LastModified, referenceData?.LastModified); Assert.AreEqual<string?>(sourceAttributeData.Key, attributeData?.Key); Assert.AreEqual<string?>(sourceAttributeData.Value, attributeData?.Value); Assert.AreEqual<DateTime?>(sourceAttributeData.LastModified, attributeData?.LastModified); Assert.AreEqual<string?>(sourceChildTopicData.Key, childTopicData?.Key); Assert.AreEqual<string?>(sourceChildTopicData.UniqueKey, childTopicData?.UniqueKey); Assert.AreEqual<string?>(sourceChildTopicData.ContentType, childTopicData?.ContentType); Assert.AreEqual<int>(0, sourceChildTopicData.Relationships.Count); Assert.AreEqual<int>(0, sourceChildTopicData.Children.Count); }
public void Serialize_TopicGraph_ReturnsExpectedResults() { var lastModified = new DateTime(2021, 02, 16, 16, 06, 25); var topicData = new TopicData() { Key = "Test", UniqueKey = "Root:Test", ContentType = "Container" }; var relationshipData = new KeyValuesPair() { Key = "Test" }; var referenceData = new RecordData() { Key = "Test", LastModified = lastModified }; var attributeData = new RecordData() { Key = "Test", LastModified = lastModified }; var childTopicData = new TopicData() { Key = "Child", UniqueKey = "Root:Test:Child", ContentType = "Container" }; relationshipData.Values.Add("Root:Web"); topicData.Relationships.Add(relationshipData); topicData.References.Add(referenceData); topicData.Attributes.Add(attributeData); topicData.Children.Add(childTopicData); var expected = $"{{" + $"\"Key\":\"{topicData.Key}\"," + $"\"UniqueKey\":\"{topicData.UniqueKey}\"," + $"\"ContentType\":\"{topicData.ContentType}\"," + $"\"Attributes\":[" + $"{{" + $"\"Key\":\"{attributeData.Key}\"," + $"\"LastModified\":\"{attributeData.LastModified:s}\"" + $"}}"+ $"]," + $"\"Relationships\":[" + $"{{" + $"\"Key\":\"{relationshipData.Key}\"," + $"\"Values\":[\"Root:Web\"]" + $"}}" + $"]," + $"\"References\":[" + $"{{" + $"\"Key\":\"{referenceData.Key}\"," + $"\"LastModified\":\"{referenceData.LastModified:s}\"" + $"}}"+ $"]," + $"\"Children\":[" + $"{{" + $"\"Key\":\"{childTopicData.Key}\"," + $"\"UniqueKey\":\"{childTopicData.UniqueKey}\"," + $"\"ContentType\":\"{childTopicData.ContentType}\"," + $"\"Attributes\":[]," + $"\"Relationships\":[]," + $"\"References\":[]," + $"\"Children\":[]" + $"}}" + $"]" + $"}}"; var json = JsonSerializer.Serialize(topicData, new() { IgnoreNullValues = true }); Assert.AreEqual<string>(expected, json); }