4using System.Threading.Tasks;
14 internal class RangesCursor<T> : ICursor<T>
16 private readonly RangeInfo[] ranges;
17 private readonly IndexBTreeFile index;
18 private readonly IApplicableFilter[] additionalFilters;
19 private RangeInfo[] currentLimits;
20 private ICursor<T> currentRange;
21 private KeyValuePair<string, IApplicableFilter>[] startRangeFilters;
22 private KeyValuePair<string, IApplicableFilter>[] endRangeFilters;
23 private readonly FilesProvider provider;
24 private readonly
int nrRanges;
25 private int limitsUpdatedAt;
26 private readonly
bool firstAscending;
27 private readonly
bool[] ascending;
29 private Type prevType =
null;
40 public RangesCursor(IndexBTreeFile Index, RangeInfo[] Ranges,
41 IApplicableFilter[] AdditionalFilters, FilesProvider Provider)
45 this.additionalFilters = AdditionalFilters;
46 this.currentRange =
null;
47 this.ascending = Index.Ascending;
48 this.firstAscending = this.ascending[0];
49 this.nrRanges = this.ranges.Length;
50 this.provider = Provider;
60 public T Current => this.CurrentCursor.Current;
62 private ICursor<T> CurrentCursor
66 if (this.currentRange is
null)
67 throw new InvalidOperationException(
"Enumeration not started or has already ended.");
69 return this.currentRange;
76 public IObjectSerializer CurrentSerializer => this.CurrentCursor.CurrentSerializer;
82 public bool CurrentTypeCompatible => this.CurrentCursor.CurrentTypeCompatible;
89 public Guid CurrentObjectId => this.CurrentCursor.CurrentObjectId;
96 this.currentRange =
null;
113 object IEnumerator.Current => this.Current;
122 public bool MoveNext() => this.MoveNextAsyncLocked().Result;
131 this.currentLimits =
new RangeInfo[this.nrRanges];
132 this.currentRange =
null;
134 for (i = 0; i < this.nrRanges; i++)
135 this.currentLimits[i] = this.ranges[i].Copy();
144 public async Task<bool> MoveNextAsyncLocked()
150 if (this.currentRange is
null)
158 for (i = 0; i < this.nrRanges; i++)
160 Range = this.currentLimits[i];
164 if (EndFilters is
null)
167 SearchParameters.
Add(
new KeyValuePair<string, object>(Range.FieldName, Range.Point));
168 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldEqualTo(Range.FieldName, Range.Point)));
176 if (this.ascending[i])
178 if (StartFilters is
null)
181 if (Range.MinInclusive)
182 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
185 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
187 if (!Comparison.Increment(ref Value))
191 SearchParameters.
Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
195 if (EndFilters is
null)
198 if (Range.MinInclusive)
199 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
201 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
209 if (this.ascending[i])
211 if (EndFilters is
null)
214 if (Range.MaxInclusive)
215 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
217 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
221 if (StartFilters is
null)
224 if (Range.MaxInclusive)
225 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
228 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
230 if (!Comparison.Decrement(ref Value))
234 SearchParameters.
Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
240 if (this.firstAscending)
242 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(
247 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(
251 this.startRangeFilters = StartFilters?.
ToArray();
252 this.endRangeFilters = EndFilters?.
ToArray();
253 this.limitsUpdatedAt = this.nrRanges;
256 if (!await this.currentRange.MoveNextAsyncLocked())
258 this.currentRange =
null;
260 if (this.limitsUpdatedAt >= this.nrRanges)
266 if (!this.currentRange.CurrentTypeCompatible)
269 object CurrentValue = this.currentRange.Current;
270 Type CurrentType = CurrentValue.GetType();
272 int OutOfStartRangeFieldIndex = -1;
273 int OutOfEndRangeFieldIndex = -1;
277 if (CurrentSerializer.
ValueType != CurrentType)
279 if (CurrentType == this.prevType)
280 CurrentSerializer = this.prevSerializer;
283 CurrentSerializer = this.prevSerializer = await this.provider.GetObjectSerializer(CurrentType);
284 this.prevType = CurrentType;
288 if (!(this.additionalFilters is
null))
290 foreach (IApplicableFilter Filter
in this.additionalFilters)
292 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
300 if (!(this.startRangeFilters is
null))
303 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.startRangeFilters)
305 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
307 OutOfStartRangeFieldIndex = i;
316 if (!(this.endRangeFilters is
null) && OutOfStartRangeFieldIndex < 0)
319 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.endRangeFilters)
321 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
323 OutOfEndRangeFieldIndex = i;
332 for (i = 0; i < this.limitsUpdatedAt; i++)
334 object FieldValue = await CurrentSerializer.
TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
335 if (FieldValue is
null)
338 bool Inclusive = OutOfStartRangeFieldIndex >= 0;
340 if (this.ascending[i])
342 if (this.currentLimits[i].SetMin(FieldValue,
343 Inclusive, out Smaller) && Smaller)
346 this.limitsUpdatedAt = i;
348 while (i < this.nrRanges)
350 this.ranges[i].CopyTo(this.currentLimits[i]);
357 if (this.currentLimits[i].SetMax(FieldValue,
358 Inclusive, out Smaller) && Smaller)
361 this.limitsUpdatedAt = i;
363 while (i < this.nrRanges)
365 this.ranges[i].CopyTo(this.currentLimits[i]);
375 if (OutOfStartRangeFieldIndex >= 0 || OutOfEndRangeFieldIndex >= 0)
377 this.currentRange =
null;
379 if (this.limitsUpdatedAt >= this.nrRanges)
391 public async Task<bool> MovePreviousAsyncLocked()
397 if (this.currentRange is
null)
405 for (i = 0; i < this.nrRanges; i++)
407 Range = this.currentLimits[i];
411 if (EndFilters is
null)
414 SearchParameters.
Add(
new KeyValuePair<string, object>(Range.FieldName, Range.Point));
415 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldEqualTo(Range.FieldName, Range.Point)));
423 if (this.ascending[i])
425 if (EndFilters is
null)
428 if (Range.MinInclusive)
429 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
431 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
435 if (StartFilters is
null)
438 if (Range.MinInclusive)
439 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
442 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
444 if (!Comparison.Increment(ref Value))
448 SearchParameters.
Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
456 if (this.ascending[i])
458 if (StartFilters is
null)
461 if (Range.MaxInclusive)
462 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
465 StartFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
467 if (!Comparison.Decrement(ref Value))
471 SearchParameters.
Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
475 if (EndFilters is
null)
478 if (Range.MaxInclusive)
479 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
481 EndFilters.
Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
487 if (this.firstAscending)
489 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(
494 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(
498 this.startRangeFilters = StartFilters?.
ToArray();
499 this.endRangeFilters = EndFilters?.
ToArray();
500 this.limitsUpdatedAt = this.nrRanges;
503 if (!await this.currentRange.MovePreviousAsyncLocked())
505 this.currentRange =
null;
507 if (this.limitsUpdatedAt >= this.nrRanges)
513 if (!this.currentRange.CurrentTypeCompatible)
516 object CurrentValue = this.currentRange.Current;
517 Type CurrentType = CurrentValue.GetType();
519 int OutOfStartRangeFieldIndex = -1;
520 int OutOfEndRangeFieldIndex = -1;
524 if (CurrentSerializer.
ValueType != CurrentType)
526 if (CurrentType == this.prevType)
527 CurrentSerializer = this.prevSerializer;
530 CurrentSerializer = this.prevSerializer = await this.provider.GetObjectSerializer(CurrentType);
531 this.prevType = CurrentType;
535 if (!(this.additionalFilters is
null))
537 foreach (IApplicableFilter Filter
in this.additionalFilters)
539 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
547 if (!(this.startRangeFilters is
null))
550 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.startRangeFilters)
552 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
554 OutOfStartRangeFieldIndex = i;
563 if (!(this.endRangeFilters is
null) && OutOfStartRangeFieldIndex < 0)
566 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.endRangeFilters)
568 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
570 OutOfEndRangeFieldIndex = i;
579 for (i = 0; i < this.limitsUpdatedAt; i++)
581 object FieldValue = await CurrentSerializer.
TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
582 if (FieldValue is
null)
585 bool Inclusive = OutOfStartRangeFieldIndex >= 0;
587 if (this.ascending[i])
589 if (this.currentLimits[i].SetMax(FieldValue,
590 Inclusive, out Smaller) && Smaller)
593 this.limitsUpdatedAt = i;
595 while (i < this.nrRanges)
597 this.ranges[i].CopyTo(this.currentLimits[i]);
604 if (this.currentLimits[i].SetMin(FieldValue,
605 Inclusive, out Smaller) && Smaller)
608 this.limitsUpdatedAt = i;
610 while (i < this.nrRanges)
612 this.ranges[i].CopyTo(this.currentLimits[i]);
622 if (OutOfStartRangeFieldIndex >= 0 || OutOfEndRangeFieldIndex >= 0)
624 this.currentRange =
null;
626 if (this.limitsUpdatedAt >= this.nrRanges)
639 public bool SameSortOrder(
string[] ConstantFields,
string[] SortOrder)
641 return this.index.SameSortOrder(ConstantFields, SortOrder);
651 public bool ReverseSortOrder(
string[] ConstantFields,
string[] SortOrder)
653 return this.index.ReverseSortOrder(ConstantFields, SortOrder);
660 public Task ContinueAfterLocked(T LastItem)
662 throw new NotSupportedException(
"Paginated search is not supported for queries with multiple ranges.");
669 public Task ContinueBeforeLocked(T LastItem)
671 throw new NotSupportedException(
"Paginated search is not supported for queries with multiple ranges.");
677 public bool CanSkip =>
false;
684 public Task<bool> Skip(
long NrObjects) => Task.FromResult(
false);
A chunked list is a linked list of chunks of objects of type T .
void Add(T Item)
Adds an item to the collection.
T[] ToArray()
Returns an array containing all elements of the collection.
Interface for asynchronous enumerators.
Task< bool > MoveNextAsync()
Advances the enumerator to the next element of the collection.
Interface for object serializers.
Task< object > TryGetFieldValue(string FieldName, object Object)
Gets the value of a field or property of an object, given its name.
Type ValueType
What type of object is being serialized.