/// <summary> /// Evaluates the node, using the variables provided in the <paramref name="Variables"/> collection. /// </summary> /// <param name="Variables">Variables collection.</param> /// <returns>Result.</returns> public override IElement Evaluate(Variables Variables) { IElement E; int Top; int Offset; int i, c; if (this.top != null) { E = this.top.Evaluate(Variables); Top = (int)Expression.ToDouble(E.AssociatedObjectValue); if (Top <= 0) { throw new ScriptRuntimeException("TOP must evaluate to a positive integer.", this.top); } } else { Top = int.MaxValue; } if (this.offset != null) { E = this.offset.Evaluate(Variables); Offset = (int)Expression.ToDouble(E.AssociatedObjectValue); if (Offset < 0) { throw new ScriptRuntimeException("OFFSET must evaluate to a non-negative integer.", this.offset); } } else { Offset = 0; } c = this.sources.Length; if (c != 1) { throw new ScriptRuntimeException("Joinds between multiple sources not supported.", this); } E = this.sources[0].Evaluate(Variables); if (!(E.AssociatedObjectValue is Type T)) { throw new ScriptRuntimeException("Type expected.", this.sources[0]); } List <string> OrderBy = new List <string>(); bool CalculatedOrder = false; if (this.orderBy != null) { foreach (KeyValuePair <ScriptNode, bool> Node in this.orderBy) { if (Node.Key is VariableReference Ref) { if (Node.Value) { OrderBy.Add(Ref.VariableName); } else { OrderBy.Add("-" + Ref.VariableName); } } else { CalculatedOrder = true; } } } if (this.groupBy != null) { foreach (ScriptNode Node in this.groupBy) { if (Node is VariableReference Ref) { if (!OrderBy.Contains(Ref.VariableName)) { OrderBy.Add(Ref.VariableName); } } else { CalculatedOrder = true; } } } bool ManualPaging = this.groupBy != null || this.where != null; bool ManualTop = Top != int.MaxValue && ManualPaging; bool ManualOffset = Offset != 0 && ManualPaging; IEnumerator e = Find(T, ManualOffset ? 0 : Offset, ManualTop ? int.MaxValue : Top, this.where, Variables, OrderBy.ToArray(), this); LinkedList <IElement[]> Items = new LinkedList <IElement[]>(); Dictionary <string, int> Columns = new Dictionary <string, int>(); IElement[] Rec; int NrRecords = 0; if (this.columns != null) { c = this.columns.Length; for (i = 0; i < c; i++) { if (this.columns[i] is VariableReference Ref) { Columns[Ref.VariableName] = i; } } } else { c = 0; } if (this.where != null) { e = new ConditionalEnumerator(e, Variables, this.where); } if (this.groupBy != null) { e = new GroupEnumerator(e, Variables, this.groupBy, this.groupByNames); if (this.having != null) { e = new ConditionalEnumerator(e, Variables, this.having); } } if (CalculatedOrder) { List <KeyValuePair <ScriptNode, bool> > Order = new List <KeyValuePair <ScriptNode, bool> >(); if (this.orderBy != null) { Order.AddRange(this.orderBy); } if (this.groupByNames != null) { foreach (ScriptNode Group in this.groupByNames) { if (Group != null) { Order.Add(new KeyValuePair <ScriptNode, bool>(Group, true)); } } } e = new CustomOrderEnumerator(e, Variables, Order.ToArray()); } while (e.MoveNext()) { if (ManualOffset && Offset > 0) { Offset--; continue; } object Item = e.Current; ObjectProperties Properties = new ObjectProperties(Item, Variables); if (this.columns is null) { Rec = new IElement[1] { Expression.Encapsulate(Item) } } ; else { Rec = new IElement[c]; for (i = 0; i < c; i++) { try { Rec[i] = this.columns[i].Evaluate(Properties); } catch (Exception ex) { ex = Log.UnnestException(ex); Rec[i] = Expression.Encapsulate(ex); } } } Items.AddLast(Rec); NrRecords++; if (ManualTop && NrRecords >= Top) { break; } } IElement[] Elements = new IElement[this.columns is null ? NrRecords : NrRecords * c];
/// <summary> /// Evaluates the node asynchronously, using the variables provided in /// the <paramref name="Variables"/> collection. /// </summary> /// <param name="Variables">Variables collection.</param> /// <returns>Result.</returns> public async Task <IElement> EvaluateAsync(Variables Variables) { IElement E; int Top; int Offset; int i, c; if (this.top != null) { E = this.top.Evaluate(Variables); Top = (int)Expression.ToDouble(E.AssociatedObjectValue); if (Top <= 0) { throw new ScriptRuntimeException("TOP must evaluate to a positive integer.", this.top); } } else { Top = int.MaxValue; } if (this.offset != null) { E = this.offset.Evaluate(Variables); Offset = (int)Expression.ToDouble(E.AssociatedObjectValue); if (Offset < 0) { throw new ScriptRuntimeException("OFFSET must evaluate to a non-negative integer.", this.offset); } } else { Offset = 0; } IDataSource Source = this.source.GetSource(Variables); List <KeyValuePair <VariableReference, bool> > OrderBy = new List <KeyValuePair <VariableReference, bool> >(); bool CalculatedOrder = false; if (this.orderBy != null) { foreach (KeyValuePair <ScriptNode, bool> Node in this.orderBy) { if (Node.Key is VariableReference Ref) { OrderBy.Add(new KeyValuePair <VariableReference, bool>(Ref, Node.Value)); } else { CalculatedOrder = true; break; } } } if (this.groupBy != null && !CalculatedOrder) { foreach (ScriptNode Node in this.groupBy) { if (Node is VariableReference Ref) { bool Found = false; foreach (KeyValuePair <VariableReference, bool> P in OrderBy) { if (P.Key.VariableName == Ref.VariableName) { Found = true; break; } } if (!Found) { OrderBy.Add(new KeyValuePair <VariableReference, bool>(Ref, true)); } } else { CalculatedOrder = true; break; } } } LinkedList <IElement[]> Items = new LinkedList <IElement[]>(); Dictionary <string, int> Columns = new Dictionary <string, int>(); IResultSetEnumerator e; RecordEnumerator e2; int NrRecords = 0; if (this.columns != null) { c = this.columns.Length; for (i = 0; i < c; i++) { if (this.columns[i] is VariableReference Ref) { Columns[Ref.VariableName] = i; } } } else { c = 0; } if (this.groupBy is null) { e = await Source.Find(Offset, Top, this.where, Variables, OrderBy.ToArray(), this); Offset = 0; Top = int.MaxValue; } else { e = await Source.Find(0, int.MaxValue, this.where, Variables, OrderBy.ToArray(), this); } if (this.groupBy != null) { e = new GroupEnumerator(e, Variables, this.groupBy, this.groupByNames); if (this.having != null) { e = new ConditionalEnumerator(e, Variables, this.having); } } if (CalculatedOrder) { List <KeyValuePair <ScriptNode, bool> > Order = new List <KeyValuePair <ScriptNode, bool> >(); if (this.orderBy != null) { Order.AddRange(this.orderBy); } if (this.groupByNames != null) { foreach (ScriptNode Group in this.groupByNames) { if (Group != null) { Order.Add(new KeyValuePair <ScriptNode, bool>(Group, true)); } } } e = new CustomOrderEnumerator(e, Variables, Order.ToArray()); } if (Offset > 0) { e = new OffsetEnumerator(e, Offset); } if (Top != int.MaxValue) { e = new MaxCountEnumerator(e, Top); } if (this.distinct) { e2 = new DistinctEnumerator(e, this.columns, Variables); } else { e2 = new RecordEnumerator(e, this.columns, Variables); } while (await e2.MoveNextAsync()) { Items.AddLast(e2.CurrentRecord); NrRecords++; } IElement[] Elements = new IElement[this.columns is null ? NrRecords : NrRecords * c];