internal static ModelInfo.SearchParamDefinition FindSearchParamDefinition(this Criterium param, string resourceType) { return(param.SearchParameters?.FirstOrDefault(sp => sp.Resource == resourceType || sp.Resource == "Resource")); //var sp = ModelInfo.SearchParameters; //return sp.Find(defn => defn.Name == param.ParamName && defn.Resource == resourceType); }
public void ParseCriterium() { var crit = Criterium.Parse("paramX=18"); Assert.AreEqual("paramX", crit.ParamName); Assert.IsNull(crit.Modifier); Assert.AreEqual("18", crit.Operand.ToString()); Assert.AreEqual(Operator.EQ, crit.Type); crit = Criterium.Parse("paramX=>18"); Assert.AreEqual("paramX", crit.ParamName); Assert.IsNull(crit.Modifier); Assert.AreEqual("18", crit.Operand.ToString()); Assert.AreEqual(Operator.GT, crit.Type); crit = Criterium.Parse("paramX:modif1=~18"); Assert.AreEqual("paramX", crit.ParamName); Assert.AreEqual("18", crit.Operand.ToString()); Assert.AreEqual("modif1", crit.Modifier); Assert.AreEqual(Operator.APPROX, crit.Type); crit = Criterium.Parse("paramX:missing=true"); Assert.AreEqual("paramX", crit.ParamName); Assert.IsNull(crit.Operand); Assert.IsNull(crit.Modifier); Assert.AreEqual(Operator.ISNULL, crit.Type); crit = Criterium.Parse("paramX:missing=false"); Assert.AreEqual("paramX", crit.ParamName); Assert.IsNull(crit.Operand); Assert.IsNull(crit.Modifier); Assert.AreEqual(Operator.NOTNULL, crit.Type); }
/// <summary> /// Change something like Condition/subject:Patient=Patient/10014 /// to Condition/subject:Patient.internal_id=Patient/10014, so it is correctly handled as a chained parameter, /// including the filtering on the type in the modifier (if any). /// </summary> /// <param name="criteria"></param> /// <param name="resourceType"></param> /// <returns></returns> private List <Criterium> NormalizeNonChainedReferenceCriteria(List <Criterium> criteria, string resourceType) { var result = new List <Criterium>(); foreach (var crit in criteria) { var critSp = crit.FindSearchParamDefinition(resourceType); if (critSp != null && critSp.Type == Conformance.SearchParamType.Reference && crit.Type != Operator.CHAIN) { var subCrit = new Criterium(); subCrit.ParamName = InternalField.ID; subCrit.Type = crit.Type; subCrit.Operand = crit.Operand; var superCrit = new Criterium(); superCrit.ParamName = crit.ParamName; superCrit.Modifier = crit.Modifier; superCrit.Type = Operator.CHAIN; superCrit.Operand = subCrit; result.Add(superCrit); } else { result.Add(crit); } } return(result); }
/// <summary> /// CloseCriterium("patient.name=\"Teun\"") -> "patient IN (id1,id2)" /// </summary> /// <param name="resourceType"></param> /// <param name="crit"></param> /// <returns></returns> private Criterium CloseCriterium(Criterium crit, string resourceType, int level) { List <string> targeted = crit.GetTargetedReferenceTypes(resourceType); List <string> allKeys = new List <string>(); var errors = new List <Exception>(); foreach (var target in targeted) { try { Criterium innerCriterium = (Criterium)crit.Operand; var keys = CollectKeys(target, new List <Criterium> { innerCriterium }, ++level); //Recursive call to CollectKeys! allKeys.AddRange(keys.Select(k => k.ToString())); } catch (Exception ex) { errors.Add(ex); } } if (errors.Count == targeted.Count()) { //It is possible that some of the targets don't support the current parameter. But if none do, there is a serious problem. throw new ArgumentException(String.Format("None of the possible target resources support querying for parameter {0}", crit.ParamName)); } crit.Operator = Operator.IN; crit.Operand = ChoiceValue.Parse(String.Join(",", allKeys)); return(crit); }
private bool TryEnrichCriteriumWithSearchParameters(Criterium criterium, ResourceType resourceType) { var sp = _fhirModel.FindSearchParameter(resourceType, criterium.ParamName); if (sp == null) { return(false); } var result = true; var spDef = sp.GetOriginalDefinition(); if (spDef != null) { criterium.SearchParameters.Add(spDef); } if (criterium.Operator == Operator.CHAIN) { var subCrit = (Criterium)(criterium.Operand); foreach (var targetType in criterium.SearchParameters.SelectMany(spd => spd.Target)) { result &= TryEnrichCriteriumWithSearchParameters(subCrit, targetType); } } return(result); }
public void HandleDateParam() { // Brian: Not sure tha these tests SHOULD pass... // a time component on the Date? var p1 = new DateValue(new DateTimeOffset(1972, 11, 30, 15, 20, 49, TimeSpan.Zero)); Assert.AreEqual("1972-11-30", p1.ToString()); // we can parse a valid FHIR datetime and strip the time part off // (but it must be a valid FHIR datetime) var p2 = DateValue.Parse("1972-11-30T18:45:36Z"); Assert.AreEqual("1972-11-30", p2.ToString()); var crit = Criterium.Parse("paramX=1972-11-30"); var p3 = ((UntypedValue)crit.Operand).AsDateValue(); Assert.AreEqual("1972-11-30", p3.Value); try { // Test with an invalid FHIR datetime (no timezone specified) var p4 = DateValue.Parse("1972-11-30T18:45:36"); Assert.Fail("The datetime [1972-11-30T18:45:36] does not have a timezone, hence should fail parsing as a datevalue (via fhirdatetime)"); } catch (ArgumentException) { } }
private IMongoQuery createSimpleQuery(Query query) // without chains { IMongoQuery resourceFilter = query.ResourceFilter(); var criteria = query.Criteria.Select(c => Criterium.Parse(c)); IMongoQuery criteriaFilter = M.Query.And(criteria.Select(c => c.ToFilter(query.ResourceType))); return(M.Query.And(resourceFilter, criteriaFilter)); }
private string GetValue(Criterium crit) { foreach (KeyValuePair <Criterium, int> critPair in criteriumTable) { if (critPair.Key.Name.Equals(crit.Name)) { return(critPair.Value.ToString()); } } return(String.Empty); }
private Criterium GetCritMaxValue(string critName) { foreach (Criterium crit in mMatrix.Criteriums) { if (crit.Name.Equals(critName)) { return(crit); } } Criterium c = new Criterium(); return(c); }
public void ParseCriteriumFromParameter() { Parameters.ParametersParameterComponent parameter = Parameters.BuildParamExtension("Subject.name", "Teun"); Criterium sut = Criterium.Parse(parameter); Assert.AreEqual("Subject", sut.ParamName); Assert.IsTrue(sut.Operand is Criterium); Criterium sub = sut.Operand as Criterium; Assert.AreEqual("Teun", sub.Operand.ToString()); Assert.AreEqual(Operator.EQ, sub.Type); }
public void HandleDateTimeParam() { var p1 = new FhirDateTime(new DateTimeOffset(1972, 11, 30, 15, 20, 49, TimeSpan.Zero)); Assert.AreEqual("1972-11-30T15:20:49+00:00", p1.Value.ToString()); var crit = Criterium.Parse("paramX=1972-11-30T18:45:36Z"); var p3 = ((UntypedValue)crit.Operand).AsDateValue(); Assert.AreEqual("1972-11-30", p3.Value); var p4 = ((UntypedValue)crit.Operand).AsDateTimeValue(); Assert.AreEqual("1972-11-30T18:45:36Z", p4.Value); }
public void HandleReferenceParam() { var p1 = new ReferenceValue("2"); Assert.AreEqual("2", p1.Value); var p2 = new ReferenceValue("http://server.org/fhir/Patient/1"); Assert.AreEqual("http://server.org/fhir/Patient/1", p2.Value); var crit = Criterium.Parse(@"paramX=http://server.org/\$4/fhir/Patient/1"); var p3 = ((UntypedValue)crit.Operand).AsReferenceValue(); Assert.AreEqual("http://server.org/$4/fhir/Patient/1", p3.Value); }
public void HandleTokenParam() { var p1 = new TokenValue("NOK", "http://somewhere.nl/codes"); Assert.AreEqual("http://somewhere.nl/codes|NOK", p1.ToString()); var p2 = new TokenValue("y|n", "http://some|where.nl/codes"); Assert.AreEqual(@"http://some\|where.nl/codes|y\|n", p2.ToString()); var p3 = new TokenValue("NOK", matchAnyNamespace: true); Assert.AreEqual("NOK", p3.ToString()); var p4 = new TokenValue("NOK", matchAnyNamespace: false); Assert.AreEqual("|NOK", p4.ToString()); var p5 = TokenValue.Parse("http://somewhere.nl/codes|NOK"); Assert.AreEqual("http://somewhere.nl/codes", p5.Namespace); Assert.AreEqual("NOK", p5.Value); Assert.IsFalse(p4.AnyNamespace); var p6 = TokenValue.Parse(@"http://some\|where.nl/codes|y\|n"); Assert.AreEqual(@"http://some|where.nl/codes", p6.Namespace); Assert.AreEqual("y|n", p6.Value); Assert.IsFalse(p6.AnyNamespace); var p7 = TokenValue.Parse("|NOK"); Assert.AreEqual(null, p7.Namespace); Assert.AreEqual("NOK", p7.Value); Assert.IsFalse(p7.AnyNamespace); var p8 = TokenValue.Parse("NOK"); Assert.AreEqual(null, p8.Namespace); Assert.AreEqual("NOK", p8.Value); Assert.IsTrue(p8.AnyNamespace); var crit = Criterium.Parse("paramX=|NOK"); var p9 = ((UntypedValue)crit.Operand).AsTokenValue(); Assert.AreEqual("NOK", p9.Value); Assert.IsFalse(p9.AnyNamespace); }
/// <summary> /// CloseCriterium("patient.name=\"Teun\"") -> "patient=id1,id2" /// </summary> /// <param name="resourceType"></param> /// <param name="crit"></param> /// <returns></returns> private Criterium CloseCriterium(Criterium crit, string resourceType) { List <string> targeted = crit.GetTargetedReferenceTypes(resourceType); List <string> allKeys = new List <string>(); foreach (var target in targeted) { var keys = CollectKeys(target, new List <Criterium> { (Criterium)crit.Operand }); //Recursive call to CollectKeys! allKeys.AddRange(keys.Select(k => k.ToString())); } crit.Type = Operator.IN; crit.Operand = ChoiceValue.Parse(String.Join(",", allKeys)); return(crit); }
private string BuildAndReturnQueryFilterAsJsonString(ResourceType resourceType, string searchParameter, string query) { var bsonSerializerRegistry = new BsonSerializerRegistry(); bsonSerializerRegistry.RegisterSerializationProvider(new BsonSerializationProvider()); var resourceTypeAsString = resourceType.GetLiteral(); var criterium = Criterium.Parse(query); criterium.SearchParameters.AddRange(ModelInfo.SearchParameters.Where(p => p.Resource == resourceTypeAsString && p.Name == searchParameter)); var filter = criterium.ToFilter(resourceType.GetLiteral()); var jsonFilter = filter?.Render(null, bsonSerializerRegistry)?.ToJson(); return(jsonFilter); }
//TODO: Delete, F.Query is obsolete. /* * public SearchResults Search(F.Query query) * { * SearchResults results = new SearchResults(); * * var criteria = parseCriteria(query, results); * * if (!results.HasErrors) * { * results.UsedCriteria = criteria; * //TODO: ResourceType.ToString() sufficient, or need to use EnumMapping? * var normalizedCriteria = NormalizeNonChainedReferenceCriteria(criteria, query.ResourceType.ToString()); * List<BsonValue> keys = CollectKeys(query.ResourceType.ToString(), normalizedCriteria, results); * * int numMatches = keys.Count(); * * results.AddRange(KeysToSearchResults(keys)); * results.MatchCount = numMatches; * } * * return results; * } */ private List <Criterium> parseCriteria(SearchParams searchCommand, SearchResults results) { var result = new List <Criterium>(); foreach (var c in searchCommand.Parameters) { try { result.Add(Criterium.Parse(c.Item1, c.Item2)); } catch (Exception ex) { results.AddIssue(String.Format("Could not parse parameter [{0}] for reason [{1}].", c.ToString(), ex.Message)); } } return(result); }
public void StringQueryTest() { var resourceType = ResourceType.Subscription.GetLiteral(); var searchParamName = "criteria"; var criterium = Criterium.Parse("criteria=Observation?patient.identifier=http://somehost.no/fhir/Name%20Hospital|someId"); criterium.SearchParameters.AddRange(ModelInfo.SearchParameters.Where(p => p.Resource == resourceType && p.Name == searchParamName)); var filter = criterium.ToFilter(resourceType); var jsonFilter = filter?.Render(null, null)?.ToJson(); Assert.Equal( "{ \"criteria\" : /^Observation?patient.identifier=http:\\/\\/somehost.no\\/fhir\\/Name%20Hospital|someId/i }", jsonFilter); }
private static IMongoQuery TagQuery(Criterium crit, Uri tagscheme) { if (crit.Type == Operator.IN) { IEnumerable <ValueExpression> opMultiple = ((ChoiceValue)crit.Operand).Choices; var optionQueries = new List <IMongoQuery>(); foreach (var choice in opMultiple) { Criterium option = new Criterium(); option.Type = Operator.EQ; option.Operand = choice; option.Modifier = crit.Modifier; option.ParamName = crit.ParamName; optionQueries.Add(TagQuery(option, tagscheme)); } return(M.Query.Or(optionQueries)); } //From here there's only 1 operand. IMongoQuery schemeQuery = M.Query.EQ(InternalField.TAGSCHEME, tagscheme.AbsoluteUri); IMongoQuery argQuery; var operand = (ValueExpression)crit.Operand; switch (crit.Modifier) { case Modifier.PARTIAL: argQuery = StringQuery(InternalField.TAGTERM, Operator.EQ, Modifier.NONE, operand); break; case Modifier.TEXT: argQuery = StringQuery(InternalField.TAGLABEL, Operator.EQ, Modifier.NONE, operand); break; case Modifier.NONE: case null: argQuery = StringQuery(InternalField.TAGTERM, Operator.EQ, Modifier.EXACT, operand); break; default: throw new ArgumentException(String.Format("Invalid modifier {0} in parameter {1}", crit.Modifier, crit.ParamName)); } return(M.Query.ElemMatch(InternalField.TAG, M.Query.And(schemeQuery, argQuery))); }
public void ParseChain() { var crit = Criterium.Parse("par1:type1.par2.par3:text=hoi"); Assert.IsTrue(crit.Type == Operator.CHAIN); Assert.AreEqual("type1", crit.Modifier); Assert.IsTrue(crit.Operand is Criterium); crit = crit.Operand as Criterium; Assert.IsTrue(crit.Type == Operator.CHAIN); Assert.AreEqual(null, crit.Modifier); Assert.IsTrue(crit.Operand is Criterium); crit = crit.Operand as Criterium; Assert.IsTrue(crit.Type == Operator.EQ); Assert.AreEqual("text", crit.Modifier); Assert.IsTrue(crit.Operand is UntypedValue); }
public void HandleNumberParam() { var p1 = new NumberValue(18); Assert.AreEqual("18", p1.ToString()); var p2 = NumberValue.Parse("18"); Assert.AreEqual(18M, p2.Value); var p3 = NumberValue.Parse("18.00"); Assert.AreEqual(18.00M, p3.Value); var crit = Criterium.Parse("paramX=18.34"); var p4 = ((UntypedValue)crit.Operand).AsNumberValue(); Assert.AreEqual(18.34M, p4.Value); }
public void HandleStringParam() { var p1 = new StringValue("Hello, world"); Assert.AreEqual(@"Hello\, world", p1.ToString()); var p2 = new StringValue("Pay $300|Pay $100|"); Assert.AreEqual(@"Pay \$300\|Pay \$100\|", p2.ToString()); var p3 = StringValue.Parse(@"Pay \$300\|Pay \$100\|"); Assert.AreEqual("Pay $300|Pay $100|", p3.Value); var crit = Criterium.Parse(@"paramX=Hello\, world"); var p4 = ((UntypedValue)crit.Operand).AsStringValue(); Assert.AreEqual("Hello, world", p4.Value); }
public Criterium GetNormalizedReferenceCriteria(Criterium c) { if (c == null) { throw new ArgumentNullException(nameof(c)); } Expression operand; if (c.Operand is ChoiceValue choiceOperand) { var normalizedChoicesList = new ChoiceValue( choiceOperand.Choices.Select(choice => GetNormalizedReferenceValue(choice as UntypedValue, c.Modifier)) .Where(normalizedValue => normalizedValue != null) .ToList()); if (!normalizedChoicesList.Choices.Any()) { return(null); // Choice operator without choices: ignore it. } operand = normalizedChoicesList; } else { var normalizedValue = GetNormalizedReferenceValue(c.Operand as UntypedValue, c.Modifier); if (normalizedValue == null) { return(null); } operand = normalizedValue; } var cloned = c.Clone(); cloned.Modifier = null; cloned.Operand = operand; cloned.SearchParameters.AddRange(c.SearchParameters); return(cloned); }
internal static List <string> GetTargetedReferenceTypes(this Criterium chainCriterium, string resourceType) { if (chainCriterium.Operator != Operator.CHAIN) { throw new ArgumentException("Targeted reference types are only relevent for chained criteria."); } var critSp = chainCriterium.FindSearchParamDefinition(resourceType); var modifier = chainCriterium.Modifier; var nextInChain = (Criterium)chainCriterium.Operand; var nextParameter = nextInChain.ParamName; // The modifier contains the type of resource that the referenced resource must be. It is optional. // If not present, search all possible types of resources allowed at this reference. // If it is present, it should be of one of the possible types. var searchResourceTypes = GetTargetedReferenceTypes(critSp, modifier); // Afterwards, filter on the types that actually have the requested searchparameter. return(searchResourceTypes.Where(rt => InternalField.All.Contains(nextParameter) || UniversalField.All.Contains(nextParameter) || ModelInfo.SearchParameters.Exists(sp => rt.Equals(sp.Resource) && nextParameter.Equals(sp.Name))).ToList()); }
public void SerializeChain() { var crit = new Criterium { ParamName = "par1", Modifier = "type1", Type = Operator.CHAIN, Operand = new Criterium { ParamName = "par2", Type = Operator.CHAIN, Operand = new Criterium { ParamName = "par3", Modifier = "text", Type = Operator.EQ, Operand = new StringValue("hoi") } } }; Assert.AreEqual("par1:type1.par2.par3:text=hoi", crit.ToString()); }
internal static IMongoQuery ToFilter(this Criterium param, string resourceType) { //Maybe it's a generic parameter. MethodInfo methodForParameter = FixedQueries.Find(m => m.Name.Equals(param.ParamName + "FixedQuery")); if (methodForParameter != null) { return((IMongoQuery)methodForParameter.Invoke(null, new object[] { param })); } //Otherwise it should be a parameter as defined in the metadata var critSp = FindSearchParamDefinition(param, resourceType); if (critSp != null) { // todo: DSTU2 - modifier not in SearchParameter return(CreateFilter(critSp, param.Operator, param.Modifier, param.Operand)); //return null; } throw new ArgumentException(String.Format("Resource {0} has no parameter with the name {1}.", resourceType, param.ParamName)); }
public void HandleQuantityParam() { var p1 = new QuantityValue(3.141M, "http://unitsofmeasure.org", "mg"); Assert.AreEqual("3.141|http://unitsofmeasure.org|mg", p1.ToString()); var p2 = new QuantityValue(3.141M, "mg"); Assert.AreEqual("3.141||mg", p2.ToString()); var p3 = new QuantityValue(3.141M, "http://system.com/id$4", "$/d"); Assert.AreEqual(@"3.141|http://system.com/id\$4|\$/d", p3.ToString()); var p4 = QuantityValue.Parse("3.141|http://unitsofmeasure.org|mg"); Assert.AreEqual(3.141M, p4.Number); Assert.AreEqual("http://unitsofmeasure.org", p4.Namespace); Assert.AreEqual("mg", p4.Unit); var p5 = QuantityValue.Parse("3.141||mg"); Assert.AreEqual(3.141M, p5.Number); Assert.IsNull(p5.Namespace); Assert.AreEqual("mg", p5.Unit); var p6 = QuantityValue.Parse(@"3.141|http://system.com/id\$4|\$/d"); Assert.AreEqual(3.141M, p6.Number); Assert.AreEqual("http://system.com/id$4", p6.Namespace); Assert.AreEqual("$/d", p6.Unit); var crit = Criterium.Parse("paramX=3.14||mg"); var p7 = ((UntypedValue)crit.Operand).AsQuantityValue(); Assert.AreEqual(3.14M, p7.Number); Assert.IsNull(p7.Namespace); Assert.AreEqual("mg", p7.Unit); }
public void SerializeCriterium() { var crit = new Criterium { ParamName = "paramX", Modifier = "modif1", Operand = new NumberValue(18), Type = Operator.GTE }; Assert.AreEqual("paramX:modif1=>=18", crit.ToString()); crit = new Criterium { ParamName = "paramX", Operand = new NumberValue(18) }; Assert.AreEqual("paramX=18", crit.ToString()); crit = new Criterium { ParamName = "paramX", Type = Operator.ISNULL }; Assert.AreEqual("paramX:missing=true", crit.ToString()); crit = new Criterium { ParamName = "paramX", Type = Operator.NOTNULL }; Assert.AreEqual("paramX:missing=false", crit.ToString()); }
/// <inheritdoc /> public async Task <SearchResults> Search(string resource, SearchParams searchCommand) { _logger.LogDebug($"{resource} search requested with {searchCommand.ToUriParamList().ToQueryString()}"); var resources = await GetIndexValues(resource, searchCommand).ConfigureAwait(false); var count = resources.Count; if (searchCommand.Count.HasValue && searchCommand.Count.Value > 0) { resources = resources.Take(searchCommand.Count.Value).ToList(); } var keys = resources.ToList(); var results = new SearchResults { MatchCount = count, UsedCriteria = searchCommand.Parameters.Select(t => Criterium.Parse(t.Item1, t.Item2)).ToList() }; results.AddRange(keys); return(results); }
private static IMongoQuery CompositeQuery(ModelInfo.SearchParamDefinition parameterDef, Operator optor, String modifier, ValueExpression operand) { if (optor == Operator.IN) { var choices = ((ChoiceValue)operand); var queries = new List <IMongoQuery>(); foreach (var choice in choices.Choices) { queries.Add(CompositeQuery(parameterDef, Operator.EQ, modifier, choice)); } return(M.Query.Or(queries)); } else if (optor == Operator.EQ) { var typedOperand = (CompositeValue)operand; var queries = new List <IMongoQuery>(); var components = typedOperand.Components; var subParams = parameterDef.CompositeParams; if (components.Count() != subParams.Count()) { throw new ArgumentException(String.Format("Parameter {0} requires exactly {1} composite values, not the currently provided {2} values.", parameterDef.Name, subParams.Count(), components.Count())); } for (int i = 0; i < subParams.Count(); i++) { var subCrit = new Criterium(); subCrit.Operator = Operator.EQ; subCrit.ParamName = subParams[i]; subCrit.Operand = components[i]; subCrit.Modifier = modifier; queries.Add(subCrit.ToFilter(parameterDef.Resource)); } return(M.Query.And(queries)); } throw new ArgumentException(String.Format("Invalid operator {0} on composite parameter {1}", optor.ToString(), parameterDef.Name)); }
/// <summary> /// Getting Max Value from Criterium list /// </summary> /// <param name="critTable">Criterium - weight of criterium</param> /// <returns></returns> private Criterium GetMaxFromCrit (Dictionary <Criterium, int> critTable) { int maxVal = 0; Criterium crit = new Criterium(); foreach (KeyValuePair <Criterium, int> critPair in criteriumTable) { if (maxVal < critPair.Value) { maxVal = critPair.Value; } } foreach (KeyValuePair <Criterium, int> critPair in criteriumTable) { if (critPair.Value == maxVal) { crit = critPair.Key; } } return(crit); }
/// <summary> /// Change something like Condition/subject:Patient=Patient/10014 /// to Condition/subject:Patient.internal_id=Patient/10014, so it is correctly handled as a chained parameter, /// including the filtering on the type in the modifier (if any). /// </summary> /// <param name="criteria"></param> /// <param name="resourceType"></param> /// <returns></returns> private List<Criterium> NormalizeNonChainedReferenceCriteria(List<Criterium> criteria, string resourceType) { var result = new List<Criterium>(); foreach (var crit in criteria) { var critSp = crit.FindSearchParamDefinition(resourceType); // var critSp_ = _fhirModel.FindSearchParameter(resourceType, crit.ParamName); HIER VERDER: kunnen meerdere searchParameters zijn, hoewel dat alleen bij subcriteria van chains het geval is... if (critSp != null && critSp.Type == SearchParamType.Reference && crit.Operator != Operator.CHAIN && crit.Modifier != Modifier.MISSING && crit.Operand != null) { var subCrit = new Criterium(); subCrit.Operator = crit.Operator; string modifier = crit.Modifier; //operand can be one of three things: //1. just the id: 10014 (in the index as internal_justid), the type could be in the modifier //2. full id: Patient/10014 (in the index as internal_id), the type in the modifier is no longer relevant //3. full url: http://localhost:xyz/fhir/Patient/100014, the type in the modifier is also no longer relevant. string operand = (crit.Operand as UntypedValue).Value; if (!operand.Contains("/")) //Situation 1 { if (String.IsNullOrWhiteSpace(modifier)) // no modifier, so no info about the referenced type at all { subCrit.ParamName = InternalField.JUSTID; subCrit.Operand = new UntypedValue(operand); } else //modifier contains the referenced type { subCrit.ParamName = InternalField.ID; subCrit.Operand = new UntypedValue(modifier + "/" + operand); } } else //Situation 2 or Situation 3 . { subCrit.ParamName = InternalField.ID; Uri uriOperand; if (Uri.TryCreate(operand, UriKind.RelativeOrAbsolute, out uriOperand)) //Situation 3 { var refUri = _localhost.RemoveBase(uriOperand); //Drop the first part if it points to our own server. subCrit.Operand = new UntypedValue(refUri.ToString().TrimStart(new char[] { '/' })); } else { subCrit.Operand = new UntypedValue(operand); } } //subCrit.Operand = crit.Operand; var superCrit = new Criterium(); superCrit.ParamName = crit.ParamName; superCrit.Modifier = crit.Modifier; superCrit.Operator = Operator.CHAIN; superCrit.Operand = subCrit; superCrit.SearchParameters.AddRange(crit.SearchParameters); result.Add(superCrit); } else result.Add(crit); } return result; }
internal static IMongoQuery _securityFixedQuery(Criterium crit) { return TagQuery(crit, Tag.FHIRTAGSCHEME_SECURITY); }
private bool TryEnrichCriteriumWithSearchParameters(Criterium criterium, ResourceType resourceType) { var sp = _fhirModel.FindSearchParameter(resourceType, criterium.ParamName); if (sp == null) { return false; } var result = true; var spDef = sp.GetOriginalDefinition(); if (spDef != null) { criterium.SearchParameters.Add(spDef); } if (criterium.Operator == Operator.CHAIN) { var subCrit = (Criterium)(criterium.Operand); foreach (var targetType in criterium.SearchParameters.SelectMany(spd => spd.Target)) { result &= TryEnrichCriteriumWithSearchParameters(subCrit, targetType); } } return result; }
//internal static IMongoQuery _idFixedQuery(Criterium crit) //{ // return StringQuery(InternalField.JUSTID, crit.Operator, "exact", (ValueExpression)crit.Operand); //} internal static IMongoQuery internal_idFixedQuery(Criterium crit) { return StringQuery(InternalField.ID, crit.Operator, "exact", (ValueExpression)crit.Operand); }
private static IMongoQuery CompositeQuery(ModelInfo.SearchParamDefinition parameterDef, Operator optor, String modifier, ValueExpression operand) { if (optor == Operator.IN) { var choices = ((ChoiceValue)operand); var queries = new List<IMongoQuery>(); foreach (var choice in choices.Choices) { queries.Add(CompositeQuery(parameterDef, Operator.EQ, modifier, choice)); } return M.Query.Or(queries); } else if (optor == Operator.EQ) { var typedOperand = (CompositeValue)operand; var queries = new List<IMongoQuery>(); var components = typedOperand.Components; var subParams = parameterDef.CompositeParams; if (components.Count() != subParams.Count()) { throw new ArgumentException(String.Format("Parameter {0} requires exactly {1} composite values, not the currently provided {2} values.", parameterDef.Name, subParams.Count(), components.Count())); } for (int i = 0; i < subParams.Count(); i++) { var subCrit = new Criterium(); subCrit.Operator = Operator.EQ; subCrit.ParamName = subParams[i]; subCrit.Operand = components[i]; subCrit.Modifier = modifier; queries.Add(subCrit.ToFilter(parameterDef.Resource)); } return M.Query.And(queries); } throw new ArgumentException(String.Format("Invalid operator {0} on composite parameter {1}", optor.ToString(), parameterDef.Name)); }
/// <summary> /// Change something like Condition/subject:Patient=Patient/10014 /// to Condition/subject:Patient.internal_id=Patient/10014, so it is correctly handled as a chained parameter, /// including the filtering on the type in the modifier (if any). /// </summary> /// <param name="criteria"></param> /// <param name="resourceType"></param> /// <returns></returns> private List<Criterium> NormalizeNonChainedReferenceCriteria(List<Criterium> criteria, string resourceType) { var result = new List<Criterium>(); foreach (var crit in criteria) { var critSp = crit.FindSearchParamDefinition(resourceType); if (critSp != null && critSp.Type == Conformance.SearchParamType.Reference && crit.Type != Operator.CHAIN) { var subCrit = new Criterium(); subCrit.ParamName = InternalField.ID; subCrit.Type = crit.Type; subCrit.Operand = crit.Operand; var superCrit = new Criterium(); superCrit.ParamName = crit.ParamName; superCrit.Modifier = crit.Modifier; superCrit.Type = Operator.CHAIN; superCrit.Operand = subCrit; result.Add(superCrit); } else result.Add(crit); } return result; }
internal static IMongoQuery _profileFixedQuery(Criterium crit) { return TagQuery(crit, Tag.FHIRTAGSCHEME_PROFILE); }
internal static IMongoQuery _tagFixedQuery(Criterium crit) { return TagQuery(crit, Tag.FHIRTAGSCHEME_GENERAL); }
internal static IMongoQuery _profileFixedQuery(Criterium crit) { return TagQuery(crit, new Uri(XmlNs.TAG_PROFILE, UriKind.Absolute)); }
internal static IMongoQuery _securityFixedQuery(Criterium crit) { return TagQuery(crit, new Uri(XmlNs.TAG_SECURITY, UriKind.Absolute)); }
internal static IMongoQuery _tagFixedQuery(Criterium crit) { return TagQuery(crit, new Uri(XmlNs.FHIRTAG, UriKind.Absolute)); }
/// <summary> /// CloseCriterium("patient.name=\"Teun\"") -> "patient IN (id1,id2)" /// </summary> /// <param name="resourceType"></param> /// <param name="crit"></param> /// <returns></returns> private Criterium CloseCriterium(Criterium crit, string resourceType, int level) { List<string> targeted = crit.GetTargetedReferenceTypes(resourceType); List<string> allKeys = new List<string>(); var errors = new List<Exception>(); foreach (var target in targeted) { try { Criterium innerCriterium = (Criterium)crit.Operand; var keys = CollectKeys(target, new List<Criterium> { innerCriterium }, ++level); //Recursive call to CollectKeys! allKeys.AddRange(keys.Select(k => k.ToString())); } catch (Exception ex) { errors.Add(ex); } } if (errors.Count == targeted.Count()) { //It is possible that some of the targets don't support the current parameter. But if none do, there is a serious problem. throw new ArgumentException(String.Format("None of the possible target resources support querying for parameter {0}", crit.ParamName)); } crit.Operator = Operator.IN; crit.Operand = ChoiceValue.Parse(String.Join(",", allKeys)); return crit; }
/// <summary> /// CloseCriterium("patient.name=\"Teun\"") -> "patient=id1,id2" /// </summary> /// <param name="resourceType"></param> /// <param name="crit"></param> /// <returns></returns> private Criterium CloseCriterium(Criterium crit, string resourceType) { List<string> targeted = crit.GetTargetedReferenceTypes(resourceType); List<string> allKeys = new List<string>(); foreach (var target in targeted) { var keys = CollectKeys(target, new List<Criterium> { (Criterium)crit.Operand }); //Recursive call to CollectKeys! allKeys.AddRange(keys.Select(k => k.ToString())); } crit.Type = Operator.IN; crit.Operand = ChoiceValue.Parse(String.Join(",", allKeys)); return crit; }
private static IMongoQuery TagQuery(Criterium crit, Uri tagscheme) { if (crit.Type == Operator.IN) { IEnumerable<ValueExpression> opMultiple = ((ChoiceValue)crit.Operand).Choices; var optionQueries = new List<IMongoQuery>(); foreach (var choice in opMultiple) { Criterium option = new Criterium(); option.Type = Operator.EQ; option.Operand = choice; option.Modifier = crit.Modifier; option.ParamName = crit.ParamName; optionQueries.Add(TagQuery(option, tagscheme)); } return M.Query.Or(optionQueries); } //From here there's only 1 operand. IMongoQuery schemeQuery = M.Query.EQ(InternalField.TAGSCHEME, tagscheme.AbsoluteUri); IMongoQuery argQuery; var operand = (ValueExpression)crit.Operand; switch (crit.Modifier) { case Modifier.PARTIAL: argQuery = StringQuery(InternalField.TAGTERM, Operator.EQ, Modifier.NONE, operand); break; case Modifier.TEXT: argQuery = StringQuery(InternalField.TAGLABEL, Operator.EQ, Modifier.NONE, operand); break; case Modifier.NONE: case null: argQuery = StringQuery(InternalField.TAGTERM, Operator.EQ, Modifier.EXACT, operand); break; default: throw new ArgumentException(String.Format("Invalid modifier {0} in parameter {1}", crit.Modifier, crit.ParamName)); } return M.Query.ElemMatch(InternalField.TAG, M.Query.And(schemeQuery, argQuery)); }