private void ParseHasParameter(KeyValuePair <string, StringValues> Item) { //GET [base]/Patient?_has:Observation:patient:code=1234-5 //or //GET [base]/Patient?_has:Observation:patient:_has:AuditEvent:entity:user=MyUserId if (Item.Key.StartsWith($"{TermHas}{TermSearchModifierDelimiter}")) { this.QueryItemProcessed = true; var HasSplit = Item.Key.Split(TermHas); FhirSearchQuery.HasParameter?RootHasParameter = null; FhirSearchQuery.HasParameter?PreviousHasParameter = null; for (int i = 1; i < HasSplit.Length; i++) { var ModifierSplit = HasSplit[i].Split(TermSearchModifierDelimiter); if (ModifierSplit.Length == 4 && RootHasParameter is null) { if (ModifierSplit[3] == string.Empty) { RootHasParameter = new HasParameter(ModifierSplit[1], ModifierSplit[2]); RootHasParameter.RawHasParameter = $"{Item.Key}={ Item.Value}"; PreviousHasParameter = RootHasParameter; } else { RootHasParameter = new HasParameter(ModifierSplit[1], ModifierSplit[2]); RootHasParameter.SearchQuery = new KeyValuePair <string, StringValues>(ModifierSplit[3], Item.Value); RootHasParameter.RawHasParameter = $"{Item.Key}={ Item.Value}"; PreviousHasParameter = RootHasParameter; } } else if (ModifierSplit.Length == 4 && RootHasParameter is object) { if (ModifierSplit[3] == string.Empty) { PreviousHasParameter !.ChildHasParameter = new HasParameter(ModifierSplit[1], ModifierSplit[2]); PreviousHasParameter = PreviousHasParameter !.ChildHasParameter; } else { PreviousHasParameter !.ChildHasParameter = new HasParameter(ModifierSplit[1], ModifierSplit[2]); PreviousHasParameter !.ChildHasParameter.SearchQuery = new KeyValuePair <string, StringValues>(ModifierSplit[3], Item.Value); PreviousHasParameter = PreviousHasParameter !.ChildHasParameter; } } else { this.InvalidParameterList.Add(new InvalidSearchQueryParameter(Item.Key, Item.Value, $"The {TermHas} query must contain a resource name followed by a reference search parameter name followed by another {TermHas} parameter or a search parameter and value where each is separated by a colon {TermSearchModifierDelimiter}. For instance: _has:Observation:patient:code=1234-5 or _has:Observation:patient:_has:AuditEvent:entity:user=MyUserId. The {TermHas} qery found was : {Item.Key}={Item.Value} ")); } } if (RootHasParameter is object) { this.Has.Add(RootHasParameter); } } }
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); } } }