Skip to content

Overview of the POCO classes and interfaces

Ewout Kramer edited this page Oct 9, 2024 · 5 revisions
classDiagram
direction LR

class IDeepCopyable{
    DeepCopy() IDeepCopyable 
    CopyTo(IDeepCopyable) IDeepCopyable 
}

Base --|> IDeepCopyable

class IDeepComparable{
    IsExactly(IDeepComparable) bool
    Matches(IDeepComparable) bool
}

Base --|> IDeepComparable

class IAnnotated{
    Annotations(Type) IEnumerable<object> 
}

Base --|> IAnnotated

class IAnnotatable{
     AddAnnotation(object) void
     RemoveAnnotations(Type) void
}

Base --|> IAnnotatable

namespace System-ComponentModel{
    class INotifyPropertyChanged{
        PropertyChangedEventHandler PropertyChanged
    }

    class IValidatableObject{
        Validate(ValidationContext) IEnumerable~ValidationResult~ 
    }
}

Base --|> INotifyPropertyChanged
Base --|> IValidatableObject

namespace System-Collections{
    class IReadOnlyDictionary~string,object~{
        Count
        Keys
        Values
        TryGetValue()        
    }
}

Base --|> IReadOnlyDictionary

class Base{
    <<abstract>>
    string TypeName
    IEnumerable~Base~ Children()
    IEnumerable~ElementValue~ NamedChildren()
    IROD AsReadOnlyDictionary()
    bool TryGetValue(string, out object)
    IEnumerable~KVP~ GetElementPairs()
}

class DataType{
    <<abstract>>
}

DataType --|> Element


class PrimitiveType{
    <<abstract>>
    object ObjectValue
    bool HasElements
    OnObjectValueChanged() void
    ToString() string 
}

PrimitiveType --|> DataType

class IExtendable{
    List<Extension> Extension
}

class IModifierExtendable{
    List<Extension> ModifierExtension
}

IModifierExtendable --|> IExtendable

class Element{
    <<abstract>>
    string ElementId
}

Element --|> IExtendable
Element --|> Base

class BackboneElement{
    <<abstract>>
}

BackboneElement --|> Element


class BackboneType{
    <<abstract>>
}
class DomainResource{
    <<abstract>>
    FindContainedResource() Resource
}

BackboneElement --|> IModifierExtendable
BackboneType --|> IModifierExtendable
DomainResource --|> IModifierExtendable

class Resource{
    <<abstract>>
    Uri ResourceBase
    object SyncLock
}

Resource --|> Base
DomainResource --|> Resource

class ISystemAndCode{
    string System
    string Code
}

class Code~T~{
    ToSystemCode() System.Code
}

class IValue~T~{
    T Value
}



class INullableValue~T~
INullableValue --|> IValue

Code --|> ISystemAndCode
Code --|> PrimitiveType
Code --|> INullableValue
Loading

Remarks about the diagram

  • Maybe getting the TypeName prop should throw on abstract types.

  • PrimitiveType makes sure the IROD returns the ObjectValue when we access the value element.

  • Some datatypes have a static IsValidValue(string) that validates the verbatim string representation:

    • Base64Binary
    • Code
    • Date
    • FhirBoolean
    • FhirDateTime
    • FhirDecimal
    • FhirString
    • FhirUri
    • FhirUrl
    • Id
    • Instant
    • Integer
    • Integer64
    • Markdown
    • Oid
    • Time
    • UnsignedInt
    • Uuid
    • XHtml (multiple)
  • Some datatypes have conversion methods to convert to CQL types:

    • Code
    • CodeableConcept
    • Code<T>
    • Coding
    • Date
    • FhirDateTime
    • Time
  • Why has Instant no conversion to a CQL type?

  • Date, FhirDateTime, Time and Instant have lots of comparators and conversions functions.

  • Bundle has all kinds of helper methods to find, resolve and filter child resources. Note that we should have these on Parameter too probably. Convert these methods to an interface on both + extension methods?

  • DomainResource has FindContainedResource().

  • Canonical has helpers to split versions and fragments.

  • We have a Bindable attribute on classes that are bindable according to the FHIR spec.

  • IValue<T> is used by primitives where the Value is a reference type (Code, Data, Canonical, etc), INullableValue<T> is used by non-reference types (FhirInteger, FhirBoolean etc.)

  • ISystemAndCode is only used by Code<T>, but is useful to check whether we are dealing with "a Code<T>" (would require something like GetGenericDefinition() etc to check against it otherwise). Why doesn't the Coding POCO implement this interface as well? Are we dependent on this being one-on-one with Code<T>?

  • There are additional interfaces IConformanceResource, IVersionableConformanceResource, IIdentifiable, ICoded<T>, IPatient implemented by the appropriate resources.

  • Remember, BackboneElement is used as the base class for nested classes (like Patient.Contact), while BackboneType is used by data types that may have modifier extensions.

  • Confusingly, Code<T> represents a FHIR Coding: its enum value has both a system+code encoded in the attributes. This is probably why this is a subclass of PrimitiveType (since it has a Value of type enum), but it is not a FHIR Primitive datatype.

Ideas (breaking)

  • Make IAnnotatable a subclass of IAnnotated.
  • We should implement most of the interfaces explicitly, so we don't clutter the surface of the POCO's too much.
  • We should remove IDeepComparable in favor of an System.Collections.Generic.EqualityComparer<Base> (e.g. a ExactlyEqualityComparer and a PatternEqualityComparer) There are several different kinds of equality defined, so this matches the usescases better. It also can be based on any of the functions to traverse the tree, it does not have to be on the class itself.
  • ElementValue should be a record, and the fields should become properties.
  • Resource has a pretty useless VersionId property that gets/sets the Meta.Versiond and also HasVersionId. I think we should remove it.
  • We should unify FhirTypeConstants and FhirTypeNames, they do the same.
  • There are lots of places where we deal with Canonicals, HL7 base urls, analyzing references. We could unify these unto one or two classes.
  • Find out why we have INullableValue<T> and IValue<T>, since it does not seem to be used by us. It does provide typed access to the Value property of a primitive, unlike PrimitiveType. INullableValue does not seem to have a use, beyond being a shorthand for doing IValue<T?> ?
  • We could move all the comparison logic to the Cql types that correspond to the primitives, so we only have one set. The POCO datatypes could then just invoke the Cql-based comparators etc.
Clone this wiki locally