示例#1
0
        /// <summary>
        /// Queries for a specified resource.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Returns the FHIR query result containing the results of the query.</returns>
        /// <exception cref="System.ArgumentNullException">parameters</exception>
        public virtual FhirQueryResult Query(System.Collections.Specialized.NameValueCollection parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            Core.Model.Query.NameValueCollection imsiQuery = null;
            FhirQuery query = QueryRewriter.RewriteFhirQuery <TFhirResource, TModel>(parameters, out imsiQuery);

            // Do the query
            int totalResults            = 0;
            List <IResultDetail> issues = new List <IResultDetail>();
            var predicate           = QueryExpressionParser.BuildLinqExpression <TModel>(imsiQuery);
            var imsiResults         = this.Query(predicate, issues, query.QueryId, query.Start, query.Quantity, out totalResults);
            var webOperationContext = WebOperationContext.Current;

            // Return FHIR query result
            return(new FhirQueryResult()
            {
                Details = issues,
                Outcome = ResultCode.Accepted,
                Results = imsiResults.AsParallel().Select(o => this.MapToFhir(o, webOperationContext)).OfType <DomainResourceBase>().ToList(),
                Query = query,
                TotalResults = totalResults
            });
        }
        /// <summary>
        /// Queries for a specified resource.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Returns the FHIR query result containing the results of the query.</returns>
        /// <exception cref="System.ArgumentNullException">parameters</exception>
        public virtual Bundle Query(System.Collections.Specialized.NameValueCollection parameters)
        {
            if (parameters == null)
            {
                this.m_traceSource.TraceError($"Argument {nameof(parameters)} null or empty");
                throw new ArgumentNullException(this.m_localizationService.GetString("error.type.ArgumentNullException"));
            }

            Core.Model.Query.NameValueCollection hdsiQuery = null;
            FhirQuery query = QueryRewriter.RewriteFhirQuery(typeof(TFhirResource), typeof(TModel), parameters, out hdsiQuery);

            // Do the query
            int totalResults = 0;
            var predicate    = QueryExpressionParser.BuildLinqExpression <TModel>(hdsiQuery);
            var hdsiResults  = this.Query(predicate, query.QueryId, query.Start, query.Quantity, out totalResults);

            var auth = AuthenticationContext.Current;

            // Return FHIR query result
            if (Environment.ProcessorCount > 4)
            {
                hdsiResults = hdsiResults.AsParallel().AsOrdered();
            }

            var retVal = new FhirQueryResult(typeof(TFhirResource).Name)
            {
                Results = hdsiResults.Select(o =>
                {
                    using (AuthenticationContext.EnterContext(auth.Principal))
                    {
                        return(new Bundle.EntryComponent()
                        {
                            Resource = this.MapToFhir(o),
                            Search = new Bundle.SearchComponent()
                            {
                                Mode = Bundle.SearchEntryMode.Match
                            }
                        });
                    }
                }).ToList(),
                Query        = query,
                TotalResults = totalResults
            };

            this.ProcessIncludes(hdsiResults, parameters, retVal);

            return(ExtensionUtil.ExecuteBeforeSendResponseBehavior(TypeRestfulInteraction.SearchType, this.ResourceType, MessageUtil.CreateBundle(retVal, Bundle.BundleType.Searchset)) as Bundle);
        }
示例#3
0
        /// <summary>
        /// Parameters
        /// </summary>
        public override FhirQueryResult Query(System.Collections.Specialized.NameValueCollection parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            Core.Model.Query.NameValueCollection hdsiQuery = null;
            FhirQuery query = QueryRewriter.RewriteFhirQuery <SanteDB.Messaging.FHIR.Resources.Observation, Core.Model.Acts.Observation>(parameters, out hdsiQuery);

            // Do the query
            int totalResults = 0;

            IEnumerable <Core.Model.Acts.Observation> hdsiResults = null;

            if (parameters["value-concept"] != null)
            {
                var predicate = QueryExpressionParser.BuildLinqExpression <Core.Model.Acts.CodedObservation>(hdsiQuery);
                hdsiResults = this.QueryEx <Core.Model.Acts.CodedObservation>(predicate, query.QueryId, query.Start, query.Quantity, out totalResults).OfType <Core.Model.Acts.Observation>();
            }
            else if (parameters["value-quantity"] != null)
            {
                var predicate = QueryExpressionParser.BuildLinqExpression <Core.Model.Acts.QuantityObservation>(hdsiQuery);
                hdsiResults = this.QueryEx <Core.Model.Acts.QuantityObservation>(predicate, query.QueryId, query.Start, query.Quantity, out totalResults).OfType <Core.Model.Acts.Observation>();
            }
            else
            {
                var predicate = QueryExpressionParser.BuildLinqExpression <Core.Model.Acts.Observation>(hdsiQuery);
                hdsiResults = this.Query(predicate, query.QueryId, query.Start, query.Quantity, out totalResults);
            }


            var restOperationContext = RestOperationContext.Current;

            // Return FHIR query result
            return(new FhirQueryResult()
            {
                Results = hdsiResults.AsParallel().Select(o => this.MapToFhir(o, restOperationContext)).OfType <ResourceBase>().ToList(),
                Query = query,
                TotalResults = totalResults
            });
        }
        /// <summary>
        /// Queries for a specified resource.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <returns>Returns the FHIR query result containing the results of the query.</returns>
        /// <exception cref="System.ArgumentNullException">parameters</exception>
        public virtual FhirQueryResult Query(System.Collections.Specialized.NameValueCollection parameters)
        {
            if (parameters == null)
            {
                throw new ArgumentNullException(nameof(parameters));
            }

            Core.Model.Query.NameValueCollection hdsiQuery = null;
            FhirQuery query = QueryRewriter.RewriteFhirQuery <TFhirResource, TModel>(parameters, out hdsiQuery);

            // Do the query
            int totalResults         = 0;
            var predicate            = QueryExpressionParser.BuildLinqExpression <TModel>(hdsiQuery);
            var hdsiResults          = this.Query(predicate, query.QueryId, query.Start, query.Quantity, out totalResults);
            var restOperationContext = RestOperationContext.Current;

            var auth = AuthenticationContext.Current;

            // Return FHIR query result
            return(new FhirQueryResult()
            {
                Results = hdsiResults.AsParallel().Select(o => {
                    try
                    {
                        AuthenticationContext.Current = auth;
                        return this.MapToFhir(o, restOperationContext);
                    }
                    finally
                    {
                        AuthenticationContext.Current = new AuthenticationContext(AuthenticationContext.AnonymousPrincipal);
                    }
                }).OfType <ResourceBase>().ToList(),
                Query = query,
                TotalResults = totalResults
            });
        }
示例#5
0
        /// <summary>
        /// Re-writes the FHIR query parameter to IMSI query parameter format
        /// </summary>
        /// <returns></returns>
        public static FhirQuery RewriteFhirQuery <TFhirResource, TModelType>(System.Collections.Specialized.NameValueCollection fhirQuery, out NameValueCollection imsiQuery)
        {
            // Try parse
            if (fhirQuery == null)
            {
                throw new ArgumentNullException(nameof(fhirQuery));
            }

            // Count and offset parameters
            int count = 0, offset = 0, page = 0;

            if (!Int32.TryParse(fhirQuery["_count"] ?? "100", out count))
            {
                throw new ArgumentException("_count");
            }
            if (!Int32.TryParse(fhirQuery["_offset"] ?? "0", out offset))
            {
                throw new ArgumentException("_offset");
            }
            if (fhirQuery["_page"] != null && Int32.TryParse(fhirQuery["_page"], out page))
            {
                offset = page * count;
            }

            Guid queryId = Guid.Empty;

            if (fhirQuery["_stateid"] != null)
            {
                queryId = Guid.Parse(fhirQuery["_stateid"]);
            }
            else
            {
                queryId = Guid.NewGuid();
            }

            // Return new query
            FhirQuery retVal = new FhirQuery()
            {
                ActualParameters   = new System.Collections.Specialized.NameValueCollection(),
                Quantity           = count,
                Start              = offset,
                MinimumDegreeMatch = 100,
                QueryId            = queryId,
                IncludeHistory     = false,
                IncludeContained   = false
            };

            imsiQuery = new NameValueCollection();

            var map = s_map.Map.FirstOrDefault(o => o.SourceType == typeof(TFhirResource));

            foreach (var kv in fhirQuery.AllKeys)
            {
                List <String> value = new List <string>(fhirQuery.GetValues(kv).Length);

                // Is the name extension?
                var parmMap = map?.Map.FirstOrDefault(o => o.FhirName == kv);
                if (parmMap == null)
                {
                    parmMap = s_default.Map.FirstOrDefault(o => o.FhirName == kv);
                }
                if (parmMap == null && kv == "extension")
                {
                    parmMap = new QueryParameterMapProperty()
                    {
                        FhirName  = "extension",
                        ModelName = "extension",
                        FhirType  = "tag"
                    }
                }
                ;
                else if (parmMap == null)
                {
                    continue;
                }

                foreach (var v in fhirQuery.GetValues(kv))
                {
                    if (String.IsNullOrEmpty(v))
                    {
                        continue;
                    }

                    // Operands
                    bool   chop    = false;
                    string opValue = String.Empty;
                    if (v.Length > 2)
                    {
                        switch (v.Substring(0, 2))
                        {
                        case "ap":
                            chop    = true;
                            opValue = "~";
                            break;

                        case "gt":
                            chop    = true;
                            opValue = ">";
                            break;

                        case "ge":
                            chop    = true;
                            opValue = ">=";
                            break;

                        case "lt":
                            chop    = true;
                            opValue = "<";
                            break;

                        case "le":
                            chop    = true;
                            opValue = "<=";
                            break;

                        case "ne":
                            chop    = true;
                            opValue = "!";
                            break;

                        case "eq":
                            chop = true;
                            break;

                        default:
                            break;
                        }
                    }
                    retVal.ActualParameters.Add(kv, v);
                    value.Add(opValue + v.Substring(chop ? 2 : 0));
                }

                if (value.Count(o => !String.IsNullOrEmpty(o)) == 0)
                {
                    continue;
                }

                // Query
                switch (parmMap.FhirType)
                {
                case "identifier":
                    foreach (var itm in value)
                    {
                        if (itm.Contains("|"))
                        {
                            var segs = itm.Split('|');
                            imsiQuery.Add(String.Format("{0}[{1}].value", parmMap.ModelName, segs[0]), segs[1]);
                        }
                        else
                        {
                            imsiQuery.Add(parmMap.ModelName + ".value", itm);
                        }
                    }
                    break;

                case "concept":
                    foreach (var itm in value)
                    {
                        if (itm.Contains("|"))
                        {
                            var segs = itm.Split('|');

                            string     codeSystemUri = segs[0];
                            CodeSystem codeSystem    = null;

                            if (codeSystemUri.StartsWith("urn:oid:"))
                            {
                                codeSystemUri = codeSystemUri.Substring(8);
                                codeSystem    = ApplicationContext.Current.GetService <IConceptRepositoryService>().FindCodeSystems(o => o.Oid == codeSystemUri).FirstOrDefault();
                            }
                            else if (codeSystemUri.StartsWith("urn:") || codeSystemUri.StartsWith("http:"))
                            {
                                codeSystem = ApplicationContext.Current.GetService <IConceptRepositoryService>().FindCodeSystems(o => o.Url == codeSystemUri).FirstOrDefault();
                            }
                            else
                            {
                                codeSystem = ApplicationContext.Current.GetService <IConceptRepositoryService>().FindCodeSystems(o => o.Name == codeSystemUri).FirstOrDefault();
                            }


                            s_tracer.TraceInformation("Have translated FHIR domain {0} to {1}", codeSystemUri, codeSystem?.Name);

                            if (codeSystem != null)
                            {
                                imsiQuery.Add(String.Format("{0}.referenceTerm[{1}].term.mnemonic", parmMap.ModelName, codeSystem.Name), segs[1]);
                            }
                            else
                            {
                                imsiQuery.Add(String.Format("{0}.mnemonic", parmMap.ModelName), segs[1]);
                            }
                        }
                        else
                        {
                            imsiQuery.Add(parmMap.ModelName + ".referenceTerm.term.mnemonic", itm);
                        }
                    }
                    break;

                case "reference":
                    foreach (var itm in value)
                    {
                        if (itm.Contains("/"))
                        {
                            var segs = itm.Split('/');
                            imsiQuery.Add(parmMap.ModelName, segs[1]);
                        }
                        else
                        {
                            imsiQuery.Add(parmMap.ModelName, itm);
                        }
                    }
                    break;

                case "tag":
                    foreach (var itm in value)
                    {
                        if (itm.Contains("|"))
                        {
                            var segs = itm.Split('|');
                            imsiQuery.Add(String.Format("{0}[{1}].value", parmMap.ModelName, segs[0]), segs[1]);
                        }
                        else
                        {
                            imsiQuery.Add(parmMap.ModelName, itm);
                        }
                    }
                    break;

                default:
                    imsiQuery.Add(parmMap.ModelName, value);
                    break;
                }
            }

            return(retVal);
        }
示例#6
0
        /// <summary>
        /// Re-writes the FHIR query parameter to HDSI query parameter format
        /// </summary>
        /// <returns></returns>
        public static FhirQuery RewriteFhirQuery(Type fhirType, Type modelType, System.Collections.Specialized.NameValueCollection fhirQuery, out NameValueCollection hdsiQuery)
        {
            // Try parse
            if (fhirQuery == null)
            {
                throw new ArgumentNullException(nameof(fhirQuery));
            }

            // Count and offset parameters
            int count = 0, offset = 0, page = 0;

            if (!Int32.TryParse(fhirQuery["_count"] ?? "25", out count))
            {
                throw new ArgumentException("_count");
            }
            if (!Int32.TryParse(fhirQuery["_offset"] ?? "0", out offset))
            {
                throw new ArgumentException("_offset");
            }
            if (fhirQuery["_page"] != null && Int32.TryParse(fhirQuery["_page"], out page))
            {
                offset = page * count;
            }

            Guid queryId = Guid.Empty;

            if (fhirQuery["_stateid"] != null)
            {
                queryId = Guid.Parse(fhirQuery["_stateid"]);
            }
            else if (fhirQuery["_total"] == "accurate") // to get an accurate total we have to persist query state
            {
                queryId = Guid.NewGuid();
            }
            else
            {
                queryId = Guid.Empty;
            }

            // Return new query
            FhirQuery retVal = new FhirQuery()
            {
                ActualParameters   = new System.Collections.Specialized.NameValueCollection(),
                Quantity           = count,
                Start              = offset,
                MinimumDegreeMatch = 100,
                QueryId            = queryId,
                IncludeHistory     = false,
                IncludeContained   = false
            };

            hdsiQuery = new NameValueCollection();

            var resourceType = fhirType.GetResourceType();
            var map          = s_map.Map.FirstOrDefault(o => resourceType.HasValue ? resourceType.Value == o.Resource : !o.ResourceSpecified);

            foreach (var kv in fhirQuery.AllKeys)
            {
                List <String> value = new List <string>(fhirQuery.GetValues(kv).Length);

                var parmComponents = kv.Split(':');

                // Is the name extension?
                var parmMap = map?.Map.FirstOrDefault(o => o.FhirQuery == parmComponents[0]);
                if (parmMap == null)
                {
                    parmMap = s_default.Map.FirstOrDefault(o => o.FhirQuery == parmComponents[0]);
                }
                if (parmMap == null && kv == "extension")
                {
                    parmMap = new QueryParameterMapProperty()
                    {
                        FhirQuery  = "extension",
                        ModelQuery = "extension",
                        FhirType   = QueryParameterRewriteType.Tag
                    }
                }
                ;
                else if (parmMap == null)
                {
                    continue;
                }

                // Valuse
                foreach (var v in fhirQuery.GetValues(kv))
                {
                    if (String.IsNullOrEmpty(v))
                    {
                        continue;
                    }

                    // Operands
                    bool   chop        = false;
                    string opValue     = String.Empty;
                    string filterValue = v;
                    if (v.Length > 2)
                    {
                        switch (v.Substring(0, 2))
                        {
                        case "ap":
                            chop    = true;
                            opValue = "~";
                            break;

                        case "gt":
                            chop    = true;
                            opValue = ">";
                            break;

                        case "ge":
                            chop    = true;
                            opValue = ">=";
                            break;

                        case "lt":
                            chop    = true;
                            opValue = "<";
                            break;

                        case "le":
                            chop    = true;
                            opValue = "<=";
                            break;

                        case "ne":
                            chop    = true;
                            opValue = "!";
                            break;

                        case "eq":
                            chop = true;
                            break;

                        default:
                            break;
                        }
                    }

                    if (parmComponents.Length > 1)
                    {
                        switch (parmComponents[1])
                        {
                        case "fuzzy":
                        case "approx":
                            opValue     = "";
                            filterValue = $":(approx|'{filterValue}')";
                            break;

                        case "contains":
                            opValue     = "~";
                            filterValue = $"*{filterValue}*";
                            break;

                        case "exact":
                            opValue = "";
                            break;

                        case "missing":
                            filterValue = "null";
                            chop        = false;
                            break;

                        default:
                            switch (parmMap.FhirType)
                            {
                            case QueryParameterRewriteType.String:         // Default string matching is wonky in FHIR but meh we can mimic it at least
                                opValue     = "~";
                                filterValue = $"*{filterValue.Replace(' ', '?')}*";
                                break;
                            }
                            break;
                        }
                    }

                    retVal.ActualParameters.Add(kv, filterValue);
                    value.Add(opValue + filterValue.Substring(chop ? 2 : 0));
                }

                if (value.Count(o => !String.IsNullOrEmpty(o)) == 0)
                {
                    continue;
                }

                // Apply a function
                if (!String.IsNullOrEmpty(parmMap.Function))
                {
                    value = value.Select(o => parmMap.Function.Replace("$1", o)).ToList();
                }

                // Query
                switch (parmMap.FhirType)
                {
                case QueryParameterRewriteType.Identifier:
                    foreach (var itm in value)
                    {
                        if (itm.Contains("|"))
                        {
                            var segs = itm.Split('|');
                            // Might be a URL
                            if (Uri.TryCreate(segs[0], UriKind.Absolute, out Uri data))
                            {
                                var aa = ApplicationServiceContext.Current.GetService <IAssigningAuthorityRepositoryService>().Get(data);
                                if (aa == null)
                                {
                                    throw new FhirException(System.Net.HttpStatusCode.BadRequest, OperationOutcome.IssueType.NotFound, $"No authority for {data} found");
                                }
                                hdsiQuery.Add(String.Format("{0}[{1}].value", parmMap.ModelQuery, aa.DomainName), segs[1]);
                            }
                            else
                            {
                                hdsiQuery.Add(String.Format("{0}[{1}].value", parmMap.ModelQuery, segs[0]), segs[1]);
                            }
                        }
                        else
                        {
                            hdsiQuery.Add(parmMap.ModelQuery + ".value", itm);
                        }
                    }
                    break;

                case QueryParameterRewriteType.Indicator:
                    var mq = NameValueCollection.ParseQueryString(parmMap.ModelQuery);
                    foreach (var itm in mq)
                    {
                        hdsiQuery.Add(itm.Key, itm.Value);
                    }
                    break;

                case QueryParameterRewriteType.Concept:
                    foreach (var itm in value)
                    {
                        if (itm.Contains("|"))
                        {
                            var segs = itm.Split('|');

                            string codeSystemUri = segs[0];
                            Core.Model.DataTypes.CodeSystem codeSystem = null;

                            if (codeSystemUri.StartsWith("urn:oid:"))
                            {
                                codeSystemUri = codeSystemUri.Substring(8);
                                codeSystem    = ApplicationServiceContext.Current.GetService <IRepositoryService <Core.Model.DataTypes.CodeSystem> >().Find(o => o.Oid == codeSystemUri).FirstOrDefault();
                            }
                            else if (codeSystemUri.StartsWith("urn:") || codeSystemUri.StartsWith("http:"))
                            {
                                codeSystem = ApplicationServiceContext.Current.GetService <IRepositoryService <Core.Model.DataTypes.CodeSystem> >().Find(o => o.Url == codeSystemUri).FirstOrDefault();
                            }
                            else
                            {
                                codeSystem = ApplicationServiceContext.Current.GetService <IRepositoryService <Core.Model.DataTypes.CodeSystem> >().Find(o => o.Name == codeSystemUri).FirstOrDefault();
                            }


                            s_tracer.TraceInfo("Have translated FHIR domain {0} to {1}", codeSystemUri, codeSystem?.Name);

                            if (codeSystem != null)
                            {
                                hdsiQuery.Add(String.Format("{0}.referenceTerm[{1}].term.mnemonic", parmMap.ModelQuery, codeSystem.Name), segs[1]);
                            }
                            else
                            {
                                hdsiQuery.Add(String.Format("{0}.mnemonic", parmMap.ModelQuery), segs[1]);
                            }
                        }
                        else
                        {
                            hdsiQuery.Add(parmMap.ModelQuery + ".referenceTerm.term.mnemonic", itm);
                        }
                    }
                    break;

                case QueryParameterRewriteType.Reference:
                    foreach (var itm in value)
                    {
                        if (itm.Contains("/"))
                        {
                            var segs = itm.Split('/');
                            hdsiQuery.Add(parmMap.ModelQuery, segs[1]);
                        }
                        else
                        {
                            hdsiQuery.Add(parmMap.ModelQuery, itm);
                        }
                    }
                    break;

                case QueryParameterRewriteType.Tag:
                    foreach (var itm in value)
                    {
                        if (itm.Contains("|"))
                        {
                            var segs = itm.Split('|');
                            hdsiQuery.Add(String.Format("{0}[{1}].value", parmMap.ModelQuery, segs[0]), segs[1]);
                        }
                        else
                        {
                            hdsiQuery.Add(parmMap.ModelQuery, itm);
                        }
                    }
                    break;

                default:
                    hdsiQuery.Add(parmMap.ModelQuery, value);
                    break;
                }
            }

            return(retVal);
        }