Skip to content

Commit a3d4798

Browse files
committed
Add IsExtendedAttributeMismatch() logic into GetAttributes()
Added a private helper method, `IsExtendedAttributeMismatch()`, to `TopicRepositoryBase`, which will detect a mismatch between where an existing `AttributeValue` _has been_ saved, and where it _should be_ saved according to the `AttributeDescriptor. This allows us to identify scenarios where the conigured storage location has changed since the attribute value was last saved. This `IsExtendedAttributeMismatch()` method is encorporated into the `GetAttributes()` method such that any mismatched attributes will be returned if `isDirty` is `true`—even if `AttributeValue.IsDirty` is `false`. This is important because even though the _value_ hasn't changed, the _storage location_ has and, therefore, it should be treated _as though_ it were `IsDirty`. This includes two unit test cases to validate this functionality—one to make sure that `!IsDirty` attributes are returned if `IsExtendedAttributeMismatch()` is true, and another to make sure they _aren't_ returned if the `isExtendedAttribute` parameter doesn't match the `AttributeDescriptor.IsExtendedAttribute` property.
1 parent 0d44c08 commit a3d4798

2 files changed

Lines changed: 91 additions & 1 deletion

File tree

OnTopic.Tests/TopicRepositoryBaseTest.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,51 @@ public void GetAttributes_ExtendedAttributes_ReturnsExtendedAttributes() {
129129

130130
}
131131

132+
/*==========================================================================================================================
133+
| TEST: GET ATTRIBUTES: EXTENDED ATTRIBUTE MISMATCH: RETURNS EXTENDED ATTRIBUTES
134+
\-------------------------------------------------------------------------------------------------------------------------*/
135+
/// <summary>
136+
/// Retrieves a list of attributes from a topic, filtering by <see cref="AttributeValue.IsDirty"/>. Expects an <see
137+
/// cref="AttributeValue"/> to be returned even if it's <i>not</i> <see cref="AttributeValue.IsDirty"/> <i>but</i> its
138+
/// <see cref="AttributeValue.IsExtendedAttribute"/> disagrees with <see cref="AttributeDescriptor.IsExtendedAttribute"/>.
139+
/// </summary>
140+
[TestMethod]
141+
public void GetAttributes_ExtendedAttributeMismatch_ReturnsExtendedAttributes() {
142+
143+
var topic = TopicFactory.Create("Test", "ContentTypes");
144+
145+
topic.Attributes.SetValue("Title", "Title", isDirty:false, isExtendedAttribute:false);
146+
147+
var attributes = _topicRepository.GetAttributesProxy(topic, true, true);
148+
149+
//Expect Title, even though it isn't IsDirty
150+
Assert.AreEqual<int>(1, attributes.Count());
151+
152+
}
153+
154+
/*==========================================================================================================================
155+
| TEST: GET ATTRIBUTES: EXTENDED ATTRIBUTE MISMATCH: RETURNS NOTHING
156+
\-------------------------------------------------------------------------------------------------------------------------*/
157+
/// <summary>
158+
/// Retrieves a list of attributes from a topic, filtering by <see cref="AttributeValue.IsDirty"/>. Expects the <see
159+
/// cref="AttributeValue"/> to <i>not</i> be returned even though its <see cref="AttributeValue.IsExtendedAttribute"/>
160+
/// disagrees with <see cref="AttributeDescriptor.IsExtendedAttribute"/>, since it won't match the <see
161+
/// cref="TopicRepositoryBase.GetAttributes(Topic, Boolean?, Boolean?, Boolean)"/>'s <c>isExtendedAttribute</c> call.
162+
/// </summary>
163+
[TestMethod]
164+
public void GetAttributes_ExtendedAttributeMismatch_ReturnsNothing() {
165+
166+
var topic = TopicFactory.Create("Test", "ContentTypes");
167+
168+
topic.Attributes.SetValue("Title", "Title", isDirty: false, isExtendedAttribute: false);
169+
170+
var attributes = _topicRepository.GetAttributesProxy(topic, false, true);
171+
172+
//Expect Key and ContentType, but not Title
173+
Assert.AreEqual<int>(2, attributes.Count());
174+
175+
}
176+
132177
/*==========================================================================================================================
133178
| TEST: GET ATTRIBUTES: ARBITRARY ATTRIBUTE WITH SHORT VALUE: RETURNS AS INDEXED ATTRIBUTE
134179
\-------------------------------------------------------------------------------------------------------------------------*/

OnTopic/Repositories/TopicRepositoryBase.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ protected IEnumerable<AttributeValue> GetAttributes(Topic topic, bool? isExtende
515515
\-----------------------------------------------------------------------------------------------------------------------*/
516516
var attributes = new List<AttributeValue>();
517517

518-
foreach (var attributeValue in topic.Attributes.Where(a => isDirty == null || a.IsDirty == isDirty)) {
518+
foreach (var attributeValue in topic.Attributes) {
519519

520520
var key = attributeValue.Key;
521521
var attribute = (AttributeDescriptor?)null;
@@ -536,6 +536,19 @@ protected IEnumerable<AttributeValue> GetAttributes(Topic topic, bool? isExtende
536536
continue;
537537
}
538538

539+
//Skip if attribute's isDirty flag doesn't match the callers preference. Alternatively, if the IsExtendedAttribute value
540+
//doesn't match the source, as this implies the storage location has changed, and the attribute should be treated as
541+
//isDirty.
542+
if (
543+
isDirty == null ||
544+
attributeValue.IsDirty == isDirty ||
545+
isDirty == IsExtendedAttributeMismatch(attribute, attributeValue)
546+
) {
547+
}
548+
else {
549+
continue;
550+
}
551+
539552
//Add the attribute based on the isExtendedAttribute paramter. Add all parameters if isExtendedAttribute is null. Assume
540553
//an attribute is extended if the corresponding attribute descriptor cannot be located and the value is over 255
541554
//characters.
@@ -643,6 +656,38 @@ topic is AttributeDescriptor &&
643656
topic.Parent?.Key == "Attributes" &&
644657
topic.Parent.Parent is ContentTypeDescriptor;
645658

659+
660+
/*==========================================================================================================================
661+
| METHOD: IS EXTENDED ATTRIBUTE MISMATCH?
662+
\-------------------------------------------------------------------------------------------------------------------------*/
663+
/// <summary>
664+
/// Determines whether or not there's a mismatch between the <see cref="AttributeDescriptor.IsExtendedAttribute"/> and the
665+
/// <see cref="AttributeValue.IsExtendedAttribute"/>.
666+
/// </summary>
667+
/// <remarks>
668+
/// <para>
669+
/// The <see cref="AttributeDescriptor.IsExtendedAttribute"/> determines where an attribute <i>should</i> be stored; the
670+
/// <see cref="AttributeValue.IsExtendedAttribute"/> determines where an attribute <i>was</i> stored. If these two
671+
/// values are in conflict, that suggests the coniguration for <see cref="AttributeDescriptor.IsExtendedAttribute"/> has
672+
/// changed since the attribute value was last saved. In that case, it should be treated as <see
673+
/// cref="AttributeValue.IsDirty"/> <i>even though</i> its value hasn't changed to ensure that its storage location is
674+
/// updated.
675+
/// </para>
676+
/// <para>
677+
/// If <see cref="AttributeDescriptor"/> cannot be found then the <see cref="AttributeValue"/> is arbitrary attribute
678+
/// not mapped to the schema. In that case, its storage location is dynamically determined based on its length, and thus
679+
/// it should only change locations when it <see cref="AttributeValue.IsDirty"/>. Otherwise, its length will remain the
680+
/// same, and thus the storage location should remain unchanged.
681+
/// </para>
682+
/// </remarks>
683+
/// <param name="attributeDescriptor">The source <see cref="AttributeDescriptor"/>, if available.</param>
684+
/// <param name="attributeValue">The target <see cref="AttributeValue"/>.</param>
685+
/// <returns></returns>
686+
private static bool IsExtendedAttributeMismatch(AttributeDescriptor? attributeDescriptor, AttributeValue attributeValue) =>
687+
attributeDescriptor != null &&
688+
attributeValue.IsExtendedAttribute != null &&
689+
attributeDescriptor.IsExtendedAttribute != attributeValue.IsExtendedAttribute;
690+
646691
/*==========================================================================================================================
647692
| METHOD: RESET ATTRIBUTE DESCRIPTORS
648693
\-------------------------------------------------------------------------------------------------------------------------*/

0 commit comments

Comments
 (0)