/// <summary> /// Render the object /// </summary> public void Render(XElement element, XmlWriter writer, IRenderContext context) { var resourceType = new ModelSerializationBinder().BindToType(String.Empty, element.Attribute("resource")?.Value); if (resourceType == null) { writer.WriteStartElement("span"); writer.WriteAttributeString("style", "color:red"); writer.WriteString($"{element.Attribute("resource")?.Value} not valid"); writer.WriteEndElement(); } else { var render = element.Attribute("render")?.Value; var identifier = ReportViewUtil.GetValue(context, element.Value); if (identifier != null) { var dpType = typeof(IDataPersistenceService <>).MakeGenericType(resourceType); var dpService = ApplicationServiceContext.Current.GetService(dpType) as IDataPersistenceService; var key = identifier is Guid || identifier is Guid? ? (Guid)identifier : Guid.Parse(identifier.ToString()); var instance = dpService.Get(key); if (instance == null) { writer.WriteComment($"{resourceType.Name}/{key} not found"); } else if (!String.IsNullOrEmpty(render)) { var selKey = $"{resourceType.Name}.{render}"; if (!this.m_selectors.TryGetValue(selKey, out Delegate selDelegate)) { selDelegate = QueryExpressionParser.BuildPropertySelector(resourceType, render).Compile(); this.m_selectors.TryAdd(selKey, selDelegate); } writer.WriteString(selDelegate.DynamicInvoke(instance)?.ToString()); } else { writer.WriteString(instance?.ToString()); } } } }
/// <summary> /// Send query to master target /// </summary> private List <Patient> SendQuery(NameValueCollection originalQuery, int count, out int totalResults) { // Map reverse var parmMap = s_map.Map.FirstOrDefault(o => o.Trigger == "Q22"); List <KeyValuePair <Hl7QueryParameterMapProperty, object> > parameters = new List <KeyValuePair <Hl7QueryParameterMapProperty, object> >(); foreach (var kv in originalQuery) { var rmap = parmMap.Parameters.Find(o => o.ModelName == kv.Key); if (rmap == null) { // Is the value a UUID? If so, it may be an identifier we can use if (Guid.TryParse(kv.Value.First(), out Guid uuid)) { // What is the type of this property var property = QueryExpressionParser.BuildPropertySelector <Patient>(kv.Key); if (property == null) { throw new InvalidOperationException($"{kv.Key} is not valid on Patient"); } // Is there a classifier? We need it for querying a guaranteed unique property var preferred = property.Body.Type.GetCustomAttribute <ClassifierAttribute>()?.ClassifierProperty; if (String.IsNullOrEmpty(preferred)) { throw new InvalidOperationException($"{property.Body.Type} does not have a ClassifierAttribute"); } var idp = typeof(IDataPersistenceService <>).MakeGenericType(property.Body.Type); var ids = ApplicationServiceContext.Current.GetService(idp) as IDataPersistenceService; if (ids == null) { throw new InvalidOperationException($"{idp} not found"); } var value = ids.Get(uuid); var match = property.Body.Type.GetProperty(preferred).GetValue(value); preferred = property.Body.Type.GetProperty(preferred).GetSerializationName(); // Get the parmaeter map for this classifier rmap = parmMap.Parameters.Find(o => o.ModelName == $"{kv.Key}.{preferred}"); if (rmap != null) { parameters.Add(new KeyValuePair <Hl7QueryParameterMapProperty, object>(rmap, match)); } else { continue; } } else { continue; } } else { parameters.Add(new KeyValuePair <Hl7QueryParameterMapProperty, object>(rmap, kv.Value)); } } if (parameters.Count == 0) { parameters.Add(new KeyValuePair <Hl7QueryParameterMapProperty, object>(parmMap.Parameters.FirstOrDefault(o => o.Hl7Name == "@PID.33"), DateTime.MinValue.AddDays(10))); } // Construct the basic QBP_Q22 QBP_Q21 queryRequest = new QBP_Q21(); var endpoint = this.Configuration.Endpoints.First(); queryRequest.MSH.SetDefault(endpoint.ReceivingDevice, endpoint.ReceivingFacility, endpoint.SecurityToken); queryRequest.MSH.MessageType.MessageStructure.Value = "QBP_Q21"; queryRequest.MSH.MessageType.TriggerEvent.Value = "Q22"; queryRequest.MSH.MessageType.MessageCode.Value = "QBP"; queryRequest.GetSFT(0).SetDefault(); queryRequest.RCP.QuantityLimitedRequest.Units.Identifier.Value = "RD"; queryRequest.RCP.QuantityLimitedRequest.Quantity.Value = (count).ToString(); queryRequest.QPD.MessageQueryName.Identifier.Value = "Q22"; queryRequest.QPD.MessageQueryName.Text.Value = "Find Candidates"; queryRequest.QPD.MessageQueryName.NameOfCodingSystem.Value = "HL7"; Terser tser = new Terser(queryRequest); int q = 0; foreach (var qp in parameters) { List <String> filter = qp.Value as List <String> ?? new List <String>() { qp.Value.ToString() }; foreach (var val in filter) { Terser.Set(queryRequest.QPD, 3, q, 1, 1, qp.Key.Hl7Name); string dval = val; while (new String[] { "<", ">", "!", "=", "~" }.Any(o => dval.StartsWith(o))) { dval = dval.Substring(1); } switch (qp.Key.ParameterType) { case "date": var dt = DateTime.Parse(dval); switch (dval.Length) { case 4: Terser.Set(queryRequest.QPD, 3, q, 2, 1, dt.Year.ToString()); break; case 7: Terser.Set(queryRequest.QPD, 3, q, 2, 1, dt.ToString("yyyyMM")); break; case 10: Terser.Set(queryRequest.QPD, 3, q, 2, 1, dt.ToString("yyyyMMdd")); break; default: Terser.Set(queryRequest.QPD, 3, q, 2, 1, dt.ToString("yyyyMMddHHmmss.fffzzzz").Replace(":", "")); break; } break; default: Terser.Set(queryRequest.QPD, 3, q, 2, 1, dval); break; } q++; } } // TODO: Send the query and then maps results try { RSP_K21 response = endpoint.GetSender().SendAndReceive(queryRequest) as RSP_K21; // Iterate and create responses totalResults = Int32.Parse(response.QAK.HitCount.Value ?? response.QUERY_RESPONSERepetitionsUsed.ToString()); List <Patient> overr = new List <Patient>(); // Query response for (int i = 0; i < response.QUERY_RESPONSERepetitionsUsed; i++) { var ar = response.GetQUERY_RESPONSE(i); // Create patient Bundle patientData = MessageUtils.Parse(ar); patientData.Reconstitute(); // Does this patient "really" exist? if (!ar.PID.GetPatientIdentifierList().Any(o => o.AssigningAuthority.NamespaceID.Value == this.m_configuration.LocalAuthority.DomainName) && !this.m_retrieveHacks.ContainsKey(patientData.Item.OfType <Patient>().First().Key.Value)) { var key = this.m_retrieveHacks.FirstOrDefault(o => o.Value.Any(x => x.Value == ar.PID.GetPatientIdentifierList()[0].IDNumber.Value)); var patient = patientData.Item.OfType <Patient>().First(); if (key.Key != Guid.Empty) { patient.Key = key.Key; } else { this.m_retrieveHacks.Add(patient.Key.Value, patient.Identifiers); } } // Now we extract the patient var pat = patientData.Item.OfType <Patient>().First(); pat.VersionKey = pat.Key; overr.Add(pat); } return(overr); } catch (Exception ex) { totalResults = 0; this.m_tracer.TraceEvent(EventLevel.Error, "Error dispatching HL7 query {0}", ex); throw new HL7ProcessingException("Error dispatching HL7 query", null, null, 0, 0, ex); } }
// [PolicyPermission(System.Security.Permissions.SecurityAction.Demand, PolicyId = PermissionPolicyIdentifiers.CreateDevice)] internal static void QueryData(HdsiQueryParameters parms) { if (String.IsNullOrEmpty(parms.ResourceType)) { throw new ArgumentNullException("Require --resourceType or -r"); } // Get the type var type = new ModelSerializationBinder().BindToType(null, parms.ResourceType); if (type == null) { throw new InvalidOperationException($"Cannot find reosurce type {parms.ResourceType}"); } if (!parms.AsDataSet) { Console.WriteLine("Type: {0}", type); } // Build the parameter list NameValueCollection nvc = new NameValueCollection(); if (parms.Filter != null) { foreach (var kv in parms.Filter) { var f = kv.Split('='); nvc.Add(f[0], f[1]); } } Int32.TryParse(parms.Offset ?? "0", out int offset); Int32.TryParse(parms.Count ?? "25", out int count); if (parms.Display == null) { parms.Display = new System.Collections.Specialized.StringCollection() { "id", "ToString" } } ; // Get the specified lambda expression var builderMethod = typeof(QueryExpressionParser).GetGenericMethod(nameof(QueryExpressionParser.BuildLinqExpression), new Type[] { type }, new Type[] { typeof(NameValueCollection) }); var linqExpression = builderMethod.Invoke(null, new object[] { nvc }); if (!parms.AsDataSet) { Console.WriteLine("Filter: {0}", linqExpression); } // Fetch results var queryMethod = m_client.GetType().GetGenericMethod(nameof(HdsiServiceClient.Query), new Type[] { type }, new Type[] { linqExpression.GetType(), typeof(int), typeof(int?), typeof(String[]), typeof(Guid?), typeof(ModelSort <>).MakeGenericType(type).MakeArrayType() }); var result = queryMethod.Invoke(m_client, new object[] { linqExpression, offset, count, parms.Expand?.OfType <String>().ToArray(), null, null }) as Bundle; if (!parms.AsDataSet) { Console.WriteLine("Result: {0} .. {1} of {2}", result.Offset, result.Item.Count, result.TotalResults); var displayCols = parms.Display.OfType <String>().Select(o => { return((Expression <Func <IdentifiedData, Object> >)(col => o == "ToString" ? col.ToString() : QueryExpressionParser.BuildPropertySelector(type, o, true).Compile().DynamicInvoke(col))); }).ToArray(); DisplayUtil.TablePrint <IdentifiedData>(result.Item, parms.Display.OfType <String>().ToArray(), parms.Display.OfType <String>().Select(o => 40).ToArray(), displayCols); } else { Dataset ds = new Dataset($"sdbac Dataset for {type} filter {nvc}"); Delegate displaySelector = null; if (parms.Display.Count > 0) { displaySelector = QueryExpressionParser.BuildPropertySelector(type, parms.Display.OfType <String>().FirstOrDefault(), true).Compile(); } foreach (var itm in result.Item) { ds.Action.Add(new DataUpdate() { InsertIfNotExists = true, IgnoreErrors = true, Element = (IdentifiedData)(displaySelector != null ? displaySelector.DynamicInvoke(itm) : itm) }); } m_xsz.Serialize(Console.Out, ds); } } }
/// <summary> /// Perform the block operation /// </summary> private IEnumerable <T> DoBlock <T>(T input, MatchBlock block, IEnumerable <Guid> ignoreKeys, IRecordMatchingDiagnosticSession collector = null) where T : IdentifiedData { // Load the persistence service int tr = 1; try { collector?.LogStartAction(block); // Perpare filter var filter = block.Filter; NameValueCollection qfilter = new NameValueCollection(); foreach (var b in filter) { bool shouldIncludeExpression = true; if (b.When?.Any() == true) // Only include the filter when the conditions are met { var guardExpression = b.GuardExpression; if (guardExpression == null) // not built { var parameter = Expression.Parameter(typeof(T)); Expression guardBody = null; foreach (var whenClause in b.When) { var selectorExpression = QueryExpressionParser.BuildPropertySelector <T>(whenClause, true); if (guardBody == null) { guardBody = Expression.MakeBinary(ExpressionType.NotEqual, Expression.Invoke(selectorExpression, parameter), Expression.Constant(null)); } else { guardBody = Expression.MakeBinary(ExpressionType.AndAlso, Expression.Invoke(guardBody, parameter), Expression.MakeBinary(ExpressionType.NotEqual, Expression.Invoke(selectorExpression, parameter), Expression.Constant(null))); } } b.GuardExpression = guardExpression = Expression.Lambda(guardBody, parameter).Compile(); } shouldIncludeExpression = (bool)guardExpression.DynamicInvoke(input); } if (shouldIncludeExpression) { var nvc = NameValueCollection.ParseQueryString(b.Expression); // Build the expression foreach (var nv in nvc) { foreach (var val in nv.Value) { qfilter.Add(nv.Key, val); } } } } // Do we skip when no conditions? if (!qfilter.Any()) { yield break; } // Add ignore clauses if (ignoreKeys?.Any() == true) { qfilter.Add("id", ignoreKeys.Select(o => $"!{o}")); } if (input.Key.HasValue) { qfilter.Add("id", $"!{input.Key}"); } // Make LINQ query // NOTE: We can't build and store this since input is a closure // TODO: Figure out a way to compile this expression once var linq = QueryExpressionParser.BuildLinqExpression <T>(qfilter, new Dictionary <string, Func <Object> >() { { "input", ((Func <T>)(() => input)) } }, safeNullable: true, lazyExpandVariables: false); // Add status keys if (typeof(IHasState).IsAssignableFrom(typeof(T))) { var stateAccess = Expression.MakeMemberAccess(linq.Parameters[0], typeof(T).GetProperty(nameof(IHasState.StatusConceptKey))); Expression statePart = null; foreach (var stateKey in StatusKeys.ActiveStates) { if (statePart == null) { statePart = Expression.MakeBinary(ExpressionType.Equal, stateAccess, Expression.Convert(Expression.Constant(stateKey), typeof(Guid?))); } else { statePart = Expression.MakeBinary(ExpressionType.OrElse, Expression.MakeBinary(ExpressionType.Equal, stateAccess, Expression.Convert(Expression.Constant(stateKey), typeof(Guid?))), statePart); } } linq = Expression.Lambda <Func <T, bool> >(Expression.MakeBinary(ExpressionType.AndAlso, statePart, linq.Body), linq.Parameters[0]); } this.m_tracer.TraceVerbose("Will execute block query : {0}", linq); // Query control variables for iterating result sets var batch = block.BatchSize; if (batch == 0) { batch = 100; } // Set the authentication context using (AuthenticationContext.EnterSystemContext()) { int ofs = 0; while (ofs < tr) { if (block.UseRawPersistenceLayer) { var persistenceService = ApplicationServiceContext.Current.GetService <IDataPersistenceService <T> >(); if (persistenceService == null) { throw new InvalidOperationException($"Cannot find persistence service for {typeof(T).FullName}"); } var records = persistenceService.Query(linq, ofs, batch, out tr, AuthenticationContext.SystemPrincipal); collector?.LogSample(linq.ToString(), tr); foreach (var itm in records) { yield return(itm); } ofs += batch; } else { var persistenceService = ApplicationServiceContext.Current.GetService <IRepositoryService <T> >(); if (persistenceService == null) { throw new InvalidOperationException($"Cannot find persistence service for {typeof(T).FullName}"); } var records = persistenceService.Find(linq, ofs, batch, out tr); collector?.LogSample(linq.ToString(), tr); foreach (var itm in records) { if (itm.Key.HasValue && itm.Key != input.Key && ignoreKeys?.Contains(itm.Key.Value) != true) { yield return(itm); } } ofs += batch; } if (ofs > 100) { collector?.LogSample("too-many-results", tr); yield break; } } } } finally { collector?.LogEndAction(); } }