Skip to content

Commit 2151a08

Browse files
committed
Support deleting arbitrary attributes
Arbitrary attributes represent a bit of a challenge when it comes to deleting indexed attributes. These deletions are currently handled based on the output of `GetUnmatchedAttributes()` in the `TopicRepositoryBase`. This method returns an `IEnumerable<AttributeDescriptor>`, as it's normally looking for `ContentTypeDescriptor.AttributeDescriptors` that don't correspond to any `AttributeValue`s on the current `Topic`. Arbitrary attributes, however, don't have a corresponding `AttributeDescriptor` by definition (that's what makes them arbitrary). To mitigate this, while maintaining backward compatibility with `GetUnmatchedAttributes()`, we need to introduce a small hack. The `GetUnmatchedAttributes()` will now also look for arbitrary attributes—i.e., attributes without a corresponding `AttributeDescriptor`—whose value is either `null` or empty, and it will include them in its results alongside other types of unmatched attributes. It will do this by constructing an _ad hoc_ `AttribtueDescriptor` (or, more specifically, a `TextAttribute`). This allows it to relay this finding to downstream callers. The upshot of this is that `Save()` will not be able to delete arbitrary attribute values—i.e., arbitrary attributes that previously had a value, but then had it deleted. This prevents a scenario where, otherwise, arbitrary values could be saved (c3c01ef) and read, but couldn't be deleted, thus lingering in the database, and potentially polluting the application data since they'll show back up after the application resets. As part of this, I've introduced a new unit test to validate the core functionality. This supports Programmatic Support for Arbitrary Attributes (#19)
1 parent c3c01ef commit 2151a08

2 files changed

Lines changed: 45 additions & 2 deletions

File tree

OnTopic.Tests/TopicRepositoryBaseTest.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,34 @@ public void GetUnmatchedAttributes_ReturnsAttributes() {
169169

170170
}
171171

172+
/*==========================================================================================================================
173+
| TEST: GET UNMATCHED ATTRIBUTES: EMPTY ARBITRARY ATTRIBUTES: RETURNS ATTRIBUTES
174+
\-------------------------------------------------------------------------------------------------------------------------*/
175+
/// <summary>
176+
/// Using <see cref="TopicRepositoryBase.GetUnmatchedAttributes(Topic)"/>, ensures that any attributes that exist on the
177+
/// <see cref="Topic"/> but not the <see cref="ContentTypeDescriptor"/> <i>and</i> are either <c>null</c> or empty are
178+
/// returned. This ensures that arbitrary attributes can be deleted programmatically, instead of lingering as orphans in
179+
/// the database.
180+
/// </summary>
181+
[TestMethod]
182+
public void GetUnmatchedAttributes_EmptyArbitraryAttributes_ReturnsAttributes() {
183+
184+
var topic = TopicFactory.Create("Test", "ContentTypeDescriptor", 1);
185+
186+
topic.Attributes.SetValue("ArbitraryAttribute", "Value");
187+
topic.Attributes.SetValue("ArbitraryAttribute", "");
188+
topic.Attributes.SetValue("AnotherArbitraryAttribute", "Value");
189+
topic.Attributes.SetValue("YetAnotherArbitraryAttribute", "Value");
190+
topic.Attributes.SetValue("YetAnotherArbitraryAttribute", null);
191+
192+
var attributes = _topicRepository.GetUnmatchedAttributesProxy(topic);
193+
194+
Assert.IsTrue(attributes.Any(a => a.Key.Equals("ArbitraryAttribute", StringComparison.InvariantCulture)));
195+
Assert.IsTrue(attributes.Any(a => a.Key.Equals("YetAnotherArbitraryAttribute", StringComparison.InvariantCulture)));
196+
Assert.IsFalse(attributes.Any(a => a.Key.Equals("AnotherArbitraryAttribute", StringComparison.InvariantCulture)));
197+
198+
}
199+
172200
/*==========================================================================================================================
173201
| TEST: GET CONTENT TYPE DESCRIPTORS: RETURNS CONTENT TYPES
174202
\-------------------------------------------------------------------------------------------------------------------------*/

OnTopic/Repositories/TopicRepositoryBase.cs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -541,9 +541,9 @@ protected IEnumerable<AttributeDescriptor> GetUnmatchedAttributes(Topic topic) {
541541
);
542542

543543
/*------------------------------------------------------------------------------------------------------------------------
544-
| Get unmatched attributes
544+
| Get unmatched attribute descriptors
545545
\-----------------------------------------------------------------------------------------------------------------------*/
546-
var attributes = new List<AttributeDescriptor>();
546+
var attributes = new TopicCollection<AttributeDescriptor>();
547547

548548
foreach (var attribute in contentType.AttributeDescriptors) {
549549

@@ -574,6 +574,21 @@ protected IEnumerable<AttributeDescriptor> GetUnmatchedAttributes(Topic topic) {
574574

575575
}
576576

577+
/*------------------------------------------------------------------------------------------------------------------------
578+
| Get arbitrary attributes
579+
>-------------------------------------------------------------------------------------------------------------------------
580+
| ###HACK JJC20200502: Arbitrary attributes are those that don't map back to the scheme. These aren't picked up by the
581+
| AttributeDescriptors check above. This means there's no way to programmatically delete arbitrary (or orphaned)
582+
| attributes. To mitigate this, any null or empty attribute values should be included. By definition, though, arbitrary
583+
| attributes don't have corresponding AttributeDescriptors. To mitigate this, an ad hoc AttributeDescriptor object will be
584+
| created for each empty AttributeDescriptor.
585+
\-----------------------------------------------------------------------------------------------------------------------*/
586+
foreach (var attribute in topic.Attributes.Where(a => String.IsNullOrEmpty(a.Value))) {
587+
if (!attributes.Contains(attribute.Key)) {
588+
attributes.Add((TextAttribute)TopicFactory.Create(attribute.Key, "TextAttribute"));
589+
}
590+
}
591+
577592
/*------------------------------------------------------------------------------------------------------------------------
578593
| Return values
579594
\-----------------------------------------------------------------------------------------------------------------------*/

0 commit comments

Comments
 (0)