Skip to content

Commit 408d01a

Browse files
committed
Introduced new GetContentTypeDescriptor() method
On the surface, the new `GetContentTypeDescriptor()` appears to just be a convenience method for checking the `GetContentTypeDescriptors() to determine if it contains the `ContentTypeDescriptor` associated with the current `Topic` and, if so, returning it. The `GetContentTypeDescriptor()` method does a lot more than this, however. If the `ContentTypeDescriptor` _cannot_ be found, then it attempts to locate the `Root:Configuration:ContentTypes` topic within the in-memory topic graph using the new `GetTopicByUniqueKey()` extension method (f2cb109). If found, it will then merge that tree with the `GetContentTypeDescriptors()` cache by using the new overload (7a5a243). In this way, it is able to fall back from persisted `ContentTypeDescriptor`s loaded from the database to potentially rely on new—but not yet persisted—`ContentTypeDescriptor`s available in the current graph. As part of this, the new `GetContentTypeDescriptor()` method is used for the content type lookups in the local `GetAttributes()` and `GetUnmatchedAttributes()` methods, which are in turn used by the concrete `Save()` implementation. This provides a reactive solution for the discovering in-memory `ContentTypeDescriptor` on `Save()` (#18). In practice, we'll generally prefer a proactive solution by updating these as `ContentTypeDescriptor`s when they're saved, instead of discovering them only when `Save()` is unable to find them. That will be addressed in a future commit. For now, however, this provides a fallback implementation, and will be necessary for supporting more complex scenarios such as bootstrapping the database, or otherwise importing complex topic graphs using e.g. the **OnTopic Data Exchange** library. Includes two unit tests for validating the functionality.
1 parent 7a5a243 commit 408d01a

3 files changed

Lines changed: 90 additions & 3 deletions

File tree

OnTopic.TestDoubles/StubTopicRepository.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ public IEnumerable<AttributeValue> GetAttributesProxy(Topic topic, bool? isExten
184184
public ContentTypeDescriptorCollection GetContentTypeDescriptorsProxy(ContentTypeDescriptor topicGraph) =>
185185
base.GetContentTypeDescriptors(topicGraph);
186186

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+
187194
/*==========================================================================================================================
188195
| METHOD: CREATE FAKE DATA
189196
\-------------------------------------------------------------------------------------------------------------------------*/

OnTopic.Tests/TopicRepositoryBaseTest.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,5 +168,37 @@ public void GetContentTypeDescriptors_WithTopicGraph_ReturnsMergedContentTypes()
168168

169169
}
170170

171+
/*==========================================================================================================================
172+
| TEST: GET CONTENT TYPE DESCRIPTOR: GET VALID CONTENT TYPE: RETURNS CONTENT TYPE
173+
\-------------------------------------------------------------------------------------------------------------------------*/
174+
/// <summary>
175+
/// Attempts to retrieve a specific <see cref="ContentTypeDescriptor"/> by its <see cref="Topic.Key"/>.
176+
/// </summary>
177+
[TestMethod]
178+
public void GetContentTypeDescriptor_GetValidContentType_ReturnsContentType() {
179+
180+
var topic = TopicFactory.Create("Test", "Page");
181+
var contentType = _topicRepository.GetContentTypeDescriptorProxy(topic);
182+
183+
Assert.IsNotNull(contentType);
184+
185+
}
186+
187+
/*==========================================================================================================================
188+
| TEST: GET CONTENT TYPE DESCRIPTOR: GET INVALID CONTENT TYPE: RETURNS NULL
189+
\-------------------------------------------------------------------------------------------------------------------------*/
190+
/// <summary>
191+
/// Attempts to retrieve an invalid <see cref="ContentTypeDescriptor"/>.
192+
/// </summary>
193+
[TestMethod]
194+
public void GetContentTypeDescriptor_GetInvalidContentType_ReturnsNull() {
195+
196+
var topic = TopicFactory.Create("Test", "InvalidContentType");
197+
var contentType = _topicRepository.GetContentTypeDescriptorProxy(topic);
198+
199+
Assert.IsNull(contentType);
200+
201+
}
202+
171203
} //Class
172204
} //Namespace

OnTopic/Repositories/TopicRepositoryBase.cs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,54 @@ topic is ContentTypeDescriptor contentTypeDescriptor &&
139139

140140
}
141141

142+
/*==========================================================================================================================
143+
| GET CONTENT TYPE DESCRIPTOR
144+
\-------------------------------------------------------------------------------------------------------------------------*/
145+
/// <summary>
146+
/// Attempts to identify the <see cref="ContentTypeDescriptor"/> for the provided <paramref name="sourceTopic"/>.
147+
/// </summary>
148+
/// <remarks>
149+
/// The <see cref="GetContentTypeDescriptor(Topic)"/> method will attempt to get the <see cref="ContentTypeDescriptor"/>
150+
/// from the <see cref="GetContentTypeDescriptors()"/> method using the <paramref name="sourceTopic"/>'s <see
151+
/// cref="Topic.ContentType"/>. If that can't be found, however, then it will instead look in the <paramref
152+
/// name="sourceTopic"/>'s topic graph to see if the <see cref="ContentTypeDescriptor"/> can be found there. This is
153+
/// useful for cases where new topic graphs are being imported and a new <see cref="Topic"/> references a new <see
154+
/// cref="ContentTypeDescriptor"/> prior to it having been saved. In this case, that new version will be added to the
155+
/// locally cached collection used by <see cref="GetContentTypeDescriptors()"/>.
156+
/// </remarks>
157+
/// <param name="sourceTopic"></param>
158+
/// <returns></returns>
159+
protected ContentTypeDescriptor? GetContentTypeDescriptor(Topic sourceTopic) {
160+
/*------------------------------------------------------------------------------------------------------------------------
161+
| Validate parameters
162+
\-----------------------------------------------------------------------------------------------------------------------*/
163+
Contract.Requires(sourceTopic, nameof(sourceTopic));
164+
165+
/*------------------------------------------------------------------------------------------------------------------------
166+
| Retrieve content type
167+
\-----------------------------------------------------------------------------------------------------------------------*/
168+
var contentType = sourceTopic.ContentType;
169+
var contentTypes = GetContentTypeDescriptors();
170+
var contentTypeDescriptor = contentTypes.Contains(contentType)? contentTypes[contentType] : null;
171+
172+
if (contentTypeDescriptor != null) {
173+
return contentTypeDescriptor;
174+
}
175+
176+
/*------------------------------------------------------------------------------------------------------------------------
177+
| Retrieve content type
178+
\-----------------------------------------------------------------------------------------------------------------------*/
179+
if (
180+
sourceTopic.GetByUniqueKey("Root:Configuration:ContentTypes") is ContentTypeDescriptor sourceContentTypes &&
181+
!contentTypes.Contains(sourceContentTypes)
182+
) {
183+
contentTypes = GetContentTypeDescriptors(sourceContentTypes);
184+
}
185+
186+
return contentTypes.Contains(contentType)? contentTypes[contentType] : null;
187+
188+
}
189+
142190
/*==========================================================================================================================
143191
| METHOD: LOAD
144192
\-------------------------------------------------------------------------------------------------------------------------*/
@@ -383,7 +431,7 @@ protected IEnumerable<AttributeValue> GetAttributes(Topic topic, bool? isExtende
383431
/*------------------------------------------------------------------------------------------------------------------------
384432
| Get associated content type descriptor
385433
\-----------------------------------------------------------------------------------------------------------------------*/
386-
var contentType = GetContentTypeDescriptors()[topic.Attributes.GetValue("ContentType", "Page")?? "Page"];
434+
var contentType = GetContentTypeDescriptor(topic);
387435

388436
Contract.Assume(
389437
contentType,
@@ -432,11 +480,11 @@ protected IEnumerable<AttributeDescriptor> GetUnmatchedAttributes(Topic topic) {
432480
/*------------------------------------------------------------------------------------------------------------------------
433481
| Get associated content type descriptor
434482
\-----------------------------------------------------------------------------------------------------------------------*/
435-
var contentType = GetContentTypeDescriptors()[topic.Attributes.GetValue("ContentType", "Page")?? "Page"];
483+
var contentType = GetContentTypeDescriptor(topic);
436484

437485
Contract.Assume(
438486
contentType,
439-
"The Topics repository or database does not contain a ContentTypeDescriptor for the Page content type."
487+
$"The Topics repository or database does not contain a ContentTypeDescriptor for the {topic.ContentType} content type."
440488
);
441489

442490
/*------------------------------------------------------------------------------------------------------------------------

0 commit comments

Comments
 (0)