/// <summary> /// GROUP BY: Apply groupBy expression and aggregate results in DocumentGroup /// </summary> private IEnumerable <DocumentGroup> GroupBy(IEnumerable <BsonDocument> source, GroupBy groupBy) { using (var enumerator = source.GetEnumerator()) { var done = new Done { Running = enumerator.MoveNext() }; while (done.Running) { var key = groupBy.Expression.ExecuteScalar(enumerator.Current); groupBy.Select.Parameters["key"] = key; var group = YieldDocuments(key, enumerator, groupBy, done); yield return(new DocumentGroup(key, enumerator.Current, group, _lookup)); } } }
/// <summary> /// YieldDocuments will run over all key-ordered source and returns groups of source /// </summary> private IEnumerable <BsonDocument> YieldDocuments(BsonValue key, IEnumerator <BsonDocument> enumerator, GroupBy groupBy, Done done) { yield return(enumerator.Current); while (done.Running = enumerator.MoveNext()) { var current = groupBy.Expression.ExecuteScalar(enumerator.Current); if (key == current) { // yield return document in same key (group) yield return(enumerator.Current); } else { groupBy.Select.Parameters["key"] = current; // stop current sequence yield break; } } }
/// <summary> /// Split values in many IEnumerable. Each enumerable contains values to be insert in a single container /// </summary> private IEnumerable <IEnumerable <KeyValuePair <BsonValue, PageAddress> > > SliptValues(IEnumerable <KeyValuePair <BsonValue, PageAddress> > source, Done done) { using (var enumerator = source.GetEnumerator()) { if (enumerator.MoveNext()) { done.Count = 1; while (done.Running) { yield return(this.YieldValues(enumerator, done)); } } } }
/// <summary> /// Loop in values enumerator to return N values for a single container /// </summary> private IEnumerable <KeyValuePair <BsonValue, PageAddress> > YieldValues(IEnumerator <KeyValuePair <BsonValue, PageAddress> > source, Done done) { var size = SortContainer.GetKeyLength(source.Current.Key) + PageAddress.SIZE; yield return(source.Current); while (source.MoveNext()) { var length = SortContainer.GetKeyLength(source.Current.Key) + PageAddress.SIZE; done.Count++; if (size + length > _containerSize) { yield break; } size += length; yield return(source.Current); } done.Running = false; }
/// <summary> /// Loop in values enumerator to return N values for a single container /// </summary> private IEnumerable <KeyValuePair <BsonValue, PageAddress> > YieldValues(IEnumerator <KeyValuePair <BsonValue, PageAddress> > source, Done done) { var size = IndexNode.GetKeyLength(source.Current.Key, false) + PageAddress.SIZE; if (size > MAX_INDEX_KEY_LENGTH) { throw new LiteException(0, $"Current value are larger than {MAX_INDEX_KEY_LENGTH} bytes and can't be sorted."); } yield return(source.Current); while (source.MoveNext()) { var length = IndexNode.GetKeyLength(source.Current.Key, false) + PageAddress.SIZE; done.Count++; if (size + length > _containerSize) { yield break; } size += length; yield return(source.Current); } done.Running = false; }