Skip to content

Commit fb3366e

Browse files
committed
Merge branch 'feature/GetContentTypeDescriptors-Caching' into develop
Previously, the oroborus configuration—which allows the OnTopic Library to be configured using topics within the OnTopic Library—was optimized for read-only states. A number of changes to the configuration would not take effect until the application had been reset, and the cache cleared. As part of this, it also wasn't well-suited for programmatically persisting topic graphs which included new configuration elements, or bootstrapping a new database, since that would frequently introduce order-of-operations issues—e.g., it can't save a topic of a given content type until the associated `ContentTypeDescriptor` was persisted. So, for example, given a new database, how do you save the `ContentTypeDescriptor` content type without already having the `ContentTypeDescriptor` content type saved? These issues are largely mitigated by this update, which automatically updates the appropriate caches for the `ContentTypeDescriptor`s (via `TopicRepositoryBase.GetContentTypeDescriptors()`) and `AttributeDescriptor`s (via `ContentTypeDescriptor.AttributeDescriptors`) whenever `ContentTypeDescriptor`s or `AttributeDescriptor`s are `Save()`d, `Delete()`d, or `Move()`d. Further, for complex topic graphs, fallbacks were put in place to automatically search for updates to the `ContentTypeDescriptor`(s) or `AttributeDescriptor`(s) via the in-memory topic graph if they're not found in the currently cached version—and, if they're found, to update the cached versions with the new objects. This provides significantly more flexibility, thus permitting both real time configuration (without application resets) as well as programmatically updating entire topic graphs (as needed for the **OnTopic Data Exchange** library). The bootstrapping problem isn't entirely solved—that requires some additional considerations—but this lays a solid foundation for that effort. The update resolves the following feature enhancements and bug fixes: - Update content type cache when adding or removing content types (#16) - Update attribute descriptors when adding or removing an attribute (#17) - Discover in-memory ContentTypeDescriptor, AttributeDescriptor on Save() (#18)
2 parents d18984d + 2f8e0b5 commit fb3366e

File tree

7 files changed

+598
-63
lines changed

7 files changed

+598
-63
lines changed

OnTopic.TestDoubles/StubTopicRepository.cs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
| Project Topics Library
55
\=============================================================================================================================*/
66
using System;
7+
using System.Collections.Generic;
78
using System.Globalization;
89
using OnTopic.Attributes;
910
using OnTopic.Internal.Diagnostics;
@@ -163,6 +164,33 @@ public override void Move(Topic topic, Topic target, Topic? sibling) {
163164
/// <inheritdoc />
164165
public override void Delete(Topic topic, bool isRecursive = false) => base.Delete(topic, isRecursive);
165166

167+
/*==========================================================================================================================
168+
| METHOD: GET ATTRIBUTES (PROXY)
169+
\-------------------------------------------------------------------------------------------------------------------------*/
170+
/// <inheritdoc cref="TopicRepositoryBase.GetAttributes(Topic, Boolean?, Boolean?)" />
171+
public IEnumerable<AttributeValue> GetAttributesProxy(Topic topic, bool? isExtendedAttribute, bool? isDirty = null) =>
172+
base.GetAttributes(topic, isExtendedAttribute, isDirty);
173+
174+
/*==========================================================================================================================
175+
| METHOD: GET UNMATCHED ATTRIBUTES (PROXY)
176+
\-------------------------------------------------------------------------------------------------------------------------*/
177+
/// <inheritdoc cref="TopicRepositoryBase.GetUnmatchedAttributes(Topic)" />
178+
public IEnumerable<AttributeDescriptor> GetUnmatchedAttributesProxy(Topic topic) => base.GetUnmatchedAttributes(topic);
179+
180+
/*==========================================================================================================================
181+
| METHOD: GET CONTENT TYPE DESCRIPTORS (PROXY)
182+
\-------------------------------------------------------------------------------------------------------------------------*/
183+
/// <inheritdoc cref="TopicRepositoryBase.GetContentTypeDescriptors(ContentTypeDescriptor)" />
184+
public ContentTypeDescriptorCollection GetContentTypeDescriptorsProxy(ContentTypeDescriptor topicGraph) =>
185+
base.GetContentTypeDescriptors(topicGraph);
186+
187+
/*==========================================================================================================================
188+
| METHOD: GET CONTENT TYPE DESCRIPTOR (PROXY)
189+
\-------------------------------------------------------------------------------------------------------------------------*/
190+
/// <inheritdoc cref="TopicRepositoryBase.GetContentTypeDescriptor(Topic)" />
191+
public ContentTypeDescriptor? GetContentTypeDescriptorProxy(Topic sourceTopic) =>
192+
base.GetContentTypeDescriptor(sourceTopic);
193+
166194
/*==========================================================================================================================
167195
| METHOD: CREATE FAKE DATA
168196
\-------------------------------------------------------------------------------------------------------------------------*/
@@ -183,10 +211,10 @@ private Topic CreateFakeData() {
183211
var configuration = TopicFactory.Create("Configuration", "Container", rootTopic);
184212
var contentTypes = TopicFactory.Create("ContentTypes", "ContentTypeDescriptor", configuration);
185213

186-
addAttribute(contentTypes, "Key", "TextAttribute", true);
187-
addAttribute(contentTypes, "ContentType", "TextAttribute", true);
188-
addAttribute(contentTypes, "Title", "TextAttribute", true);
189-
addAttribute(contentTypes, "TopicId", "TopicReferenceAttribute");
214+
addAttribute(contentTypes, "Key", "TextAttribute", false, true);
215+
addAttribute(contentTypes, "ContentType", "TextAttribute", false, true);
216+
addAttribute(contentTypes, "Title", "TextAttribute", true, true);
217+
addAttribute(contentTypes, "TopicId", "TopicReferenceAttribute", false);
190218

191219
var contentTypeDescriptor = TopicFactory.Create("ContentTypeDescriptor", "ContentTypeDescriptor", contentTypes);
192220

@@ -200,8 +228,8 @@ private Topic CreateFakeData() {
200228

201229
var attributeDescriptor = (ContentTypeDescriptor)TopicFactory.Create("AttributeDescriptor", "ContentTypeDescriptor", contentTypes);
202230

203-
addAttribute(attributeDescriptor, "DefaultValue", "TextAttribute", true);
204-
addAttribute(attributeDescriptor, "IsRequired", "BooleanAttribute", true);
231+
addAttribute(attributeDescriptor, "DefaultValue", "TextAttribute", false, true);
232+
addAttribute(attributeDescriptor, "IsRequired", "TextAttribute", false, true);
205233

206234
TopicFactory.Create("BooleanAttribute", "ContentTypeDescriptor", attributeDescriptor);
207235
TopicFactory.Create("NestedTopicListAttribute", "ContentTypeDescriptor", attributeDescriptor);
@@ -214,29 +242,36 @@ private Topic CreateFakeData() {
214242

215243
addAttribute(pageContentType, "MetaTitle");
216244
addAttribute(pageContentType, "MetaDescription");
217-
addAttribute(pageContentType, "IsHidden");
218-
addAttribute(pageContentType, "TopicReference", "TopicReferenceAttribute");
245+
addAttribute(pageContentType, "IsHidden", "TextAttribute", false);
246+
addAttribute(pageContentType, "TopicReference", "TopicReferenceAttribute", false);
219247

220248
pageContentType.Relationships.SetTopic("ContentTypes", pageContentType);
221249
pageContentType.Relationships.SetTopic("ContentTypes", contentTypeDescriptor);
222250

223251
var contactContentType = TopicFactory.Create("Contact", "ContentTypeDescriptor", contentTypes);
224252

225-
addAttribute(contactContentType, "Name");
226-
addAttribute(contactContentType, "AlternateEmail");
227-
addAttribute(contactContentType, "BillingContactEmail");
253+
addAttribute(contactContentType, "Name", isExtended: false);
254+
addAttribute(contactContentType, "AlternateEmail", isExtended: false);
255+
addAttribute(contactContentType, "BillingContactEmail", isExtended: false);
228256

229257
/*------------------------------------------------------------------------------------------------------------------------
230258
| Local addAttribute() helper function
231259
\-----------------------------------------------------------------------------------------------------------------------*/
232-
AttributeDescriptor addAttribute(Topic contentType, string attributeKey, string editorType = "TextAttribute", bool isRequired = false) {
260+
AttributeDescriptor addAttribute(
261+
Topic contentType,
262+
string attributeKey,
263+
string editorType = "TextAttribute",
264+
bool isExtended = true,
265+
bool isRequired = false
266+
) {
233267
var container = contentType.Children.GetTopic("Attributes");
234268
if (container == null) {
235269
container = TopicFactory.Create("Attributes", "List", contentType);
236270
container.Attributes.SetBoolean("IsHidden", true);
237271
}
238272
var attribute = (AttributeDescriptor)TopicFactory.Create(attributeKey, editorType, currentAttributeId++, container);
239273
attribute.IsRequired = isRequired;
274+
attribute.IsExtendedAttribute = isExtended;
240275
return attribute;
241276
}
242277

OnTopic.Tests/ITopicRepositoryTest.cs

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,14 @@
77
using System.Linq;
88
using OnTopic.Collections;
99
using OnTopic.Data.Caching;
10-
using OnTopic.Metadata;
1110
using OnTopic.Repositories;
1211
using OnTopic.TestDoubles;
1312
using Microsoft.VisualStudio.TestTools.UnitTesting;
1413

1514
namespace OnTopic.Tests {
1615

1716
/*============================================================================================================================
18-
| CLASS: ATTRIBUTE VALUE COLLECTION TEST
17+
| CLASS: TOPIC REPOSITORY TEST
1918
\---------------------------------------------------------------------------------------------------------------------------*/
2019
/// <summary>
2120
/// Provides unit tests for the <see cref="AttributeValueCollection"/> class.
@@ -30,7 +29,7 @@ public class ITopicRepositoryTest {
3029
/*==========================================================================================================================
3130
| PRIVATE VARIABLES
3231
\-------------------------------------------------------------------------------------------------------------------------*/
33-
readonly ITopicRepository _topicRepository;
32+
readonly ITopicRepository _topicRepository;
3433

3534
/*==========================================================================================================================
3635
| CONSTRUCTOR
@@ -225,24 +224,5 @@ public void Delete_Topic_Removed() {
225224

226225
}
227226

228-
/*==========================================================================================================================
229-
| TEST: GET CONTENT TYPE DESCRIPTORS: RETURNS TOPICS
230-
\-------------------------------------------------------------------------------------------------------------------------*/
231-
/// <summary>
232-
/// Retrieves a list of <see cref="ContentTypeDescriptor"/>s from the <see cref="ITopicRepository"/> and ensures that
233-
/// the expected number (2) are present.
234-
/// </summary>
235-
[TestMethod]
236-
public void GetContentTypeDescriptors_ReturnsTopics() {
237-
238-
var contentTypes = _topicRepository.GetContentTypeDescriptors();
239-
240-
Assert.AreEqual<int>(15, contentTypes.Count);
241-
Assert.IsNotNull(contentTypes.GetTopic("ContentTypeDescriptor"));
242-
Assert.IsNotNull(contentTypes.GetTopic("Page"));
243-
Assert.IsNotNull(contentTypes.GetTopic("LookupListItem"));
244-
245-
}
246-
247227
} //Class
248228
} //Namespace

0 commit comments

Comments
 (0)