Created
March 16, 2022 19:36
-
-
Save GinoCanessa/3e593bc56b43dd290ecedbbb431e0447 to your computer and use it in GitHub Desktop.
FHIR Interface Hierarchy Exploration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Starting processing of Interfaces in the inheritance tree... | |
JSON of Interfaces included in inheritance tree: | |
------------ | |
{ | |
"Problematic": "Scalar value", | |
"Author": [ | |
"This should be invalid" | |
], | |
"Url": "http://example.org/interfaceInInheritance", | |
"Id": "inherited-interface" | |
} | |
------------ | |
Starting processing of Interfaces as an external concept... | |
Non-inheritance caught: This element is not valid on this Resource. | |
Non-inheritance caught: Questionnaire is restricted to a single Problematic value | |
JSON of Interfaces as a separate concept: | |
------------ | |
{ | |
"Url": "http://example.org/keepStrictInheritance", | |
"Problematic": "Scalar value", | |
"Id": "external-interface" | |
} | |
------------ | |
Starting processing of Interfaces as an external concept (v2)... | |
Non-inheritance caught: This element is not valid on this Resource. | |
Non-inheritance caught: Questionnaire is restricted to a single Problematic value | |
JSON of Interfaces as a separate concept v2: | |
------------ | |
{ | |
"Url": "http://example.org/keepStrictInheritance", | |
"Problematic": [ | |
"Scalar value" | |
], | |
"Id": "external-interface-v2" | |
} | |
------------ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Text.Json; | |
using System.Text.Json.Serialization; | |
/// <summary>A partial metadata resource.</summary> | |
public class PartialMetadataResource : PartialResource | |
{ | |
/// <summary>Gets or sets URL of the document.</summary> | |
public Uri Url { get; set; } | |
/// <summary>Gets or sets the author.</summary> | |
public string[] Author { get; set; } | |
/// <summary>Gets or sets the especially problematic.</summary> | |
public string[] Problematic { get; set; } | |
} | |
/// <summary>Interface for partial metadata.</summary> | |
public interface IPartialMetadata | |
{ | |
/// <summary>Gets or sets URL of the document.</summary> | |
Uri Url { get; set; } | |
/// <summary>Gets or sets the author.</summary> | |
string[] Author { get; set; } | |
/// <summary>Gets or sets the especially problematic.</summary> | |
string[] Problematic { get; set; } | |
} | |
/// <summary>A partial questionnaire inherit.</summary> | |
public class PartialQuestionnaireInherit : PartialMetadataResource | |
{ | |
/// <summary>Gets or sets the especially problematic.</summary> | |
new public string Problematic { get; set; } | |
/// <summary> | |
/// Gets or sets the author. | |
/// Note that we need to explicitly flag this property NOT to be serialized, because | |
/// otherwise the serializer will get this exception and stop processing. | |
/// </summary> | |
/// <exception cref="Exception">Thrown when an exception error condition occurs.</exception> | |
[Obsolete("Metadata.Author is invalid", true)] | |
[JsonIgnore] | |
new public string[] Author | |
{ | |
get => throw new Exception("This element is not valid on this Resource."); | |
set => throw new Exception("This element is not valid on this Resource."); | |
} | |
} | |
/// <summary>A partial questionnaire strict.</summary> | |
public class PartialQuestionnaireStrict : PartialResource, IPartialMetadata | |
{ | |
/// <summary>Gets or sets URL of the document.</summary> | |
public Uri Url { get; set; } | |
/// <summary>Gets or sets the especially problematic.</summary> | |
public string Problematic { get; set; } | |
/// <summary> | |
/// Gets or sets the author. | |
/// Note that we need to explicitly flag this property NOT to be serialized, because | |
/// otherwise the serializer will get this exception and stop processing. | |
/// </summary> | |
[Obsolete("Metadata.Author is invalid")] | |
[JsonIgnore] | |
string[] IPartialMetadata.Author | |
{ | |
get => throw new Exception("This element is not valid on this Resource."); | |
set => throw new Exception("This element is not valid on this Resource."); | |
} | |
/// <summary>Gets or sets URL of the document.</summary> | |
Uri IPartialMetadata.Url { get => this.Url; set => this.Url = value; } | |
/// <summary>Gets or sets the especially problematic.</summary> | |
string[] IPartialMetadata.Problematic | |
{ | |
get | |
{ | |
if (string.IsNullOrEmpty(this.Problematic)) | |
{ | |
return new string[0]; | |
} | |
return new string[1] { this.Problematic }; | |
} | |
set | |
{ | |
if ((value == null) || | |
(value.Length == 0)) | |
{ | |
this.Problematic = null; | |
return; | |
} | |
if (value.Length > 1) | |
{ | |
throw new Exception("Questionnaire is restricted to a single Problematic value"); | |
} | |
this.Problematic = value[0]; | |
} | |
} | |
} | |
public class PartialQuestionnaireStrict2 : PartialResource, IPartialMetadata | |
{ | |
/// <summary>Gets or sets URL of the document.</summary> | |
public Uri Url { get; set; } | |
/// <summary> | |
/// Gets or sets the especially problematic. | |
/// Here we define Problematic as an array, which is a better | |
/// compatibility story, but we only know that from the pain | |
/// of trying otherwise | |
/// </summary> | |
public string[] Problematic { get; set; } | |
/// <summary> | |
/// Gets or sets the author. | |
/// Note that we need to explicitly flag this property NOT to be serialized, because | |
/// otherwise the serializer will get this exception and stop processing. | |
/// </summary> | |
[Obsolete("Metadata.Author is invalid")] | |
[JsonIgnore] | |
string[] IPartialMetadata.Author | |
{ | |
get => throw new Exception("This element is not valid on this Resource."); | |
set => throw new Exception("This element is not valid on this Resource."); | |
} | |
/// <summary>Gets or sets URL of the document.</summary> | |
Uri IPartialMetadata.Url { get => this.Url; set => this.Url = value; } | |
/// <summary>Gets or sets the especially problematic.</summary> | |
string[] IPartialMetadata.Problematic | |
{ | |
get | |
{ | |
if ((this.Problematic == null) || | |
(this.Problematic.Length == 0)) | |
{ | |
return new string[0]; | |
} | |
return this.Problematic; | |
} | |
set | |
{ | |
if ((value == null) || | |
(value.Length == 0)) | |
{ | |
this.Problematic = null; | |
return; | |
} | |
if (value.Length > 1) | |
{ | |
throw new Exception("Questionnaire is restricted to a single Problematic value"); | |
} | |
this.Problematic = value; | |
} | |
} | |
} | |
/// <summary>A program.</summary> | |
public static class Program | |
{ | |
/// <summary>Main entry-point for this application.</summary> | |
/// <param name="args">An array of command-line argument strings.</param> | |
/// <returns>Exit-code for the process - 0 for success, else an error code.</returns> | |
public static int Main(string[] args) | |
{ | |
// ******************************************************* | |
// Start interfaces are included in inheritance tree | |
// ******************************************************* | |
Console.WriteLine("Starting processing of Interfaces in the inheritance tree..."); | |
// Author element is present, best developer experience I have | |
// discovered is marking it Obsolete, so it cannot be used directly | |
// this works with POCOs, but does not help with tree-based | |
// or dynamic navigation styles. | |
// * | |
// Problematic appears as scalar. | |
PartialQuestionnaireInherit inherit = new() | |
{ | |
Id = "inherited-interface", | |
Url = new Uri("http://example.org/interfaceInInheritance"), | |
//Author = new string[1] { "Invalid Element Needs To Throw" }, | |
Problematic = "Scalar value", | |
}; | |
// create a meta-view based on the inherited class of metadata | |
PartialMetadataResource metaOfInherited = (PartialMetadataResource)inherit; | |
// despite the element being flagged in Questionnaire, it is present and can | |
// receive values. I have not found a way to bypass this. | |
metaOfInherited.Author = new string[1] { "This should be invalid" }; | |
// in this view, Problematic is an array now | |
metaOfInherited.Problematic = new string[2] { "Scalar value", "An INVALID second value" }; | |
// serialize to JSON | |
string jsonInherited = JsonSerializer.Serialize(inherit, new JsonSerializerOptions() { WriteIndented = true }); | |
Console.WriteLine("JSON of Interfaces included in inheritance tree:"); | |
Console.WriteLine("------------"); | |
Console.WriteLine(jsonInherited); | |
Console.WriteLine("------------"); | |
// ******************************************************* | |
// Start interfaces are external from inheritance tree | |
// ******************************************************* | |
Console.WriteLine("\nStarting processing of Interfaces as an external concept..."); | |
PartialQuestionnaireStrict strict; | |
try | |
{ | |
// Author element is not present, since it is not defined. | |
// * | |
// Problematic appears as scalar, but throws when set. | |
strict = new() | |
{ | |
Id = "external-interface", | |
Url = new Uri("http://example.org/keepStrictInheritance"), | |
Problematic = "Scalar value", | |
}; | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Non-inheritance caught: {ex.Message}"); | |
// This time, create without the problematic element | |
strict = new() | |
{ | |
Id = "external-interface", | |
Url = new Uri("http://example.org/keepStrictInheritance"), | |
}; | |
} | |
// create a meta-view based on the interface of metadata | |
IPartialMetadata iStrict = (IPartialMetadata)strict; | |
// despite the element being flagged in Questionnaire, it is present and will still fail at runtime | |
// but, at least it throws an exception here | |
try | |
{ | |
iStrict.Author = new string[1] { "This should be invalid" }; | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Non-inheritance caught: {ex.Message}"); | |
} | |
// in this view, Problematic is an array now, and it throws if we try to add a second value | |
try | |
{ | |
iStrict.Problematic = new string[2] { "Scalar value", "An INVALID second value" }; | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Non-inheritance caught: {ex.Message}"); | |
} | |
// serialize to JSON | |
string jsonStrict = JsonSerializer.Serialize(strict, new JsonSerializerOptions() { WriteIndented = true }); | |
Console.WriteLine("JSON of Interfaces as a separate concept:"); | |
Console.WriteLine("------------"); | |
Console.WriteLine(jsonStrict); | |
Console.WriteLine("------------"); | |
// ******************************************************* | |
// Start interfaces are external from inheritance tree v2 | |
// ******************************************************* | |
Console.WriteLine("\nStarting processing of Interfaces as an external concept (v2)..."); | |
// Author element is not present, since it is not defined. | |
// * | |
// Problematic appears as array, will throw if multiple values are passed. | |
PartialQuestionnaireStrict2 strict2 = new() | |
{ | |
Id = "external-interface-v2", | |
Url = new Uri("http://example.org/keepStrictInheritance"), | |
Problematic = new string[1] { "Scalar value" }, | |
}; | |
// create a meta-view based on the interface of metadata | |
IPartialMetadata iStrict2 = (IPartialMetadata)strict2; | |
// despite the element being flagged as obsolete in Questionnaire, it is present and will still | |
// fail at runtime. But, at least it throws an exception here. | |
try | |
{ | |
iStrict.Author = new string[1] { "This should be invalid" }; | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Non-inheritance caught: {ex.Message}"); | |
} | |
// in this view, Problematic is an array now, and it throws if we try to add a second value | |
try | |
{ | |
iStrict.Problematic = new string[2] { "Scalar value", "An INVALID second value" }; | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine($"Non-inheritance caught: {ex.Message}"); | |
} | |
// serialize to JSON | |
string jsonStrict2 = JsonSerializer.Serialize(strict2, new JsonSerializerOptions() { WriteIndented = true }); | |
Console.WriteLine("JSON of Interfaces as a separate concept v2:"); | |
Console.WriteLine("------------"); | |
Console.WriteLine(jsonStrict2); | |
Console.WriteLine("------------"); | |
return 0; | |
} | |
} | |
/// <summary>A partial FHIR resource.</summary> | |
public class PartialResource | |
{ | |
/// <summary>Gets or sets the identifier.</summary> | |
public string Id { get; set; } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Code structure notes:
General notes
Disclaimers/Assumptions/Context:
So, my attempt at collecting thoughts...
-- 'Profiling' in resource definitions:
-- Interfaces in the class hierarchy:
-- General thoughts
Including interfaces in the modeling inheritance means I have to deal with the strangeness of implied elements, etc. in order to use any model that has one (with the implication that more of these will appear in the future). Leaving it out means that I only add that complexity if I want to use interfaces.