public override bool Visit(ILinqBody body, ILinqBody context) { _stack.Push(body); try { return(base.Visit(body, context)); } finally { _stack.Pop(); } }
/// <summary> /// Creates a new <see cref="LinqFusionSelectBody"/> with the /// <paramref name="selection"/>, <paramref name="target"/>, /// and <paramref name="next"/> provided. /// </summary> /// <param name="selection">The <see cref="IExpression"/> /// which denotes what is selected as a result of the /// language integrated query.</param> /// <param name="target">The <see cref="String"/> representing the name of the /// range variable that the data from the grouped query is stored into.</param> /// <param name="next">The <see cref="ILinqBody"/> which /// continues the language integrated query.</param> public LinqFusionSelectBody(IExpression selection, string target, ILinqBody next) : base(selection) { this.target = new LinqRangeVariable(this, target); this.Next = next; }
/// <summary> /// Creates a new <see cref="LinqFusionGroupBody"/> with /// the <paramref name="selection"/>, <paramref name="key"/>, /// <paramref name="target"/> and <paramref name="next"/> /// provided. /// </summary> /// <param name="selection">The <see cref="IExpression"/> which /// acts as a selector on the data set to retrieve the data for the query.</param> /// <param name="key">The <see cref="IExpression"/> which acts /// as the key for grouping the <see cref="ILinqSelectBody.Selection"/>s.</param> /// <param name="target">The <see cref="String"/> representing the name of the /// range variable that the data from the grouped query is stored into.</param> /// <param name="next">The <see cref="ILinqBody"/> which /// continues the language integrated query.</param> public LinqFusionGroupBody(IExpression selection, IExpression key, string target, ILinqBody next) : base(selection, target, next) { this.Key = key; }
public ILinqExpression Build() { var path = new Stack <ILinqBodyBuilderParent>(); //Build a reverse-order listing of the current expression graph. for (ILinqBodyBuilderParent current = this; current != null; path.Push(current), current = current.Parent) { ; } ILinqExpression result = new LinqExpression(); int bodyCount = 0; var pathNodes = path.ToArray(); const int selectBody = 1, selectFuseBody = 3; const int groupBody = 2, groupFuseBody = 4; //Count the number of body continuations. for (int i = 0; i < pathNodes.Length; i++) { if (pathNodes[i] is ILinqTailBodyBuilder) { bodyCount++; } } int[] bodyTypes = new int[bodyCount]; int bodyIndex = 0; /* * * Iterate through and, from the tails, discern * the kind of body to use. * */ for (int i = 0; i < pathNodes.Length; i++) { if (pathNodes[i] is ILinqTailBodyBuilder) { bool last = i == pathNodes.Length - 1; if (pathNodes[i] is LinqTailGroupBodyBuilder) { bodyTypes[bodyIndex++] = last ? groupBody : groupFuseBody; } else { bodyTypes[bodyIndex++] = last ? selectBody : selectFuseBody; } } } ILinqBody currentBody = null; bodyIndex = 0; var selector = pathNodes[0] as LinqTypedFromBodyBuilder; /* * * The first element is always a from clause, either typed or * untyped. * * * This is why initialization pipeline is closed. * */ if (selector == null) { result.From = BuildFromClause(pathNodes[0] as LinqFromBodyBuilder); } else { result.From = BuildFromClause(selector); } /* * * Iterate through the elements and build the bodies, * linking the clauses in between. * */ for (int i = 1; i < pathNodes.Length; i++) { bool last = i == pathNodes.Length - 1; /* * * Create the initial body from the current element. * */ if (currentBody == null) { currentBody = result.Body = GetBody(bodyTypes[bodyIndex++]); if (currentBody == null) { throw new InvalidOperationException("Unknown error."); } } /* * * This breaks programming practice rules, bite me. * */ var fromClauseT = pathNodes[i] as LinqTypedFromBodyBuilder; if (fromClauseT != null) { currentBody.Clauses.From(fromClauseT.RangeVariableInfo, fromClauseT.RangeSource); continue; } var fromClause = pathNodes[i] as LinqFromBodyBuilder; if (fromClause != null) { currentBody.Clauses.From(fromClause.RangeVariableName, fromClause.RangeSource); continue; } var joinClauseT = pathNodes[i] as LinqTypedJoinBodyBuilder; if (joinClauseT != null) { currentBody.Clauses.Join(joinClauseT.RangeVariableInfo, joinClauseT.RangeSource, joinClauseT.LeftConditionSelector, joinClauseT.RightConditionSelector, joinClauseT.IntoTarget); continue; } var joinClause = pathNodes[i] as LinqJoinBodyBuilder; if (joinClause != null) { currentBody.Clauses.Join(joinClause.RangeVariableName, joinClause.RangeSource, joinClause.LeftConditionSelector, joinClause.RightConditionSelector, joinClause.IntoTarget); continue; } var letClause = pathNodes[i] as LinqLetBodyBuilder; if (letClause != null) { currentBody.Clauses.Let(letClause.RangeVariableName, letClause.RangeSource); continue; } var dOrderClause = pathNodes[i] as LinqDirectedOrderByBodyBuilder; if (dOrderClause != null) { /* * * Special case, forward glance needs made to determine the proper * clause to construct. * */ int lastClause = -1; for (int j = i + 1; j < pathNodes.Length; j++) { if (pathNodes[j] is LinqThenByBodyBuilder || pathNodes[j] is LinqDirectedThenByBodyBuilder) { lastClause = j; } else { break; } } if (lastClause == -1) { currentBody.Clauses.OrderBy(dOrderClause.OrderKey, dOrderClause.Direction); } else { var pairs = new LinqOrderingPair[(lastClause + 1) - i]; pairs[0] = new LinqOrderingPair(dOrderClause.OrderKey, dOrderClause.Direction); int lastValid = i; for (int j = i + 1; j <= lastClause; j++) { var dThenBy = pathNodes[j] as LinqDirectedThenByBodyBuilder; if (dThenBy != null) { pairs[j - i] = new LinqOrderingPair(dThenBy.OrderKey, dThenBy.Direction); lastValid = j; continue; } var thenBy = pathNodes[j] as LinqThenByBodyBuilder; if (thenBy != null) { pairs[j - i] = new LinqOrderingPair(thenBy.OrderKey); lastValid = j; continue; } break; } i = lastValid; currentBody.Clauses.OrderBy(pairs); } continue; } var orderClause = pathNodes[i] as LinqOrderByBodyBuilder; if (orderClause != null) { int lastClause = -1; for (int j = i + 1; j < pathNodes.Length; j++) { if (pathNodes[j] is LinqThenByBodyBuilder || pathNodes[j] is LinqDirectedThenByBodyBuilder) { lastClause = j; } else { break; } } if (lastClause == -1) { currentBody.Clauses.OrderBy(orderClause.OrderKey); } else { var pairs = new LinqOrderingPair[(lastClause + 1) - i]; pairs[0] = new LinqOrderingPair(orderClause.OrderKey); int lastValid = i; for (int j = i + 1; j <= lastClause; j++) { var dThenBy = pathNodes[j] as LinqDirectedThenByBodyBuilder; if (dThenBy != null) { pairs[j - i] = new LinqOrderingPair(dThenBy.OrderKey, dThenBy.Direction); lastValid = j; continue; } var thenBy = pathNodes[j] as LinqThenByBodyBuilder; if (thenBy != null) { pairs[j - i] = new LinqOrderingPair(thenBy.OrderKey); lastValid = j; continue; } break; } i = lastValid; currentBody.Clauses.OrderBy(pairs); } continue; } var whereClause = pathNodes[i] as LinqWhereBodyBuilder; if (whereClause != null) { currentBody.Clauses.Where(whereClause.BooleanCondition); continue; } var groupBuilder = pathNodes[i] as LinqTailGroupBodyBuilder; LinqTailSelectBodyBuilder selectBuilder; /* * * If we're working with a group builder... * */ if (groupBuilder != null) { var gbCurrent = currentBody as ILinqGroupBody; if (gbCurrent == null) { break; } /* * * No continuation, we're finished. * */ if (last) { gbCurrent.Key = groupBuilder.Key; gbCurrent.Selection = groupBuilder.Selection; break; } else { /* * * Link the current to the next, and set its * target 'into' range variable name. * */ var gfbCurrent = gbCurrent as ILinqFusionGroupBody; if (gfbCurrent == null) { break; } gfbCurrent.Key = groupBuilder.Key; gfbCurrent.Selection = groupBuilder.Selection; var next = pathNodes[++i] as LinqFusionBodyBuilder; if (next == null) { break; } gfbCurrent.Target.Name = next.IntoRangeName; gfbCurrent.Next = currentBody = GetBody(bodyTypes[bodyIndex++]); } } else if ((selectBuilder = pathNodes[i] as LinqTailSelectBodyBuilder) != null) { var sbCurrent = currentBody as ILinqSelectBody; if (sbCurrent == null) { break; } /* * * No continuation, we're finished. * */ if (last) { sbCurrent.Selection = selectBuilder.Selection; break; } else { /* * * Link the current to the next, and set its * target 'into' range variable name. * */ var sfbCurrent = sbCurrent as ILinqFusionSelectBody; if (sfbCurrent == null) { break; } sfbCurrent.Selection = selectBuilder.Selection; var next = pathNodes[++i] as LinqFusionBodyBuilder; if (next == null) { break; } sfbCurrent.Target.Name = next.IntoRangeName; sfbCurrent.Next = currentBody = GetBody(bodyTypes[bodyIndex++]); } } } return(result); }