/// <summary> /// Rewrite a QPD query to an HDSI query /// </summary> public virtual NameValueCollection ParseQuery(QPD qpd, Hl7QueryParameterType map) { NameValueCollection retVal = new NameValueCollection(); // Control of strength String strStrength = (qpd.GetField(4, 0) as Varies)?.Data.ToString(), algorithm = (qpd.GetField(5, 0) as Varies)?.Data.ToString(); Double?strength = String.IsNullOrEmpty(strStrength) ? null : (double?)Double.Parse(strStrength); // Query parameters foreach (var itm in MessageUtils.ParseQueryElement(qpd.GetField(3).OfType <Varies>(), map, algorithm, strength)) { try { retVal.Add(itm.Key, itm.Value); } catch (Exception e) { this.m_tracer.TraceError("Error processing query parameter", "QPD", "1", 3, 0, e); throw new HL7ProcessingException(this.m_localizationService.FormatString("error.type.HL7ProcessingException", new { param = "query parameter" }), "QPD", "1", 3, 0, e); } } // Return domains foreach (var rt in qpd.GetField(8).OfType <Varies>()) { try { var rid = new CX(qpd.Message); DeepCopy.Copy(rt.Data as GenericComposite, rid); var authority = rid.AssigningAuthority.ToModel(); if (authority.Key == this.m_configuration.LocalAuthority.Key) { retVal.Add("_id", rid.IDNumber.Value); } else { retVal.Add($"identifier[{authority.DomainName}]", "!null"); } } catch (Exception e) { this.m_tracer.TraceError("Error processing return domains", "QPD", "1", 8, 0, e); throw new HL7ProcessingException(this.m_localizationService.FormatString("error.type.HL7ProcessingException", new { param = "return domains" }), "QPD", "1", 8, 0, e); } } retVal.Add("obsoletionTime", "null"); return(retVal); }
/// <summary> /// Rewrite a QPD query to an HDSI query /// </summary> public virtual NameValueCollection ParseQuery(QPD qpd, Hl7QueryParameterType map) { NameValueCollection retVal = new NameValueCollection(); // Query domains foreach (var rt in qpd.GetField(3).OfType <Varies>()) { try { var rid = new CX(qpd.Message); DeepCopy.Copy(rt.Data as GenericComposite, rid); var authority = rid.AssigningAuthority.ToModel(); if (authority.Key == m_configuration.LocalAuthority.Key) { retVal.Add("_id", rid.IDNumber.Value); } else { retVal.Add($"identifier[{authority.DomainName}].value", rid.IDNumber.Value); } } catch (Exception e) { this.m_tracer.TraceError("Error processing patient identity", "QPD", "1", 3, 4, e); throw new HL7ProcessingException(this.m_localizationService.FormatString("error.type.HL7ProcessingException", new { param = "patient identity" }), "QPD", "1", 3, 4, e); } } //// Return domains // This just verifies the return domains foreach (var rt in qpd.GetField(4).OfType <Varies>()) { try { var rid = new CX(qpd.Message); DeepCopy.Copy(rt.Data as GenericComposite, rid); var authority = rid.AssigningAuthority.ToModel(); } catch (Exception e) { this.m_tracer.TraceError("Error processing what domains returned", "QPD", "1", 4, 4, e); throw new HL7ProcessingException(this.m_localizationService.FormatString("error.type.HL7ProcessingException", new { param = "what domains returned" }), "QPD", "1", 4, 4, e); } } return(retVal); }
/// <summary> /// Create an appropriate response given the results /// </summary> /// <param name="results">The results that matches the query</param> /// <param name="map">The HL7 query parameter mapping</param> /// <param name="request">The original request message</param> /// <param name="count">The number of results that the user requested</param> /// <param name="offset">The offset to the first result</param> /// <param name="queryId">The unique query identifier used</param> /// <returns>The constructed result message</returns> protected virtual IMessage CreateQueryResponse(Hl7MessageReceivedEventArgs request, Expression filter, Hl7QueryParameterType map, IEnumerable results, Guid queryId, int offset, int count, int totalResults) { var retVal = this.CreateACK(map.ResponseType, request.Message, "AA", "Query Success"); var omsh = retVal.GetStructure("MSH") as MSH; var qak = retVal.GetStructure("QAK") as QAK; var odsc = retVal.GetStructure("DSC") as DSC; var oqpd = retVal.GetStructure("QPD") as QPD; DeepCopy.copy(request.Message.GetStructure("QPD") as ISegment, oqpd); omsh.MessageType.MessageCode.Value = "RSP"; omsh.MessageType.MessageStructure.Value = retVal.GetType().Name; omsh.MessageType.TriggerEvent.Value = map.ResponseTrigger; omsh.MessageType.MessageStructure.Value = map.ResponseTypeXml; qak.HitCount.Value = totalResults.ToString(); qak.HitsRemaining.Value = (totalResults - offset - count > 0 ? totalResults - offset - count : 0).ToString(); qak.QueryResponseStatus.Value = totalResults == 0 ? "NF" : "OK"; qak.ThisPayload.Value = results.OfType <Object>().Count().ToString(); if (ApplicationServiceContext.Current.GetService <Core.Services.IQueryPersistenceService>() != null && Int32.Parse(qak.HitsRemaining.Value) > 0) { odsc.ContinuationPointer.Value = queryId.ToString(); odsc.ContinuationStyle.Value = "RD"; } // Process results retVal = map.QueryHandler.AppendQueryResult(results, filter, retVal, request, map.ScoreConfiguration, offset); return(retVal); }
/// <summary> /// Rewrite a QPD query to an HDSI query /// </summary> public static NameValueCollection ParseQueryElement(IEnumerable <Varies> varies, Hl7QueryParameterType map, String matchAlgorithm, double?matchStrength = null) { NameValueCollection retVal = new NameValueCollection(); var config = ApplicationServiceContext.Current.GetService <IConfigurationManager>().GetSection <Hl7ConfigurationSection>(); // Query parameters foreach (var qp in varies) { var composite = qp.Data as GenericComposite; // Parse the parameters var qfield = (composite.Components[0] as Varies)?.Data?.ToString(); var qvalue = (composite.Components[1] as Varies)?.Data?.ToString(); // Attempt to find the query parameter and map var parm = map.Parameters.Where(o => o.Hl7Name == qfield || o.Hl7Name == qfield + ".1" || o.Hl7Name == qfield + ".1.1").OrderBy(o => o.Hl7Name.Length - qfield.Length).FirstOrDefault(); if (parm == null) { throw new ArgumentOutOfRangeException($"{qfield} not mapped to query parameter"); } switch (parm.ParameterType) { case "concept": retVal.Add($"{parm.ModelName}.referenceTerm.term.mnemonic", qvalue); break; case "string": // Enables phonetic matching String transform = null; if (parm.AllowFuzzy) { switch ((matchAlgorithm ?? "pattern").ToLower()) { case "approx": transform = ":(approx|{0})"; break; case "exact": transform = "{0}"; break; case "pattern": transform = "~*{0}*"; break; case "soundex": if (matchStrength.HasValue) { transform = ":(soundex){0}"; } else { transform = $":(phonetic_diff|{{0}},soundex)<={matchStrength * qvalue.Length}"; } break; case "metaphone": if (matchStrength.HasValue) { transform = ":(metaphone){0}"; } else { transform = $":(phonetic_diff|{{0}},metaphone)<={matchStrength * qvalue.Length}"; } break; case "dmetaphone": if (matchStrength.HasValue) { transform = ":(dmetaphone){0}"; } else { transform = $":(phonetic_diff|{{0}},dmetaphone)<={matchStrength * qvalue.Length}"; } break; case "alias": transform = $":(alias|{{0}})>={matchStrength ?? 3}"; break; default: transform = "~{0}"; break; } } else { transform = "{0}"; } retVal.Add(parm.ModelName, transform.Split(',').Select(tx => String.Format(tx, qvalue)).ToList()); break; case "date": if (qvalue.Length == 4) // partial date { retVal.Add(parm.ModelName, $"~{qvalue}"); } else if (qvalue.Length == 6) // partial to month { retVal.Add(parm.ModelName, $"~{qvalue.Insert(4, "-")}"); } else { retVal.Add(parm.ModelName, qvalue); } break; default: var txv = parm.ValueTransform ?? "{0}"; retVal.Add(parm.ModelName, txv.Split(',').Select(tx => String.Format(tx, qvalue)).ToList()); break; } } // HACK: Are they asking for the @PID.3.4.1 of our local auth? List <String> localId = null; if (retVal.TryGetValue("identifier.authority.domainName", out localId) && localId.Contains(config.LocalAuthority.DomainName)) { retVal.Remove("identifier.authority.domainName"); localId = retVal["identifier.value"]; retVal.Remove("identifier.value"); retVal.Add("_id", localId); } return(retVal); }
/// <summary> /// Create query response for the data according to ITI-9 /// </summary> protected override IMessage CreateQueryResponse(Hl7MessageReceivedEventArgs request, Expression filter, Hl7QueryParameterType map, IEnumerable results, Guid queryId, int offset, int count, int totalResults) { var retVal = base.CreateQueryResponse(request, filter, map, results, queryId, offset, count, totalResults) as RSP_K23; // CASE 3: Domains are recognized but no results if (results.OfType <Patient>().Count() == 0) { retVal.MSA.AcknowledgmentCode.Value = "AE"; retVal.MSA.TextMessage.Value = "Query Error"; retVal.QAK.QueryResponseStatus.Value = "AE"; retVal.ERR.GetErrorLocation(0).SegmentID.Value = "QPD"; retVal.ERR.GetErrorLocation(0).SegmentSequence.Value = "1"; retVal.ERR.GetErrorLocation(0).FieldPosition.Value = "3"; retVal.ERR.GetErrorLocation(0).FieldRepetition.Value = "1"; retVal.ERR.GetErrorLocation(0).ComponentNumber.Value = "1"; retVal.ERR.HL7ErrorCode.Identifier.Value = "204"; retVal.ERR.HL7ErrorCode.Text.Value = "Unknown Key Identifier"; } return(retVal); }