Esempio n. 1
0
        private async Task <Bug.Logic.DomainModel.SearchParameter?> GetSearchParameter(string parameterName)
        {
            Bug.Logic.DomainModel.SearchParameter        SearchParameter;
            List <Bug.Logic.DomainModel.SearchParameter> SearchParameterList = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, this.ResourceContext);

            //Here we go through a series of ways to locate the SearchParameter for each segment of the chain query
            if (PreviousChainSearchParameter is null)
            {
                //If there is no previous then we look through the search parameter for the root resource type stored in this.ResourceContext
                SearchParameter = SearchParameterList.SingleOrDefault(x => x.Name == parameterName);
                if (SearchParameter is null)
                {
                    ErrorInSearchParameterProcessing = true;
                    UnsupportedSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, $"The resource search parameter name of: {parameterName} within the chained search query of: {this.RawParameter} is not a known search parameter for the resource: {this.ResourceContext} for this server in FHIR version: {this.FhirVersion.GetCode()}"));
                    return(null);
                }
                else
                {
                    return(SearchParameter);
                }
            }
            else
            {
                //Here we are using the PreviousChainSearchParameter's TypeModifierResource as the context to find the search parameter
                if (!PreviousChainSearchParameter.TypeModifierResource.HasValue)
                {
                    //If there is no TypeModifierResource on the previous then we look at how many it supports and if only one we can use that.
                    if (PreviousChainSearchParameter.TargetResourceTypeList.Count == 1)
                    {
                        PreviousChainSearchParameter.TypeModifierResource = PreviousChainSearchParameter.TargetResourceTypeList.ToArray()[0].ResourceTypeId;
                        List <Bug.Logic.DomainModel.SearchParameter> SearchParametersListForTarget = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, PreviousChainSearchParameter.TargetResourceTypeList.ToArray()[0].ResourceTypeId);

                        Bug.Logic.DomainModel.SearchParameter SearchParameterForTarget = SearchParametersListForTarget.SingleOrDefault(x => x.Name == parameterName);
                        if (SearchParameterForTarget is null)
                        {
                            string Message = $"Unable to locate the search parameter named: {parameterName} for the resource type: {PreviousChainSearchParameter.TypeModifierResource} for FHIR version: {this.FhirVersion.GetCode()} within the chain search query of: {this.RawParameter}";
                            ErrorInSearchParameterProcessing = true;
                            InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                            return(null);
                        }
                        else
                        {
                            SearchParameter = SearchParameterForTarget;
                            return(SearchParameter);
                        }
                    }
                    else
                    {
                        //If more than one then we search for the given search parameter name among all  resource types supported for the PreviousChainSearchParameter
                        Dictionary <ResourceType, Bug.Logic.DomainModel.SearchParameter> MultiChainedSearchParameter = new Dictionary <ResourceType, DomainModel.SearchParameter>();
                        foreach (var TargetResourceType in PreviousChainSearchParameter.TargetResourceTypeList)
                        {
                            List <Bug.Logic.DomainModel.SearchParameter> SearchParametersListForTarget = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, TargetResourceType.ResourceTypeId);

                            Bug.Logic.DomainModel.SearchParameter SearchParameterForTarget = SearchParametersListForTarget.SingleOrDefault(x => x.Name == parameterName);
                            if (SearchParameterForTarget != null)
                            {
                                MultiChainedSearchParameter.Add(TargetResourceType.ResourceTypeId, SearchParameterForTarget);
                            }
                        }
                        if (MultiChainedSearchParameter.Count() == 1)
                        {
                            //If this resolves to only one found then we use it
                            PreviousChainSearchParameter.TypeModifierResource = MultiChainedSearchParameter.First().Key;
                            SearchParameter = MultiChainedSearchParameter.First().Value;
                            return(SearchParameter);
                        }
                        else
                        {
                            if (MultiChainedSearchParameter.Count > 1)
                            {
                                //We still have many to choose from so it cannot be resolved. The user need to specify the ResourceType with the Type modifier on the search parameter query e.g subject:Patient.family
                                string RefResources = string.Empty;
                                foreach (var DicItem in MultiChainedSearchParameter)
                                {
                                    RefResources += ", " + DicItem.Key.GetCode();
                                }
                                string ResourceName = this.ResourceContext.GetCode();
                                string Message      = string.Empty;
                                Message  = $"The chained search parameter '{this.RawParameter}' is ambiguous. ";
                                Message += $"Additional information: ";
                                Message += $"The search parameter '{parameterName}' could be a search parameter for any of the following resource types ({RefResources.TrimStart(',').Trim()}). ";
                                Message += $"To correct this you must prefix the search parameter with a Type modifier, for example: '{PreviousChainSearchParameter.Name}:{MultiChainedSearchParameter.First().Key.GetCode()}.{MultiChainedSearchParameter.First().Value.Name}' ";
                                Message += $"If the '{MultiChainedSearchParameter.First().Key.GetCode()}' resource was the intended reference for the search parameter '{MultiChainedSearchParameter.First().Value.Name}'.";
                                ErrorInSearchParameterProcessing = true;
                                InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                                return(null);
                            }
                            else
                            {
                                //We have found zero matches for this search parameter name from the previous allowed resource types, so the search parameter name is possibly wrong.
                                string TargetResourceTypes = string.Empty;
                                foreach (var TargetResourceType in PreviousChainSearchParameter.TargetResourceTypeList)
                                {
                                    TargetResourceTypes += ", " + TargetResourceType.ResourceTypeId.GetCode();
                                }
                                string ResourceName = this.ResourceContext.GetCode();
                                string Message      = string.Empty;
                                Message  = $"The chained search parameter '{this.RawParameter}' is unresolvable. ";
                                Message += $"Additional information: ";
                                Message += $"The search parameter: {parameterName} should be a search parameter for any of the following resource types ({TargetResourceTypes.TrimStart(',').Trim()}) as resolved from the previous link in the chain: {PreviousChainSearchParameter.Name}. ";
                                Message += $"To correct this you must specify a search parameter here that is supported by those resource types. ";
                                Message += $"Please review your chained search query and specifically the use of the search parameter: {parameterName}'";
                                ErrorInSearchParameterProcessing = true;
                                InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                                return(null);
                            }
                        }
                    }
                }
                else if (CheckModifierTypeResourceValidForSearchParameter(PreviousChainSearchParameter.TypeModifierResource.Value, PreviousChainSearchParameter.TargetResourceTypeList))
                {
                    //PreviousChainSearchParameter.TypeModifierResource = PreviousChainSearchParameter.TypeModifierResource;
                    //Double check the final Type modifier resource resolved is valid for the previous search parameter, the user could have got it wrong in the query.
                    ResourceType ResourceTypeTest        = PreviousChainSearchParameter.TypeModifierResource.Value;
                    FhirVersion  FhirVersionTest         = this.FhirVersion;
                    var          TempSearchParameterList = await this.ISearchParameterCache.GetForIndexingAsync(FhirVersionTest, ResourceTypeTest);

                    SearchParameter = TempSearchParameterList.SingleOrDefault(x => x.Name == parameterName);
                    if (SearchParameter is object)
                    {
                        return(SearchParameter);
                    }
                    else
                    {
                        string ResourceName = ResourceTypeTest.GetCode();
                        string Message      = $"The chained search query part: {parameterName} is not a supported search parameter name for the resource type: {ResourceName} for this server in FHIR version {this.FhirVersion.GetCode()}. ";
                        Message += $"Additional information: ";
                        Message += $"This search parameter was a chained search parameter. The part that was not recognized was: {parameterName}.";
                        ErrorInSearchParameterProcessing = true;
                        InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                        return(null);
                    }
                }
                else
                {
                    //The modifier target resource provided is not valid for the previous reference, e.g subject:DiagnosticReport.family=millar
                    string ResourceName = this.ResourceContext.GetCode();
                    string Message      = $"The search parameter '{parameterName}' is not supported by this server for the resource type '{ResourceName}'. ";
                    Message += $"Additional information: ";
                    Message += $"This search parameter was a chained search parameter. The part that was not recognized was '{PreviousChainSearchParameter.Name}.{parameterName}', The search parameter modifier given '{PreviousChainSearchParameter.TypeModifierResource}' is not valid for the search parameter {PreviousChainSearchParameter.Name}. ";
                    ErrorInSearchParameterProcessing = true;
                    InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                    return(null);
                }
            }
        }
Esempio n. 2
0
        public void IncludeQueryPositive(FhirVersion fhirVersion, ResourceType resourceContext, IncludeType parameterInclude, string isRecurseIterate, ResourceType sourceResource, string searchParameterName, ResourceType?modifierResource)
        {
            //Prepare
            SearchQueryService SearchQueryService = SetupSearchQueryService();
            Dictionary <string, StringValues> QueryDictonary;

            if (!string.IsNullOrWhiteSpace(isRecurseIterate))
            {
                if (modifierResource.HasValue)
                {
                    QueryDictonary = new Dictionary <string, StringValues>
                    {
                        { $"{parameterInclude.GetCode()}:{isRecurseIterate}", new StringValues($"{sourceResource.GetCode()}:{searchParameterName}:{modifierResource.GetCode()}") },
                    };
                }
                else
                {
                    QueryDictonary = new Dictionary <string, StringValues>
                    {
                        { $"{parameterInclude.GetCode()}:{isRecurseIterate}", new StringValues($"{sourceResource.GetCode()}:{searchParameterName}") },
                    };
                }
            }
            else
            {
                if (modifierResource.HasValue)
                {
                    QueryDictonary = new Dictionary <string, StringValues>
                    {
                        { $"{parameterInclude.GetCode()}", new StringValues($"{sourceResource.GetCode()}:{searchParameterName}:{modifierResource.GetCode()}") },
                    };
                }
                else
                {
                    QueryDictonary = new Dictionary <string, StringValues>
                    {
                        { $"{parameterInclude.GetCode()}", new StringValues($"{sourceResource.GetCode()}:{searchParameterName}") },
                    };
                }
            }

            FhirSearchQuery FhirSearchQuery = new FhirSearchQuery();

            FhirSearchQuery.Parse(QueryDictonary);

            //Act
            ISerachQueryServiceOutcome Outcome = SearchQueryService.Process(fhirVersion, resourceContext, FhirSearchQuery).Result;

            //Assert
            Assert.NotNull(Outcome);
            Assert.Equal(0, Outcome.InvalidSearchQueryList.Count);
            Assert.Null(Outcome.CountRequested);
            Assert.Equal(0, Outcome.SearchQueryList.Count);
            Assert.Equal(Common.Enums.ResourceType.Observation, Outcome.ResourceContext);
            Assert.Equal(1, Outcome.IncludeList.Count);

            var IncludeItem = Outcome.IncludeList[0];

            if (isRecurseIterate == "recurse")
            {
                Assert.True(IncludeItem.IsRecurse);
                Assert.True(IncludeItem.IsRecurseIterate);
            }
            else
            {
                Assert.False(IncludeItem.IsRecurse);
            }
            if (isRecurseIterate == "iterate")
            {
                Assert.True(IncludeItem.IsIterate);
                Assert.True(IncludeItem.IsRecurseIterate);
            }
            else
            {
                Assert.False(IncludeItem.IsIterate);
            }
            Assert.Equal(parameterInclude, IncludeItem.Type);
            Assert.Equal(sourceResource, IncludeItem.SourceResourceType);
            if (modifierResource.HasValue)
            {
                Assert.Equal(modifierResource, IncludeItem.SearchParameterTargetResourceType);
            }
            else
            {
                Assert.Null(IncludeItem.SearchParameterTargetResourceType);
            }

            Assert.Single(IncludeItem.SearchParameterList);
            var SearchParameter = IncludeItem.SearchParameterList[0];

            Assert.Equal(searchParameterName, SearchParameter.Name);
        }