Esempio n. 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));
                }
            }
        }
Esempio n. 2
0
        public async Task <ChainQueryProcessingOutcome> Process(FhirVersion fhirVersion, ResourceType resourceContext, KeyValuePair <string, StringValues> Parameter)
        {
            this.FhirVersion     = fhirVersion;
            this.ResourceContext = resourceContext;

            var Outcome = new ChainQueryProcessingOutcome();

            this.RawParameter = $"{Parameter.Key}={Parameter.Value}";
            string[] ChaimedParameterSplit = Parameter.Key.Split(FhirSearchQuery.TermChainDelimiter);

            for (int i = 0; i < ChaimedParameterSplit.Length; i++)
            {
                //Each segment in the chain is a IsChainedReferance except the last segment in the chain which has the value.
                bool IsChainedReferance = !(i == ChaimedParameterSplit.Length - 1);
                Bug.Logic.DomainModel.SearchParameter?SearchParameter = null;
                string       ParameterNameWithModifier = Parameter.Key.Split(FhirSearchQuery.TermChainDelimiter)[i];
                StringValues ParameterValue            = string.Empty;
                //There is no valid Value for a chained reference parameter unless it is the last in a series
                //of chains, so don't set it unless this is the last parameter in the whole chain.
                if (i == ChaimedParameterSplit.Count() - 1)
                {
                    ParameterValue = Parameter.Value;
                }

                var SingleChainedParameter = new KeyValuePair <string, StringValues>(ParameterNameWithModifier, ParameterValue);

                string ParameterName = string.Empty;
                string ParameterModifierTypedResource = string.Empty;

                //Check for and deal with modifiers e.g 'Patient' in the example: subject:Patient.family=millar
                if (ParameterNameWithModifier.Contains(FhirSearchQuery.TermSearchModifierDelimiter))
                {
                    string[] ParameterModifierSplit = ParameterNameWithModifier.Split(FhirSearchQuery.TermSearchModifierDelimiter);
                    ParameterName = ParameterModifierSplit[0].Trim();

                    if (ParameterModifierSplit.Length > 1)
                    {
                        ResourceType?ModifierResourceType = IResourceTypeSupport.GetTypeFromName(ParameterModifierSplit[1].Trim());
                        if (ModifierResourceType.HasValue && IKnownResource.IsKnownResource(this.FhirVersion, ParameterModifierSplit[1].Trim()))
                        {
                            ParameterModifierTypedResource = ParameterModifierSplit[1].Trim();
                        }
                        else
                        {
                            ErrorInSearchParameterProcessing = true;
                            //If the Parent is ok then we can assume that any error further down the chain is an invalid search term rather than an unsupported term
                            //as it is clear that this is a FHIR search term and not some other search parameter forgen to FHIR
                            if (ParentChainSearchParameter is object)
                            {
                                InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, $"The resource type modifier: {ParameterModifierSplit[1].Trim()} within the chained search query of {this.RawParameter} is not a known resource for FHIR version: {this.FhirVersion.GetCode()} within this server"));
                            }
                            else
                            {
                                //Here we are only looking up the ParameterName to check weather this should be an unsupported parameter or an invalid parameter.
                                //If we know the ParameterName then it is invalid whereas if we don't then it is unsupported and both are not known.
                                List <Bug.Logic.DomainModel.SearchParameter> TempSearchParameterList = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, this.ResourceContext);

                                var TempSearchParameter = TempSearchParameterList.SingleOrDefault(x => x.Name == ParameterName);
                                if (TempSearchParameter is null)
                                {
                                    string Message = $"Both the search parameter name: {ParameterName} for the resource type: {this.ResourceContext.GetCode()} and its resource type modifier: {ParameterModifierSplit[1].Trim()} within the chained search query of {this.RawParameter} are unsupported within this server for FHIR version: {this.FhirVersion.GetCode()}.";
                                    UnsupportedSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, Message));
                                }
                                else
                                {
                                    InvalidSearchQueryParameterList.Add(new InvalidSearchQueryParameter(this.RawParameter, $"The resource type modifier: {ParameterModifierSplit[1].Trim()} within the chained search query of {this.RawParameter} is not a known resource type for this server and FHIR version {this.FhirVersion.GetCode()}."));
                                }
                            }
                            break;
                        }
                    }
                }
                else
                {
                    ParameterName = ParameterNameWithModifier;
                }

                SearchParameter = await GetSearchParameter(ParameterName);

                //We have no resolved a SearchParameter so we parse the value if it is the end of the chain, see IsChainedReferance
                //or we are only parsing as a chain segment with no end value
                if (SearchParameter != null)
                {
                    //If this is the last parameter in the chain then treat is as not a chain, otherwise treat as a chain
                    await SetChain(SearchParameter, SingleChainedParameter, IsChainedReferance);
                }
                else
                {
                    ErrorInSearchParameterProcessing = true;
                    if (this.InvalidSearchQueryParameterList.Count == 0 && this.UnsupportedSearchQueryParameterList.Count == 0)
                    {
                        throw new ApplicationException("Internal Server Error: When processing a chain search query we failed to resolve a search parameter for the query string however their are " +
                                                       $"no items found in either the {nameof(InvalidSearchQueryParameterList)} or the {nameof(UnsupportedSearchQueryParameterList)}. This is an error in its self.");
                    }
                    break;
                }
            }

            //End of Chain loop
            if (!ErrorInSearchParameterProcessing)
            {
                if (ParentChainSearchParameter is object)
                {
                    Outcome !.SearchQueryList.Add(ParentChainSearchParameter);
                    return(Outcome);
                }
                else
                {
                    throw new NullReferenceException(nameof(PreviousChainSearchParameter));
                }
            }
            else
            {
                InvalidSearchQueryParameterList.ForEach(x => Outcome !.InvalidSearchQueryList.Add(x));
                UnsupportedSearchQueryParameterList.ForEach(x => Outcome !.UnsupportedSearchQueryList.Add(x));
                return(Outcome);
            }
        }
Esempio n. 3
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);
                }
            }
        }
Esempio n. 4
0
        private async Task ProcessIncludeSearchParameters(IList <IncludeParameter> IncludeList)
        {
            if (IncludeList != null)
            {
                foreach (var Include in IncludeList)
                {
                    bool   ParseOk      = true;
                    string RawParameter = $"{IncludeType.Include.GetCode()}:{FhirSearchQuery.TermIncludeRecurse}={Include.Value}";
                    //if (this.FhirVersion == FhirVersion.Stu3 && Include.Recurse)
                    //{
                    //  if (Include.Type == IncludeType.Include)
                    //  {
                    //    string IncorrectRawParameter = $"{IncludeType.Include.GetCode()}:{FhirSearchQuery.TermIncludeRecurse}={Include.Value}";
                    //    string CorrectRawParameter = $"{IncludeType.Include.GetCode()}:{FhirSearchQuery.TermIncludeRecurse}={Include.Value}";
                    //    string Message = $"The Include type query of: {IncorrectRawParameter} is using the FHIR R4 {FhirSearchQuery.TermIncludeRecurse} yet this is a FHIR Stu3 search which must use {FhirSearchQuery.TermIncludeIterate} to achieve the same effect. " +
                    //      $"Please update your query to use the FHIR Stu3 for such as: {CorrectRawParameter} ";
                    //    Outcome!.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(IncorrectRawParameter, Message));
                    //    ParseOk = false;
                    //  }
                    //}
                    //else if (this.FhirVersion == FhirVersion.R4 && Include.Iterate)
                    //{
                    //  string IncorrectRawParameter = $"{IncludeType.Include.GetCode()}:{FhirSearchQuery.TermIncludeIterate}={Include.Value}";
                    //  string CorrectRawParameter = $"{IncludeType.Include.GetCode()}:{FhirSearchQuery.TermIncludeRecurse}={Include.Value}";
                    //  string Message = $"The Include type query of: {IncorrectRawParameter} is using the FHIR Stu3 {FhirSearchQuery.TermIncludeIterate} yet this is a FHIR R4 search which must use {FhirSearchQuery.TermIncludeRecurse} to achieve the same effect. " +
                    //    $"Please update your query to use the FHIR R4 term such as: {CorrectRawParameter} ";
                    //  Outcome!.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(IncorrectRawParameter, Message));
                    //  ParseOk = false;
                    //}


                    SearchQueryInclude SearchParameterInclude = new SearchQueryInclude(Include.Type)
                    {
                        IsIterate = Include.Iterate,
                        IsRecurse = Include.Recurse
                    };

                    var          valueSplitArray     = Include.Value.Split(FhirSearchQuery.TermSearchModifierDelimiter);
                    string       ScourceResource     = valueSplitArray[0].Trim();
                    ResourceType?ScourceResourceType = IResourceTypeSupport.GetTypeFromName(ScourceResource);
                    if (ScourceResourceType.HasValue && IKnownResource.IsKnownResource(this.FhirVersion, ScourceResource))
                    {
                        SearchParameterInclude.SourceResourceType = ScourceResourceType.Value;
                    }
                    else
                    {
                        ParseOk = false;
                        Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawParameter, $"The source resource type of: {ScourceResource} for the {Include.Type.GetCode()} parameter is not recognized as a FHIR {this.FhirVersion.GetCode()} resource type by this server."));
                        break;
                    }

                    if (valueSplitArray.Count() > 2)
                    {
                        string TargetResourceTypeString = valueSplitArray[2].Trim();
                        //checked we have a something if we don't then that is fine just a syntax error of the callers part
                        //i.e _includes=Patient:subject:
                        if (!string.IsNullOrWhiteSpace(TargetResourceTypeString))
                        {
                            ResourceType?TargetResourceType = IResourceTypeSupport.GetTypeFromName(TargetResourceTypeString);
                            if (TargetResourceType.HasValue && IKnownResource.IsKnownResource(this.FhirVersion, TargetResourceTypeString))
                            {
                                SearchParameterInclude.SearchParameterTargetResourceType = TargetResourceType.Value;
                            }
                            else
                            {
                                ParseOk = false;
                                Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawParameter, $"The target resource type of : {TargetResourceTypeString} for the {Include.Type.GetCode()} parameter is not recognized as a FHIR {this.FhirVersion.GetCode()} resource type by this server."));
                                break;
                            }
                        }
                    }

                    if (valueSplitArray.Count() > 1)
                    {
                        string SearchTerm = valueSplitArray[1].Trim();
                        List <DomainModel.SearchParameter> SearchParameterList = await ISearchParameterCache.GetForIndexingAsync(this.FhirVersion, SearchParameterInclude.SourceResourceType.Value);

                        if (SearchTerm == "*")
                        {
                            if (SearchParameterInclude.SearchParameterTargetResourceType is object)
                            {
                                SearchParameterInclude.SearchParameterList = SearchParameterList.Where(x => x.SearchParamTypeId == SearchParamType.Reference && x.TargetResourceTypeList.Any(v => v.ResourceTypeId == SearchParameterInclude.SearchParameterTargetResourceType.Value)).ToList();
                            }
                            else
                            {
                                SearchParameterInclude.SearchParameterList = SearchParameterList.Where(x => x.SearchParamTypeId == SearchParamType.Reference).ToList();
                            }
                        }
                        else
                        {
                            DomainModel.SearchParameter SearchParameter = SearchParameterList.SingleOrDefault(x => x.Name == SearchTerm);
                            if (SearchParameter != null)
                            {
                                if (SearchParameter.SearchParamTypeId == SearchParamType.Reference)
                                {
                                    if (SearchParameter.TargetResourceTypeList != null && SearchParameterInclude.SearchParameterTargetResourceType.HasValue)
                                    {
                                        if (SearchParameter.TargetResourceTypeList.SingleOrDefault(x => x.ResourceTypeId == SearchParameterInclude.SearchParameterTargetResourceType.Value) == null)
                                        {
                                            ParseOk = false;
                                            string Message = $"The target Resource '{SearchParameterInclude.SearchParameterTargetResourceType.Value.GetCode()}' of the _includes parameter is not recognized for the source '{SearchParameterInclude.SourceResourceType.GetCode()}' Resource's search parameter {SearchParameter.Name}.";
                                            Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawParameter, Message));
                                            break;
                                        }
                                    }
                                    SearchParameterInclude.SearchParameterList = new List <DomainModel.SearchParameter>
                                    {
                                        SearchParameter
                                    };
                                }
                                else
                                {
                                    ParseOk = false;
                                    string Message = $"The source Resource '{SearchParameterInclude.SourceResourceType.GetCode()}' search parameter '{SearchParameter.Name}' of the _includes parameter is not of search parameter of type Reference, found search parameter type of '{SearchParameter.SearchParamTypeId.GetCode()}'.";
                                    Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawParameter, Message));
                                    break;
                                }
                            }
                            else
                            {
                                ParseOk = false;
                                string Message = $"The source Resource '{SearchParameterInclude.SourceResourceType.GetCode()}' search parameter '{SearchTerm}' is not a valid search parameter for the source Resource type.";
                                Outcome !.InvalidSearchQueryList.Add(new InvalidSearchQueryParameter(RawParameter, Message));
                                break;
                            }
                        }
                    }

                    //All Ok so add as valid include
                    if (ParseOk)
                    {
                        Outcome !.IncludeList.Add(SearchParameterInclude);
                    }
                }
            }
        }