Пример #1
0
        private async Task NormalSearchProcessing(KeyValuePair <string, StringValues> Parameter)
        {
            List <Bug.Logic.DomainModel.SearchParameter> SearchParameterList = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, this.ResourceContext);

            //Remove modifiers
            var SearchParameterName = Parameter.Key.Split(FhirSearchQuery.TermSearchModifierDelimiter)[0].Trim();

            Bug.Logic.DomainModel.SearchParameter SearchParameter = SearchParameterList.SingleOrDefault(x => x.Name == SearchParameterName);
            if (SearchParameter != null)
            {
                IList <ISearchQueryBase> SearchQueryBaseList = await ISearchQueryFactory.Create(this.ResourceContext, SearchParameter, Parameter);

                foreach (ISearchQueryBase SearchQueryBase in SearchQueryBaseList)
                {
                    if (SearchQueryBase.IsValid)
                    {
                        Outcome !.SearchQueryList.Add(SearchQueryBase);
                    }
                    else
                    {
                        Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(SearchQueryBase.RawValue, SearchQueryBase.InvalidMessage));
                    }
                }
            }
            else
            {
                foreach (var ParamValue in Parameter.Value)
                {
                    string Message = $"The search query parameter: {Parameter.Key} is not supported by this server for the resource type: {ResourceContext.GetCode()}, the whole parameter was : {Parameter.Key}={ParamValue}";
                    Outcome !.UnsupportedSearchQueryList.Add(new InvalidSearchQueryParameter(Parameter.Key, ParamValue, Message));
                }
            }
        }
Пример #2
0
        private async Task SetChain(Bug.Logic.DomainModel.SearchParameter SearchParameter, KeyValuePair <string, StringValues> SingleChainedParameter, bool IsChainedReferance)
        {
            IList <ISearchQueryBase> SearchQueryBaseList = await ISearchQueryFactory.Create(this.ResourceContext, SearchParameter, SingleChainedParameter, IsChainedReferance);

            foreach (ISearchQueryBase SearchQueryBase in SearchQueryBaseList)
            {
                if (SearchQueryBase.IsValid)
                {
                    if (SearchQueryBase.CloneDeep() is ISearchQueryBase SearchQueryBaseClone)
                    {
                        if (ParentChainSearchParameter is null)
                        {
                            ParentChainSearchParameter = SearchQueryBaseClone;
                        }
                        else
                        {
                            if (ParentChainSearchParameter.ChainedSearchParameter is null)
                            {
                                ParentChainSearchParameter.ChainedSearchParameter = SearchQueryBaseClone;
                            }

                            if (PreviousChainSearchParameter is object)
                            {
                                PreviousChainSearchParameter.ChainedSearchParameter = SearchQueryBaseClone;
                            }
                            else
                            {
                                throw new NullReferenceException(nameof(PreviousChainSearchParameter));
                            }
                        }

                        PreviousChainSearchParameter = SearchQueryBaseClone;
                        if (IsChainedReferance)
                        {
                            PreviousChainSearchParameter.Modifier = SearchModifierCode.Type;
                        }
                    }
                    else
                    {
                        throw new InvalidCastException($"Internal Server Error: Unable to cast cloned SearchQueryBase to ISearchQueryBase");
                    }
                }
                else
                {
                    string Message = $"Failed to parse the value of the chain search query. Additional information: {SearchQueryBase.InvalidMessage}";
                    ErrorInSearchParameterProcessing = true;
                    InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                    break;
                }
            }
        }
Пример #3
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);
                }
            }
        }
Пример #4
0
        private async Task <SearchQueryHas?> ProccessHas(HasParameter Has, string RawHasParameter)
        {
            var Result = new SearchQueryHas();

            ResourceType?TargetResourceForSearchQuery = IResourceTypeSupport.GetTypeFromName(Has.TargetResourceForSearchQuery);

            if (TargetResourceForSearchQuery.HasValue && IKnownResource.IsKnownResource(this.FhirVersion, Has.TargetResourceForSearchQuery))
            {
                Result.TargetResourceForSearchQuery = TargetResourceForSearchQuery.Value;
            }
            else
            {
                Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawHasParameter, $"The resource type name of: {Has.TargetResourceForSearchQuery} in a {FhirSearchQuery.TermHas} parameter could not be resolved to a resource type supported by this server for FHIR version {this.FhirVersion.GetCode()}."));
                return(null);
            }

            List <Bug.Logic.DomainModel.SearchParameter> SearchParameterList = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, Result.TargetResourceForSearchQuery);

            Bug.Logic.DomainModel.SearchParameter BackReferenceSearchParameter = SearchParameterList.SingleOrDefault(x => x.Name == Has.BackReferenceSearchParameterName);
            if (BackReferenceSearchParameter is object && BackReferenceSearchParameter.SearchParamTypeId == SearchParamType.Reference)
            {
                Result.BackReferenceSearchParameter = BackReferenceSearchParameter;
            }
            else
            {
                if (BackReferenceSearchParameter is null)
                {
                    string Message = $"The reference search parameter back to the target resource type of: {Has.BackReferenceSearchParameterName} is not a supported search parameter for the resource type {this.ResourceContext.GetCode()} for FHIR version {this.FhirVersion.GetCode()} within this server.";
                    Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawHasParameter, Message));
                    return(null);
                }
            }

            if (Has.ChildHasParameter is object)
            {
                Result.ChildSearchQueryHas = await ProccessHas(Has.ChildHasParameter, RawHasParameter);

                return(Result);
            }
            else
            {
                if (Has.SearchQuery.HasValue)
                {
                    SearchParameterList = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, Result.TargetResourceForSearchQuery);

                    Bug.Logic.DomainModel.SearchParameter SearchParameter = SearchParameterList.SingleOrDefault(x => x.Name == Has.SearchQuery.Value.Key);
                    if (SearchParameter is object)
                    {
                        IList <ISearchQueryBase> SearchQueryBaseList = await ISearchQueryFactory.Create(this.ResourceContext, SearchParameter, Has.SearchQuery.Value);

                        if (SearchQueryBaseList.Count == 1)
                        {
                            if (SearchQueryBaseList[0].IsValid)
                            {
                                Result.SearchQuery = SearchQueryBaseList[0];
                                return(Result);
                            }
                            else
                            {
                                string Message = $"Error parsing the search parameter found at the end of a {FhirSearchQuery.TermHas} query. The search parameter name was : {Has.SearchQuery.Value.Key} with the value of {Has.SearchQuery.Value.Value}. " +
                                                 $"Additional information: {SearchQueryBaseList[0].InvalidMessage}";
                                Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawHasParameter, Message));
                                return(null);
                            }
                        }
                        else
                        {
                            throw new ApplicationException($"The {FhirSearchQuery.TermHas} parameter seems to end with more then one search parameter, this should not be possible.");
                        }
                    }
                    else
                    {
                        string Message = $"The {FhirSearchQuery.TermHas} query finish with a search parameter: {Has.SearchQuery.Value.Key} for the resource type of: {Result.TargetResourceForSearchQuery.GetCode()}. " +
                                         $"However, the search parameter: {Has.SearchQuery.Value.Key} is not a supported search parameter for this resource type in this server for FHIR version {this.FhirVersion.GetCode()}.";
                        Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawHasParameter, Message));
                        return(null);
                    }
                }
                else
                {
                    string Message = $"The {FhirSearchQuery.TermHas} query does not finish with a search parameter and value.";
                    Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawHasParameter, Message));
                    return(null);
                }
            }
        }