Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8647cc6
wip
Kasdejong Dec 4, 2024
1d3d4b0
Merge branch 'feature/remove-temp-changed' into spike/remove-iscopednode
Kasdejong Dec 9, 2024
0638563
wip
Kasdejong Dec 9, 2024
3090ef1
Merge branch 'refs/heads/develop-6.0' into spike/remove-iscopednode
Kasdejong Dec 19, 2024
605becd
wip: Refactoring FP engine
Kasdejong Jan 7, 2025
0649fae
wip. Type operators should work now.
Kasdejong Jan 7, 2025
7c0f850
finished refactoring FP engine and fixed some rider warnings
Kasdejong Jan 7, 2025
fab6a64
wip, fixing bugs
Kasdejong Jan 8, 2025
ed8e75e
fixed bug with null values in focus (in a particular unit test)
Kasdejong Jan 8, 2025
44d8496
Last few bugs
Kasdejong Jan 8, 2025
4ae8d27
wip, more bugs
Kasdejong Jan 8, 2025
5720bc0
Line change
Kasdejong Jan 8, 2025
51472f9
compat suppressions
Kasdejong Jan 8, 2025
a906520
added FP system types
Kasdejong Jan 28, 2025
4564f4b
Merge branch 'develop-6.0' into spike/remove-iscopednode
Kasdejong Jan 28, 2025
2a825e8
Merge branch 'feature/add-cql-type-pocos' into spike/remove-iscopednode
Kasdejong Jan 28, 2025
f09da09
implemented some new logic surrounding the system primitives in the F…
Kasdejong Feb 11, 2025
3011e31
wip
Kasdejong Feb 11, 2025
df06487
Merge branch 'develop-6.0' into spike/remove-iscopednode
Kasdejong Feb 11, 2025
c3f829f
resolved merge conflicts
Kasdejong Feb 11, 2025
b5602cf
Fixed remaining unit tests
Kasdejong Feb 11, 2025
49a27a3
compatibility suppressions
Kasdejong Feb 11, 2025
e55110e
fixed unit tests
Kasdejong Feb 11, 2025
5168f6b
changed xml again for this failing unit test
Kasdejong Feb 11, 2025
c3d42f5
WIP documentation
Kasdejong Feb 11, 2025
7e3ca0f
fixed another unit test
Kasdejong Feb 11, 2025
c03b1a0
Fixed a test where a poco was being constructed without the appropria…
Kasdejong Feb 11, 2025
f223bcc
Adjustments to public interface
Kasdejong Feb 11, 2025
7ea20bd
added some documentation and moved a method to the extension methods.
Kasdejong Feb 11, 2025
fe545da
oops...
Kasdejong Feb 11, 2025
fa91a67
removed TemporarilyChanged Attributes. These were unused
Kasdejong Feb 12, 2025
b70bc9c
Applied PR changes
Kasdejong Feb 13, 2025
78692ba
compat suppressions
Kasdejong Feb 13, 2025
613e870
fixed failing unit test
Kasdejong Feb 19, 2025
fbe41f7
refactored extension methods around the elementmodel to now be in the…
Kasdejong Feb 19, 2025
6087ae3
uhm... renames again?
Kasdejong Feb 19, 2025
0e35fff
compat suppressions
Kasdejong Feb 25, 2025
4c192f4
renames according to PR review
Kasdejong Feb 25, 2025
9c0f146
Merge pull request #3052 from FirelyTeam/feature/reorg-toX-files
ewoutkramer Feb 25, 2025
2745a35
Merge branch 'develop-6.0' into spike/remove-iscopednode
ewoutkramer Feb 25, 2025
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
832 changes: 703 additions & 129 deletions src/Hl7.Fhir.Base/CompatibilitySuppressions.xml

Large diffs are not rendered by default.

123 changes: 0 additions & 123 deletions src/Hl7.Fhir.Base/ElementModel/ElementNodeExtensions.cs

This file was deleted.

81 changes: 40 additions & 41 deletions src/Hl7.Fhir.Base/ElementModel/ISourceNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,52 +8,51 @@

using System.Collections.Generic;

namespace Hl7.Fhir.ElementModel
namespace Hl7.Fhir.ElementModel;

/// <summary>
/// A node within a tree of FHIR data.
/// </summary>
/// <remarks>
/// <para>This interface is typically implemented by a parser for one of the low-level serialization formats for FHIR, i.e.
/// FHIR xml/json/rdf or v3 XML. The interface does not depend on the availability of FHIR metadata and definitions
/// (in contrast to <see cref="ITypedElement" />), so the names of the nodes will have their type suffixes (for choice types)
/// and all primitives values are represented as strings, instead of native objects.</para>
/// <para>Implementations of this interface that want to report errors while parsing should only do so on the
/// <see cref="Children(string)"/> function and <see cref="Text"/> getter.</para>
/// </remarks>
public interface ISourceNode
{
/// <summary>
/// A node within a tree of FHIR data.
/// Gets the name of the node, e.g. "active", "valueQuantity".
/// </summary>
/// <remarks>
/// <para>This interface is typically implemented by a parser for one of the low-level serialization formats for FHIR, i.e.
/// FHIR xml/json/rdf or v3 XML. The interface does not depend on the availability of FHIR metadata and definitions
/// (in contrast to <see cref="ITypedElement" />), so the names of the nodes will have their type suffixes (for choice types)
/// and all primitives values are represented as strings, instead of native objects.</para>
/// <para>Implementations of this interface that want to report errors while parsing should only do so on the
/// <see cref="Children(string)"/> function and <see cref="Text"/> getter.</para>
/// <remarks>Since the node has no type information, choice elements are represented as their
/// name on the wire, possibly including the type suffix for choice elements.
/// </remarks>
public interface ISourceNode
{
/// <summary>
/// Gets the name of the node, e.g. "active", "valueQuantity".
/// </summary>
/// <remarks>Since the node has no type information, choice elements are represented as their
/// name on the wire, possibly including the type suffix for choice elements.
/// </remarks>
string Name { get; }
string Name { get; }

/// <summary>
/// Gets the text of the primitive value of the node
/// </summary>
/// <value>Returns the raw textual value as represented in the serialization, or null if there is no value in this node.</value>
string Text { get; }
/// <summary>
/// Gets the text of the primitive value of the node
/// </summary>
/// <value>Returns the raw textual value as represented in the serialization, or null if there is no value in this node.</value>
string Text { get; }

/// <summary>
/// Gets the location of this node within the tree of data.
/// </summary>
/// <value>A string of dot-separated names representing the path to the node within the tree, including indices
/// to distinguish repeated occurences of an element.</value>
string Location { get; }
/// <summary>
/// Gets the location of this node within the tree of data.
/// </summary>
/// <value>A string of dot-separated names representing the path to the node within the tree, including indices
/// to distinguish repeated occurences of an element.</value>
string Location { get; }

/// <summary>
/// Enumerates the direct child nodes of the current node (if any).
/// </summary>
/// <param name="name">Optional. The name filter for the children. Can be omitted to not filter by name.</param>
/// <returns>The children of the node matching the given filter, or all children if no filter was specified.
/// If no children match the given filter, the function returns an empty enumerable.</returns>
/// <remarks>
/// <para>If the <paramref name="name"/>parameter ends in an asterix ('*'),
/// the function will return the children of which the name starts with the given name.</para>
/// <para>Repeating elements will always be returned consecutively.</para></remarks>
IEnumerable<ISourceNode> Children(string name = null);
}
/// <summary>
/// Enumerates the direct child nodes of the current node (if any).
/// </summary>
/// <param name="name">Optional. The name filter for the children. Can be omitted to not filter by name.</param>
/// <returns>The children of the node matching the given filter, or all children if no filter was specified.
/// If no children match the given filter, the function returns an empty enumerable.</returns>
/// <remarks>
/// <para>If the <paramref name="name"/>parameter ends in an asterix ('*'),
/// the function will return the children of which the name starts with the given name.</para>
/// <para>Repeating elements will always be returned consecutively.</para></remarks>
IEnumerable<ISourceNode> Children(string name = null);
}
4 changes: 2 additions & 2 deletions src/Hl7.Fhir.Base/ElementModel/NewPocoBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private ClassMapping classMappingForElement(ITypedElement node, PropertyMapping?

// Otherwise, let's use the ITypedElement's instance type.
if (node.InstanceType is { } instanceType &&
inspector.FindClassMapping(instanceType) is { NativeType.IsAbstract: false } mapping)
inspector.FindClassMapping(instanceType) is { NativeType.IsAbstract: false } mapping && typeof(Base).IsAssignableFrom(mapping.NativeType))
return mapping;

// No useable concrete type in the property, nor in the instance type, so we need to create
Expand Down Expand Up @@ -183,7 +183,7 @@ private ClassMapping determineBestDynamicMappingForElement(ITypedElement node)
if (node.Value is not null || (node.InstanceType is { } it && char.IsLower(it[0])))
return determineBestPrimitiveMapping();

if (node.Annotation<IResourceTypeSupplier>() is not null)
if (node.Annotation<IResourceTypeSupplier>() is not null || node.Definition?.IsResource is true)
return getClassMapping(DYNAMIC_RESOURCE_TYPE_NAME);

return getClassMapping(DYNAMIC_DATATYPE_TYPE_NAME);
Expand Down
36 changes: 0 additions & 36 deletions src/Hl7.Fhir.Base/ElementModel/PocoBuilderExtensions.cs

This file was deleted.

96 changes: 96 additions & 0 deletions src/Hl7.Fhir.Base/ElementModel/PocoNode.Primitives.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using Hl7.Fhir.Model;
using Hl7.FhirPath;
using System;
using System.Collections.Generic;
using System.Linq;

#nullable enable

namespace Hl7.Fhir.ElementModel;

public partial record PocoNode
{
/// <summary>
/// Constructs a PocoNode from a PrimitiveType
/// </summary>
/// <returns></returns>
public static PocoNode ForPrimitive(PrimitiveType primitive) =>
new PrimitiveNode(primitive, null, null);


/// <summary>
/// Constructs a PocoNode from an object. Allowed objects are those that can be converted to a PrimitiveType, and are not yet PrimitiveTypes.
/// </summary>
/// <returns></returns>
public static PocoNode ForAnyPrimitive(object value)
{
return ForPrimitive(PrimitiveNode.InferFromValue(value));
}

/// <summary>
/// Constructs a PocoNode from a value and a type. The type must be a PrimitiveType.
/// </summary>
/// <param name="value"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static PocoNode ForPrimitive<T>(object value) where T : PrimitiveType, new() =>
new PrimitiveNode(new T { ObjectValue = value }, null, null);

/// <summary>
/// Constructs a PocoNode from a list of PrimitiveTypes
/// </summary>
/// <param name="primitives"></param>
/// <param name="name"></param>
/// <returns></returns>
public static IEnumerable<PocoNode> FromList(IEnumerable<PrimitiveType> primitives, string? name = null) =>
primitives.Select(ForPrimitive);

/// <summary>
/// Constructs multiple PocoNodes from a list of values and a type. The type must be a PrimitiveType.
/// </summary>
/// <param name="values"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<PocoNode> FromList<T>(IEnumerable<object> values) where T : PrimitiveType, new() =>
values.Select(ForPrimitive<T>);

/// <summary>
/// Constructs multiple PocoNodes from a list of objects. Allowed objects are those that can be converted to a PrimitiveType, and are not yet PrimitiveTypes.
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
public static IEnumerable<PocoNode> FromAnyList(IEnumerable<object> values) =>
values.Select(v => v as PocoNode ?? ForAnyPrimitive(v));
}

public record PrimitiveNode(PrimitiveType Primitive, PocoNodeOrList? ParentNode, int? Index, string? Name = null) : PocoNode(Primitive, ParentNode, Index, Name)
{
protected override object? ValueInternal => Primitive.ToITypedElementValue();
internal object? Value => ValueInternal;

internal static PrimitiveType InferFromValue(object value) => value switch
{
Types.Quantity qt => new FPQuantity(qt),
Types.DateTime dt => new FPDateTime(dt),
Types.Date d => new FPDate(d),
Types.Time t => new FPTime(t),
decimal dec => new FPDecimal(dec),
float f => new FPDecimal((decimal)f),
double d => new FPDecimal((decimal)d),
bool b => new FPBoolean(b),
int i => new FPInteger(i),
long l => new FPLong(l),
string s => new FPString(s),
_ => throw new ArgumentException("Cannot infer primitive type from value", nameof(value))
};

protected override string? TextInternal => Primitive.ToString();
}

internal record PrimitiveListNode(IReadOnlyList<PrimitiveType> Primitives, PocoNodeOrList? ParentNode, string? Name = null) : PocoListNode(Primitives, ParentNode, Name ?? "value")
{
public override IEnumerator<PocoNode> GetEnumerator() =>
Primitives.Select((primitive, index) => new PrimitiveNode(primitive, ParentNode, index, Name)).GetEnumerator();

internal IEnumerable<object?> Values => Primitives.Select(p => p.ObjectValue);
}
Loading