Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design and extend "IScopedNode" #2894

Closed
ewoutkramer opened this issue Oct 9, 2024 · 3 comments · Fixed by #2921
Closed

Design and extend "IScopedNode" #2894

ewoutkramer opened this issue Oct 9, 2024 · 3 comments · Fixed by #2921

Comments

@ewoutkramer
Copy link
Member

We need a new interface with at least Parent (and maybe Resolve()). This is the "ITypedElement" for POCOs. See #2893 for more discussion on the design need and issues for this interface.

@Kasdejong Kasdejong added the SDK-6 label Oct 9, 2024
@Kasdejong Kasdejong added this to the SDK 6 milestone Oct 9, 2024
@Kasdejong Kasdejong removed this from the SDK 6 milestone Oct 9, 2024
@Kasdejong Kasdejong removed the SDK-6 label Oct 9, 2024
@ewoutkramer ewoutkramer changed the title Design the "ITypedElement" replacement Design and extend "IScopedNode" Oct 17, 2024
@ewoutkramer
Copy link
Member Author

Kas and I decided to call it "IScopedNode" for now, since it is still basically ITypedElement + more stuff - Definition.

@mmsmits mmsmits assigned ewoutkramer and unassigned ewoutkramer Oct 23, 2024
@mmsmits mmsmits linked a pull request Oct 23, 2024 that will close this issue
@ewoutkramer
Copy link
Member Author

Final design:

// Now.
IDictionary<string,object>
 
object:

 * "value" => int,string,boolean,....
 * "id" / "url" => string
 * List<>
 * Base

// ITypedElement
* !"value"   (NB Extension.value)
* "id" / "url"  => FhirString, FhirUri (*) POCO: string, string
* ITypedElement****
* Value (CQL types)

Remarks:
* Het feit dat Element.ElementId een string is en Extension.Url een string geeft veel uitzonderingen in de code, want je moet het vaak als Base behandelen.
* Graag gebruiken wij de key "value" niet, want dit is toch een speciaal geval, heeft geen zin om hetzelfde te behandelen als de andere properties.




// Then
Base:

partial class Patient
{
    // Slimme getters en setters.
    public FhirBoolean Active { get; set; }

    Base[] Children(string? name)
    {
     //   Base[].Parent = this;
    }

    bool TryGetElement(string, Base[])
    {
       
    }

    void SetElement(string, Base[])
    
    string GetLocation();
    Base Resolve()
}

public Base? Child(this Base?  b, string name)
{
    if(b is null) return null;
    return b.TryGetValue(name, bla) ? bla.SingleOrDefault() : null;
}

public T? Child<T>(this Base?, string name) => ...
 


var p = new Patient();

p.Children("active").Resolve();
p.Child<FhirBoolean>("active").Value = true;

p.Active.Resolve();


// Tweede oplossing, zonder slimme setters/getters, uses Navigate() to step to other "world" of navigation.
// Onze oude PocoElementNode
record ScopedNode(Base[] Poco) : ITypedElement
{
    private Name;
    private Parent;
    private Index

    // Hieronder de navigatie
    IEnumerable<ScopedNode> Children()
    this[]
    SetValue()
    
    Resolve()
    GetLocation()

    IEnumerable<ITypedElement> ITypedElement.Children(string name) =>
        this.Children(name);

    bool Equals(object other) => other == this;

    public implicit operator Base(ScopedNode sn) => sn.Poco.SingleOrDefault();
    public explicit operator Base[](ScopedNode sn) => sn.Poco;
}


var x = p.Navigate()["active"] as FhirBoolean;
x.Value = false;


ITypedElement ToTypedELement(this Base b) => b.Navigate();

var p =;

// Add dynamic stuff
dynamic pn = p;
var d = pn.name.given;

@ewoutkramer ewoutkramer reopened this Nov 20, 2024
@Kasdejong
Copy link
Member

record ScopedNode<T>(T[] Poco) : ITypedElement where T : Base
{
    private Name;
    private Parent;
    private Index;
    
    public T? Single => Poco.SingleOrDefault();
        
    IEnumerable<ScopedNode<Base>> Children() => // some impl with GetElemPairs on the poco.
    ScopedNode<Base>? Child(string name) => // some impl with TryGetValue on the poco.
    this[]
    SetValue()
    
    Resolve()
    GetLocation() // remark: the Location property is part of ITE, so we cant make this a method.

    IEnumerable<ITypedElement> ITypedElement.Children(string name) =>
        this.Children(name);

    bool Equals(object other) => other == this;

    public implicit operator Base(ScopedNode sn) => sn.Poco.SingleOrDefault();
    public explicit operator Base[](ScopedNode sn) => sn.Poco;
}

static class ScopedNodeExtensions
{
    public static IEnumerable<ScopedNode<T>> Children<T>(this ScopedNode<Base>? sn, string? name = null) where T : Base 
        => name is null
            ? sn?.Children().OfType<T>() ?? []
            : sn?.Children(name).OfType<T>() ?? [];
    
    public static ScopedNode<T>? Child<T>(this ScopedNode? sn, string name) where T : Base 
        => sn.Child() is {Single is T} node 
            ? node 
            : null;
}

var pat = new Patient();
ScopedNode<HumanName> x = pat.Navigate().Child<HumanName>("name"); // null if multiple or none.
ScopedNode<HumanName> y = pat.Navigate().Children<HumanName>("name"); // empty if none.

HumanName z = pat.Navigate().Child<HumanName>("name").Single; // poco
string s = pat.Navigate().Child("name").Child<FhirString>("given").Value;

// or maybe even:
string s = pat.Navigate().Child<FhirString>("name.given").Value; // Children would have to allow period-delimited names.
``

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants