Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void merge(ElementDefinition snap, ElementDefinition diff, bool mergeElementId,
// Constraints are cumulative, so they are always "new" (hence a constant false for the comparer)
// [WMR 20160917] Note: constraint keys must be unique. The validator will detect duplicate keys, so the derived
// profile author can correct the conflicting constraint key.
// [WMR 20160918] MUST merge indentical constraints, otherwise each derived profile accumulates
// [WMR 20160918] MUST merge identical constraints, otherwise each derived profile accumulates
// additional identical constraints inherited from e.g. BackboneElement.
// snap.Constraint = mergeCollection(snap.Constraint, diff.Constraint, (a, b) => false);
// [WMR 20190723] R4 NEW: Initialize Constraint.source property
Expand Down Expand Up @@ -283,7 +283,7 @@ ElementDefinition.TypeRefComponent mergeElementType(ElementDefinition.TypeRefCom
// TODO: Move logic to MergeTo method on partial class TypeRefComponent

// TODO: Copy diff annotations...?
if (diff.ElementId != null) { result.ElementId = diff.ElementId; }
result.ElementId = mergeString(snap.ElementId, diff.ElementId);
result.Extension = mergeExtensions(snap.Extension, diff.Extension);
result.CodeElement = mergePrimitiveElement(snap.CodeElement, diff.CodeElement);

Expand Down Expand Up @@ -366,6 +366,7 @@ private ElementDefinition.ElementDefinitionBindingComponent mergeBinding(Element
snap.StrengthElement = mergePrimitiveElement(snap.StrengthElement, diff.StrengthElement);
snap.DescriptionElement = mergePrimitiveElement(snap.DescriptionElement, diff.DescriptionElement);
snap.ValueSetElement = mergeComplexAttribute(snap.ValueSetElement, diff.ValueSetElement);
snap.ElementId = mergeString(snap.ElementId, diff.ElementId);
snap.Extension = mergeExtensions(snap.Extension, diff.Extension);
snap.Additional = mergeCollection(snap.Additional, diff.Additional, matchExactly);
onConstraint(result);
Expand Down Expand Up @@ -670,7 +671,8 @@ T mergePrimitiveElement<T>(T snap, T diff, bool allowAppend = false) where T : P
{
result.ObjectValue = diffValue;
}
// Also merge extensions on primitives
// Also merge element id and extensions on primitives
result.ElementId = mergeString(snap.ElementId, diff.ElementId);
result.Extension = mergeExtensions(snap.Extension, diff.Extension);
onConstraint(result);
}
Expand All @@ -692,21 +694,21 @@ static string mergeId(ElementDefinition snap, ElementDefinition diff, bool merge
}
// Newly introduced named slices NEVER inherit element id
// Must always regenerate new unique identifier for named slices
else if (!IsEqualName(diff.SliceName, snap.SliceName))
if (!IsEqualName(diff.SliceName, snap.SliceName))
{
// Regenerate; don't inherit from snap
return null;
}
// Otherwise inherit existing element id from snap
return snap.ElementId;
}
else
{
// Don't merge elementId, e.g. for type profiles
return null;
}

// Don't merge elementId, e.g. for type profiles
return null;
}

static string mergeString(string snap, string diff) => diff ?? snap;

// Functions to match snap collection items to diff collection items
// Matching key depends on collection type

Expand Down
16 changes: 9 additions & 7 deletions src/Hl7.Fhir.STU3/Specification/Snapshot/ElementDefnMerger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,9 @@ T mergePrimitiveAttribute<T>(T snap, T diff, bool allowAppend = false) where T :

result.ObjectValue = diffText;
}
// Also merge extensions on primitives
// Also merge element id and extensions on primitives
// [Backported from R4]
result.ElementId = mergeString(snap?.ElementId, diff.ElementId);
result.Extension = mergeExtensions(snap?.Extension, diff.Extension);
onConstraint(result);
return result;
Expand Down Expand Up @@ -509,6 +510,7 @@ private ElementDefinition.ElementDefinitionBindingComponent mergeBinding(Element
snap.StrengthElement = mergePrimitiveAttribute(snap.StrengthElement, diff.StrengthElement);
snap.DescriptionElement = mergePrimitiveAttribute(snap.DescriptionElement, diff.DescriptionElement);
snap.ValueSet = mergeComplexAttribute(snap.ValueSet, diff.ValueSet);
snap.ElementId = mergeString(snap.ElementId, diff.ElementId);
snap.Extension = mergeExtensions(snap.Extension, diff.Extension);
onConstraint(result);
}
Expand All @@ -535,21 +537,21 @@ string mergeId(ElementDefinition snap, ElementDefinition diff, bool mergeElement
}
// Newly introduced named slices NEVER inherit element id
// Must always regenerate new unique identifier for named slices
else if (diff.SliceName != snap.SliceName)
if (diff.SliceName != snap.SliceName)
{
// Regenerate; don't inherit from snap
return null;
}
// Otherwise inherit existing element id from snap
return snap.ElementId;
}
else
{
// Don't merge elementId, e.g. for type profiles
return null;
}

// Don't merge elementId, e.g. for type profiles
return null;
}

static string mergeString(string snap, string diff) => diff ?? snap;

// [WMR 20180611] NEW
static bool isEqualCoding(Coding c, Coding d)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,18 @@ namespace Hl7.Fhir.Specification.Tests
/// The property can also be a specific item from a property list.
/// The property name is specified in the constructor.
///
/// The name is either the name of the property (e.g. "Binding") or the name of the property list
/// with a item selector (e.g. "Constraint[Key:dom-2]").
/// The name can be
/// - the name of the property (e.g. "Binding")
/// - the name of the property list with an index (e.g. "Type[0]").
/// - the name of the property list with an item selector (e.g. "Constraint[Key:dom-2]").
/// </summary>
internal class ElementDefinitionPropertyProxy
{
private bool _isList;
private string _propertyName;
private string _selectorPropertyName;
private string _selectorValue;
private string _listSelectorPropertyName;
private string _listSelectorValue;
private int? _listIndex;
private PropertyInfo _propertyInfo;
private PropertyInfo _selectorPropertyInfo;

Expand All @@ -38,7 +42,7 @@ public object CreateInstance(Element element)
{
var instance = Activator.CreateInstance(_propertyInfo.PropertyType);

if (_selectorPropertyInfo == null)
if (!_isList)
return instance; // Primitive property

// Create item for property list
Expand All @@ -47,8 +51,8 @@ public object CreateInstance(Element element)
// Initialize with specified element
element?.CopyTo(item);

// Set key value
_selectorPropertyInfo.SetValue(item, _selectorValue);
if (_selectorPropertyInfo != null)
_selectorPropertyInfo.SetValue(item, _listSelectorValue); // Set key value

// Add item to property list
if (instance is IList items)
Expand All @@ -74,18 +78,29 @@ public void SetValue(object instance, object value)
/// <returns>The property value as an Element type.</returns>
public Element GetValueAsElement(object instance)
{
if (_selectorPropertyInfo == null)
if (!_isList)
return (Element)_propertyInfo.GetValue(instance);

if (_propertyInfo.GetValue(instance, null) is not IList items)
return null;

foreach (var item in items)
if (_selectorPropertyInfo != null)
{
var value = _selectorPropertyInfo.GetValue(item)?.ToString();
foreach (var item in items)
{
var value = _selectorPropertyInfo.GetValue(item)?.ToString();

if (_selectorValue.Equals(value))
return (Element)item;
if (_listSelectorValue.Equals(value))
return (Element)item;
}

return null;
}

if (_listIndex.HasValue)
{
_listIndex.Value.Should().BeInRange(0, items.Count - 1);
return (Element)items[_listIndex.Value];
}

return null;
Expand All @@ -98,34 +113,60 @@ private void getPropertyInfo(string propertyName)
_propertyInfo = typeof(ElementDefinition).GetProperty(_propertyName);
_propertyInfo.Should().NotBeNull(); // Check property exists

// ReSharper disable once PossibleNullReferenceException
if (!isList(_propertyInfo.PropertyType))
_isList = isList(_propertyInfo.PropertyType);

if (!_isList)
{
_propertyInfo.PropertyType.IsAssignableTo(typeof(Element)).Should().BeTrue(); // Property type should be derived from Element
return;
}

_propertyInfo.PropertyType.GenericTypeArguments[0].IsAssignableTo(typeof(Element)).Should().BeTrue(); // Property type should be derived from Element

_selectorPropertyInfo = _propertyInfo.PropertyType.GenericTypeArguments[0].GetProperty(_selectorPropertyName);
if (_listSelectorPropertyName == null)
return;

_selectorPropertyInfo = _propertyInfo.PropertyType.GenericTypeArguments[0].GetProperty(_listSelectorPropertyName);
_selectorPropertyInfo.Should().NotBeNull(); // Check property exists
}

private void parsePropertyName(string propertyName)
{
_propertyName = propertyName;

var regex = new Regex("(.*)\\[(.*):(.*)\\]|(.*)");
if (!tryParseListKey(propertyName))
tryParseListIndex(propertyName);
}

private static bool isList(Type type) => typeof(IList).IsAssignableFrom(type);

private bool tryParseListKey(string propertyName)
{
var regex = new Regex("(.+)\\[(.+):(.+)\\]");
var result = regex.Match(propertyName);

if (!result.Success || result.Groups[4].Success)
return;
if (!result.Success)
return false;

_propertyName = result.Groups[1].Value;
_selectorPropertyName = result.Groups[2].Value;
_selectorValue = result.Groups[3].Value;
_listSelectorPropertyName = result.Groups[2].Value;
_listSelectorValue = result.Groups[3].Value;

return true;
}

private static bool isList(Type type) => typeof(IList).IsAssignableFrom(type);
private bool tryParseListIndex(string propertyName)
{
var regex = new Regex("(.+)\\[(\\d+)\\]");
var result = regex.Match(propertyName);

if (!result.Success)
return false;

_propertyName = result.Groups[1].Value;
_listIndex = int.Parse(result.Groups[2].Value);

return true;
}
}
}
Loading