protected virtual void EmitBetweenExpression(BetweenExpression expression) { Append("("); EmitExpression(expression.Expression); Append(" between "); EmitExpression(expression.LowerExpression); Append(" and "); EmitExpression(expression.UpperExpression); Append(")"); }
public object Translate(TranslationContext context, ASTNode node) { // In(element, interval)... // In(element, list) // Translate as: // exists (select * from (<list>) T where <element equality condition>) // As long as this is list containment, it can be translated using an Exists(Filter(Collection, Condition(Current = Element))); var elementNode = node.Children[0]; var collectionNode = node.Children[1]; if (elementNode.ResultType is ListType) { throw new NotSupportedException("In translation with an element of type list is not supported because there is no equivalent SQL representation."); } if (collectionNode.ResultType is ListType) { var selectExpression = new SQLModel.SelectExpression(); selectExpression.SelectClause = new SQLModel.SelectClause(); selectExpression.SelectClause.NonProject = true; selectExpression.FromClause = new SQLModel.CalculusFromClause(new SQLModel.TableSpecifier(SQLTranslationUtilities.EnsureSelectStatementExpression(context.TranslateNode(collectionNode)), "T")); selectExpression.WhereClause = new SQLModel.WhereClause(); Model.Expression condition = null; if (elementNode.ResultType is ObjectType) { foreach (var property in ((ObjectType)elementNode.ResultType).Properties) { // TODO: O is an assumed alias here, need a way to establish the outer context for comparison of the element.... var propertyCondition = new Model.BinaryExpression(new SQLModel.QualifiedFieldExpression(property.Name, "T"), "iEqual", new SQLModel.QualifiedFieldExpression(property.Name, "O")); if (condition == null) { condition = propertyCondition; } else { condition = new Model.BinaryExpression(condition, "iAnd", propertyCondition); } } } else { condition = new Model.BinaryExpression(new SQLModel.QualifiedFieldExpression("value", "T"), "iEqual", (Model.Expression)context.TranslateNode(elementNode)); } selectExpression.WhereClause.Expression = condition; return selectExpression; } else { var betweenExpression = new Model.BetweenExpression(); betweenExpression.Expression = (Model.Expression)context.TranslateNode(elementNode); // TODO: Translate an interval selector.... betweenExpression.LowerExpression = new Model.ValueExpression(1); betweenExpression.UpperExpression = new Model.ValueExpression(1); return betweenExpression; } }
public object Translate(TranslationContext context, ASTNode node) { var requestListType = node.ResultType as ListType; var requestType = (requestListType == null ? node.ResultType : requestListType.ElementType) as ObjectType; if (requestType == null) { throw new InvalidOperationException(String.Format("Unable to determine request type from source type: '{0}'.", node.ResultType.Name)); } Model.Expression condition = null; // Translate Codes var codes = node.Children.Where(n => n.Name == "codes").FirstOrDefault(); if (codes != null) { var codesResult = context.TranslateNode(codes); // codesResult will be a select statement returning the list of codes // So the retrieve must include a where condition limiting the code property to the set of codes (same as InValueSet translation) var codeExpression = SQLTranslationUtilities.ResolvePath(node.GetAttribute<string>("codeProperty"), "T"); var selectExpression = (SQLModel.SelectExpression)codesResult; // This assumes the codes element is a ValueSetRef... selectExpression.WhereClause.Expression = new Model.BinaryExpression ( selectExpression.WhereClause.Expression, "iAnd", new Model.BinaryExpression(codeExpression, "iEqual", new SQLModel.QualifiedFieldExpression("Code", "VS")) ); var codeCondition = new Model.UnaryExpression("iExists", selectExpression); if (condition != null) { condition = new Model.BinaryExpression(condition, "iAnd", codeCondition); } else { condition = codeCondition; } } // Translate DateRange var dateRange = node.Children.Where(n => n.Name == "dateRange").FirstOrDefault(); if (dateRange != null) { var dateRangeResult = context.TranslateNode(dateRange); var dateExpression = SQLTranslationUtilities.ResolvePath(node.GetAttribute<string>("dateProperty"), "T"); // dateRangeResult will be an interval-valued expression // So the retrieve must include a where condition limiting the date range property to the interval (same as In(date, interval) translation) var dateRangeCondition = new Model.BetweenExpression(); dateRangeCondition.Expression = dateExpression; // TODO: //dateRangeCondition.LowerExpression = // dateRangeResult.Low... //dateRangeCondition.UpperExpression = // dateRangeResult.High... //if (condition != null) //{ // condition = new Model.BinaryExpression(condition, "iAnd", dateRangeCondition); //} //else //{ // condition = codeCondition; //} } // For FHIR, there will also potentially need to be profile filters... // This depends on how the FHIR model is realized within the SQL structures... var inQueryContext = ((SQLTranslationContext)context).InQueryContext(); // Within a Query Context, a retrieve is part of a FromClause var tableExpression = new SQLModel.TableExpression(requestType.Name); if (inQueryContext && (condition == null)) { return tableExpression; } else { var selectExpression = new SQLModel.SelectExpression(); selectExpression.SelectClause = new SQLModel.SelectClause(); selectExpression.SelectClause.Distinct = false; selectExpression.SelectClause.NonProject = true; selectExpression.FromClause = new SQLModel.CalculusFromClause(new SQLModel.TableSpecifier(tableExpression, "T")); if (condition != null) { selectExpression.WhereClause = new SQLModel.WhereClause(); selectExpression.WhereClause.Expression = condition; } return selectExpression; } }