Skip to content

Commit

Permalink
Merge pull request #2845 from FirelyTeam/feature/scopednode-cache-dic…
Browse files Browse the repository at this point in the history
…tionaries

Scoped node cache overhaul
  • Loading branch information
ewoutkramer authored Sep 4, 2024
2 parents 4c38d9a + 570c97b commit f8ef048
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 24 deletions.
33 changes: 33 additions & 0 deletions src/Hl7.Fhir.Base/ElementModel/ReferencedResourceCache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Hl7.Fhir.ElementModel;

#nullable enable

internal class ReferencedResourceCache : IEnumerable<ScopedNode.BundledResource>
{
private Dictionary<string, ScopedNode?> _items;

public ReferencedResourceCache(IEnumerable<KeyValuePair<string, ScopedNode?>> items)
{
_items = new Dictionary<string, ScopedNode?>();
foreach (var item in items)
{
_items.Add(item.Key, item.Value);
}
}

internal IEnumerable<ScopedNode> Resources => _items.Values.OfType<ScopedNode>();

internal ScopedNode? ResolveReference(string reference)
{
return _items.TryGetValue(reference, out var node) ? node : null;
}

public IEnumerator<ScopedNode.BundledResource> GetEnumerator() => _items.Select(i => new ScopedNode.BundledResource(i.Key, i.Value)).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

#nullable restore
66 changes: 50 additions & 16 deletions src/Hl7.Fhir.Base/ElementModel/ScopedNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Hl7.Fhir.Specification;
using Hl7.Fhir.Utility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

Expand All @@ -23,8 +24,8 @@ private class Cache
public readonly object _lock = new();

public string? Id;
public IEnumerable<ScopedNode>? ContainedResources;
public IEnumerable<BundledResource>? BundledResources;
public ReferencedResourceCache? ContainedResources;
public ReferencedResourceCache? BundledResources;

public string? InstanceUri;
}
Expand Down Expand Up @@ -166,20 +167,51 @@ public IEnumerable<ScopedNode> ParentResources()
/// </summary>
public IEnumerable<ScopedNode> ContainedResources()
{
if (_cache.ContainedResources == null)
if (_cache.ContainedResources != null) return _cache.ContainedResources.Resources;

if (AtResource)
{
_cache.ContainedResources = AtResource ?
this.Children("contained").Cast<ScopedNode>() :
Enumerable.Empty<ScopedNode>();
var referenceEntryPairs = from contained in this.Children("contained")
let id = contained.Children("id").FirstOrDefault()?.Value as string
let resource = contained as ScopedNode
select new KeyValuePair<string, ScopedNode?>(id, resource);
_cache.ContainedResources = new ReferencedResourceCache(referenceEntryPairs);
}
else
_cache.ContainedResources = new ReferencedResourceCache([]);

return _cache.ContainedResources.Resources;
}

internal ReferencedResourceCache ContainedResourcesWithId()
{
if (_cache.ContainedResources != null) return _cache.ContainedResources;

if (AtResource)
{
var referenceEntryPairs = from contained in this.Children("contained")
let id = $"#{contained.Children("id").FirstOrDefault()?.Value as string}"
let resource = contained as ScopedNode
select new KeyValuePair<string, ScopedNode?>(id, resource);
_cache.ContainedResources = new ReferencedResourceCache(referenceEntryPairs);
}
else
_cache.ContainedResources = new ReferencedResourceCache([]);

return _cache.ContainedResources;
}

/// <summary>
/// A tuple of a bundled resource plus its Bundle.entry.fullUrl property.
/// </summary>
public class BundledResource
public class BundledResource()
{
public BundledResource(string? fullUrl, ScopedNode? resource) : this()
{
FullUrl = fullUrl;
Resource = resource;
}

public string? FullUrl;
public ScopedNode? Resource;
}
Expand All @@ -189,21 +221,23 @@ public class BundledResource
/// </summary>
public IEnumerable<BundledResource> BundledResources()
{
if (_cache.BundledResources == null)
if (_cache.BundledResources != null) return _cache.BundledResources;

if (InstanceType == "Bundle")
{
if (InstanceType == "Bundle")
_cache.BundledResources = from e in this.Children("entry")
let fullUrl = e.Children("fullUrl").FirstOrDefault()?.Value as string
let resource = e.Children("resource").FirstOrDefault() as ScopedNode
select new BundledResource { FullUrl = fullUrl, Resource = resource };
else
_cache.BundledResources = Enumerable.Empty<BundledResource>();
var referenceEntryPairs = from e in this.Children("entry")
let fullUrl = e.Children("fullUrl").FirstOrDefault()?.Value as string
let resource = e.Children("resource").FirstOrDefault() as ScopedNode
select new KeyValuePair<string, ScopedNode>(fullUrl, resource);
_cache.BundledResources = new ReferencedResourceCache(referenceEntryPairs);
}

else
_cache.BundledResources = new ReferencedResourceCache([]);

return _cache.BundledResources;
}


private readonly string? _fullUrl = null;

/// <summary>
Expand Down
15 changes: 7 additions & 8 deletions src/Hl7.Fhir.Base/ElementModel/ScopedNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

using Hl7.Fhir.Rest;
using Hl7.Fhir.Support.Poco;
using Hl7.FhirPath.Sprache;
using System;
using System.Linq;

Expand Down Expand Up @@ -110,15 +111,13 @@ public static string MakeAbsolute(this ScopedNode node, string reference) =>
{
if (parent.InstanceType == FhirTypeConstants.BUNDLE)
{
var result = parent.BundledResources().FirstOrDefault(br => br.FullUrl == url)?.Resource;
if (result != null) return result;
}
else
{
if (parent.Id() == url) return parent;
var result = parent.ContainedResources().FirstOrDefault(cr => cr.Id() == url);
if (result != null) return result;
return ((ReferencedResourceCache)parent.BundledResources()).ResolveReference(url); // safe cast but we cannot change the signature
}

if (parent.Id() == url)
return parent;
if (parent.ContainedResourcesWithId().ResolveReference(url) is { } resource) // safe cast but we cannot change the signature
return resource;
}

return null;
Expand Down

0 comments on commit f8ef048

Please sign in to comment.