private IReadOnlyList <ISearchValue> ExtractSearchValues( string searchParameterDefinitionUrl, SearchParamType?searchParameterType, IReadOnlyList <string> allowedReferenceResourceTypes, ITypedElement element, string fhirPathExpression, EvaluationContext context) { Debug.Assert(searchParameterType != SearchParamType.Composite, "The search parameter must be non-composite."); var results = new List <ISearchValue>(); // For simple value type, we can parse the expression directly. IEnumerable <ITypedElement> extractedValues = Enumerable.Empty <ITypedElement>(); try { extractedValues = element.Select(fhirPathExpression, context); } catch (Exception ex) { _logger.LogWarning( ex, "Failed to extract the values using '{FhirPathExpression}' against '{ElementType}'.", fhirPathExpression, element.GetType()); } Debug.Assert(extractedValues != null, "The extracted values should not be null."); // If there is target set, then filter the extracted values to only those types. if (searchParameterType == SearchParamType.Reference && allowedReferenceResourceTypes?.Count > 0) { List <string> targetResourceTypes = _targetTypesLookup.GetOrAdd(searchParameterDefinitionUrl, _ => { return(allowedReferenceResourceTypes.Select(t => t.ToString()).ToList()); }); // TODO: The expression for reference search parameters in STU3 has issues. // The reference search parameter could be pointing to an element that can be multiple types. For example, // the Appointment.participant.actor can be type of Patient, Practitioner, Related Person, Location, and so on. // Some search parameter could refer to this property but restrict to certain types. For example, // Appointment's location search parameter is returned only when Appointment.participant.actor is Location element. // The STU3 expressions don't have this restriction so everything is being returned. This is addressed in R4 release (see // http://community.fhir.org/t/expression-seems-incorrect-for-reference-search-parameter-thats-only-applicable-to-certain-types/916/2). // Therefore, for now, we will need to compare the reference value itself (which can be internal or external references), and restrict // the values ourselves. extractedValues = extractedValues.Where(ev => { if (ev.InstanceType.Equals("ResourceReference", StringComparison.OrdinalIgnoreCase)) { return(ev.Scalar("reference") is string rr && targetResourceTypes.Any(trt => rr.Contains(trt, StringComparison.Ordinal))); } return(true); }); } foreach (var extractedValue in extractedValues) { if (!_fhirElementTypeConverterManager.TryGetConverter(extractedValue.InstanceType, GetSearchValueTypeForSearchParamType(searchParameterType), out ITypedElementToSearchValueConverter converter)) { _logger.LogWarning( "The FHIR element '{ElementType}' is not supported.", extractedValue.InstanceType); continue; } IEnumerable <ISearchValue> searchValues = converter.ConvertTo(extractedValue); if (searchValues != null) { if (searchParameterType == SearchParamType.Reference && allowedReferenceResourceTypes?.Count == 1) { // For references, if the type is not specified in the reference string, we can set the type on the search value because // in this case it can only be of one type. string singleAllowedResourceType = allowedReferenceResourceTypes[0]; foreach (ISearchValue searchValue in searchValues) { if (searchValue is ReferenceSearchValue rsr && string.IsNullOrEmpty(rsr.ResourceType)) { results.Add(new ReferenceSearchValue(rsr.Kind, rsr.BaseUri, singleAllowedResourceType, rsr.ResourceId)); } else { results.Add(searchValue); } } }