1- using System . Text . Json ;
2- using System . Text . RegularExpressions ;
1+ using Hl7 . Fhir . ElementModel ;
2+ using Hl7 . Fhir . Model ;
3+ using Hl7 . FhirPath ;
4+ using System . Text . Json ;
35
46namespace LantanaGroup . Automation . Generation ;
57
@@ -19,7 +21,8 @@ public static HashSet<string> Apply(
1921 HashSet < string > acquiredKeys ,
2022 IReadOnlyList < ( string ResourceType , string ResourceId , string Key , JsonElement Resource ) > patientResourceEntries ,
2123 IReadOnlyList < ( string ResourceType , string ResourceId , string Key , JsonElement Resource ) > ? sharedResourceEntries ,
22- IReadOnlyList < string > ? organizationLocationConditionFhirPaths )
24+ IReadOnlyList < string > ? organizationLocationConditionFhirPaths ,
25+ IReadOnlySet < string > ? cqlFilteredKeys = null )
2326 {
2427 if ( acquiredKeys . Count == 0
2528 || organizationLocationConditionFhirPaths == null
@@ -115,12 +118,13 @@ public static HashSet<string> Apply(
115118 filtered . Add ( key ) ;
116119 }
117120
118- return PruneUnreferencedReferenceResources ( filtered , entriesByKey ) ;
121+ return PruneUnreferencedReferenceResources ( filtered , entriesByKey , cqlFilteredKeys ) ;
119122 }
120123
121124 private static HashSet < string > PruneUnreferencedReferenceResources (
122125 HashSet < string > keptKeys ,
123- Dictionary < string , ResourceEntry > entriesByKey )
126+ Dictionary < string , ResourceEntry > entriesByKey ,
127+ IReadOnlySet < string > ? cqlFilteredKeys )
124128 {
125129 if ( keptKeys . Count == 0 )
126130 return keptKeys ;
@@ -129,6 +133,7 @@ private static HashSet<string> PruneUnreferencedReferenceResources(
129133 // prediction if still referenced by kept resources after org-scope filtering.
130134 var pruneTypes = new HashSet < string > ( StringComparer . OrdinalIgnoreCase )
131135 {
136+ "Location" ,
132137 "Medication" ,
133138 "Specimen" ,
134139 "Device"
@@ -142,6 +147,9 @@ private static HashSet<string> PruneUnreferencedReferenceResources(
142147 var referencedKeys = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
143148 foreach ( var key in keptKeys )
144149 {
150+ if ( cqlFilteredKeys ? . Contains ( key ) == true )
151+ continue ;
152+
145153 if ( ! entriesByKey . TryGetValue ( key , out var entry ) )
146154 continue ;
147155
@@ -196,86 +204,46 @@ private static bool LocationMatchesCondition(JsonElement locationResource, strin
196204 if ( string . IsNullOrWhiteSpace ( fhirPath ) )
197205 return false ;
198206
199- var path = fhirPath . Trim ( ) ;
200- if ( path . StartsWith ( "Location." , StringComparison . OrdinalIgnoreCase ) )
201- path = path [ "Location." . Length ..] ;
202-
203- var system = ExtractQuotedValue ( path , "system" ) ;
204- var value = ExtractQuotedValue ( path , "value" ) ;
205- var code = ExtractQuotedValue ( path , "code" ) ;
206-
207- if ( path . Contains ( "identifier" , StringComparison . OrdinalIgnoreCase )
208- && ! string . IsNullOrWhiteSpace ( system )
209- && locationResource . TryGetProperty ( "identifier" , out var identifiers )
210- && identifiers . ValueKind == JsonValueKind . Array )
207+ try
211208 {
212- foreach ( var identifier in identifiers . EnumerateArray ( ) )
213- {
214- if ( ! identifier . TryGetProperty ( "system" , out var sysProp ) || sysProp . ValueKind != JsonValueKind . String )
215- continue ;
209+ var path = fhirPath . Trim ( ) ;
210+ if ( path . StartsWith ( "Location." , StringComparison . OrdinalIgnoreCase ) )
211+ path = path [ "Location." . Length ..] ;
216212
217- var identifierSystem = sysProp . GetString ( ) ;
218- if ( ! string . Equals ( identifierSystem , system , StringComparison . OrdinalIgnoreCase ) )
219- continue ;
213+ var location = JsonSerializer . Deserialize < Location > (
214+ locationResource . GetRawText ( ) ,
215+ FhirSerializerOptions . ForFhirWithoutValidation ( ) ) ;
220216
221- if ( string . IsNullOrWhiteSpace ( value ) )
222- return true ;
217+ if ( location is null )
218+ return false ;
223219
224- if ( identifier . TryGetProperty ( "value" , out var valueProp )
225- && valueProp . ValueKind == JsonValueKind . String
226- && string . Equals ( valueProp . GetString ( ) , value , StringComparison . OrdinalIgnoreCase ) )
227- {
228- return true ;
229- }
230- }
231- }
220+ var element = location . ToTypedElement ( ) ;
221+ var compiled = new FhirPathCompiler ( ) . Compile ( path ) ;
222+ var results = compiled ( element , new EvaluationContext ( ) ) . ToList ( ) ;
232223
233- if ( path . Contains ( "type.coding" , StringComparison . OrdinalIgnoreCase )
234- && ! string . IsNullOrWhiteSpace ( system )
235- && locationResource . TryGetProperty ( "type" , out var types )
236- && types . ValueKind == JsonValueKind . Array )
237- {
238- foreach ( var type in types . EnumerateArray ( ) )
239- {
240- if ( ! type . TryGetProperty ( "coding" , out var codingArray ) || codingArray . ValueKind != JsonValueKind . Array )
241- continue ;
224+ if ( results . Count == 0 )
225+ return false ;
242226
243- foreach ( var coding in codingArray . EnumerateArray ( ) )
244- {
245- if ( ! coding . TryGetProperty ( "system" , out var sysProp ) || sysProp . ValueKind != JsonValueKind . String )
246- continue ;
227+ if ( results . Count == 1 && results [ 0 ] . Value is bool isMatch )
228+ return isMatch ;
247229
248- if ( ! string . Equals ( sysProp . GetString ( ) , system , StringComparison . OrdinalIgnoreCase ) )
249- continue ;
250-
251- if ( string . IsNullOrWhiteSpace ( code ) )
252- return true ;
253-
254- if ( coding . TryGetProperty ( "code" , out var codeProp )
255- && codeProp . ValueKind == JsonValueKind . String
256- && string . Equals ( codeProp . GetString ( ) , code , StringComparison . OrdinalIgnoreCase ) )
257- {
258- return true ;
259- }
260- }
261- }
230+ return true ;
231+ }
232+ catch
233+ {
234+ return false ;
262235 }
263-
264- return false ;
265- }
266-
267- private static string ? ExtractQuotedValue ( string source , string key )
268- {
269- var match = Regex . Match ( source , $@ "\b{ Regex . Escape ( key ) } \s*=\s*'([^']+)'", RegexOptions . IgnoreCase ) ;
270- return match . Success ? match . Groups [ 1 ] . Value : null ;
271236 }
272237
273238 private static bool TryGetReferencedResourceIds ( JsonElement resource , string resourceType , out List < string > ids )
274239 {
275240 ids = EnumerateReferences ( resource )
276- . Where ( reference => reference . StartsWith ( resourceType + "/" , StringComparison . OrdinalIgnoreCase ) )
277- . Select ( reference => reference [ ( resourceType . Length + 1 ) ..] )
278- . Where ( id => ! string . IsNullOrWhiteSpace ( id ) )
241+ . Select ( reference => TryParseReference ( reference , out var type , out var id )
242+ ? ( Type : type , Id : id )
243+ : ( Type : string . Empty , Id : string . Empty ) )
244+ . Where ( parsed => string . Equals ( parsed . Type , resourceType , StringComparison . OrdinalIgnoreCase )
245+ && ! string . IsNullOrWhiteSpace ( parsed . Id ) )
246+ . Select ( parsed => parsed . Id )
279247 . Distinct ( StringComparer . OrdinalIgnoreCase )
280248 . ToList ( ) ;
281249
0 commit comments