2using System.Collections;
3using System.Collections.Generic;
4using System.Threading.Tasks;
13 internal class RangesCursor<T> : ICursor<T>
15 private readonly RangeInfo[] ranges;
16 private readonly IndexBTreeFile index;
17 private readonly IApplicableFilter[] additionalfilters;
18 private RangeInfo[] currentLimits;
19 private ICursor<T> currentRange;
20 private KeyValuePair<string, IApplicableFilter>[] startRangeFilters;
21 private KeyValuePair<string, IApplicableFilter>[] endRangeFilters;
22 private readonly FilesProvider provider;
23 private readonly
int nrRanges;
24 private int limitsUpdatedAt;
25 private readonly
bool firstAscending;
26 private readonly
bool[] ascending;
36 public RangesCursor(IndexBTreeFile Index, RangeInfo[] Ranges, IApplicableFilter[] AdditionalFilters, FilesProvider Provider)
40 this.additionalfilters = AdditionalFilters;
41 this.currentRange =
null;
42 this.ascending = Index.Ascending;
43 this.firstAscending = this.ascending[0];
44 this.nrRanges = this.ranges.Length;
45 this.provider = Provider;
55 public T Current => this.CurrentCursor.Current;
57 private ICursor<T> CurrentCursor
61 if (this.currentRange is
null)
62 throw new InvalidOperationException(
"Enumeration not started or has already ended.");
64 return this.currentRange;
71 public IObjectSerializer CurrentSerializer => this.CurrentCursor.CurrentSerializer;
77 public bool CurrentTypeCompatible => this.CurrentCursor.CurrentTypeCompatible;
84 public Guid CurrentObjectId => this.CurrentCursor.CurrentObjectId;
91 this.currentRange =
null;
108 object IEnumerator.Current => this.Current;
117 public bool MoveNext() => this.MoveNextAsyncLocked().Result;
126 this.currentLimits =
new RangeInfo[this.nrRanges];
127 this.currentRange =
null;
129 for (i = 0; i < this.nrRanges; i++)
130 this.currentLimits[i] = this.ranges[i].Copy();
139 public async Task<bool> MoveNextAsyncLocked()
145 if (this.currentRange is
null)
147 List<KeyValuePair<string, object>> SearchParameters =
new List<KeyValuePair<string, object>>();
148 List<KeyValuePair<string, IApplicableFilter>> StartFilters =
null;
149 List<KeyValuePair<string, IApplicableFilter>> EndFilters =
null;
153 for (i = 0; i < this.nrRanges; i++)
155 Range = this.currentLimits[i];
159 if (EndFilters is
null)
160 EndFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
162 SearchParameters.Add(
new KeyValuePair<string, object>(Range.FieldName, Range.Point));
163 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldEqualTo(Range.FieldName, Range.Point)));
171 if (this.ascending[i])
173 if (StartFilters is
null)
174 StartFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
176 if (Range.MinInclusive)
177 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
180 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
182 if (!Comparison.Increment(ref Value))
186 SearchParameters.Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
190 if (EndFilters is
null)
191 EndFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
193 if (Range.MinInclusive)
194 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
196 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
204 if (!this.ascending[i])
206 if (StartFilters is
null)
207 StartFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
209 if (Range.MaxInclusive)
210 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
213 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
215 if (!Comparison.Decrement(ref Value))
219 SearchParameters.Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
223 if (EndFilters is
null)
224 EndFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
226 if (Range.MaxInclusive)
227 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
229 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
235 if (this.firstAscending)
236 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(SearchParameters.ToArray());
238 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(SearchParameters.ToArray());
240 this.startRangeFilters = StartFilters?.ToArray();
241 this.endRangeFilters = EndFilters?.ToArray();
242 this.limitsUpdatedAt = this.nrRanges;
245 if (!await this.currentRange.MoveNextAsyncLocked())
247 this.currentRange =
null;
249 if (this.limitsUpdatedAt >= this.nrRanges)
255 if (!this.currentRange.CurrentTypeCompatible)
258 object CurrentValue = this.currentRange.Current;
260 string OutOfStartRangeField =
null;
261 string OutOfEndRangeField =
null;
265 if (!(this.additionalfilters is
null))
267 foreach (IApplicableFilter Filter
in this.additionalfilters)
269 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
277 if (!(this.startRangeFilters is
null))
279 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.startRangeFilters)
281 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
283 OutOfStartRangeField = Filter.Key;
290 if (!(this.endRangeFilters is
null) && OutOfStartRangeField is
null)
292 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.endRangeFilters)
294 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
296 OutOfEndRangeField = Filter.Key;
303 for (i = 0; i < this.limitsUpdatedAt; i++)
305 object FieldValue = await CurrentSerializer.
TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
307 if (!(FieldValue is
null))
309 if (this.ascending[i])
311 if (this.currentLimits[i].SetMin(FieldValue, !(OutOfStartRangeField is
null), out Smaller) && Smaller)
314 this.limitsUpdatedAt = i;
316 while (i < this.nrRanges)
318 this.ranges[i].CopyTo(this.currentLimits[i]);
325 if (this.currentLimits[i].SetMax(FieldValue, !(OutOfStartRangeField is
null), out Smaller) && Smaller)
328 this.limitsUpdatedAt = i;
330 while (i < this.nrRanges)
332 this.ranges[i].CopyTo(this.currentLimits[i]);
342 else if (!(OutOfStartRangeField is
null) || !(OutOfEndRangeField is
null))
344 this.currentRange =
null;
346 if (this.limitsUpdatedAt >= this.nrRanges)
358 public async Task<bool> MovePreviousAsyncLocked()
364 if (this.currentRange is
null)
366 List<KeyValuePair<string, object>> SearchParameters =
new List<KeyValuePair<string, object>>();
367 List<KeyValuePair<string, IApplicableFilter>> StartFilters =
null;
368 List<KeyValuePair<string, IApplicableFilter>> EndFilters =
null;
372 for (i = 0; i < this.nrRanges; i++)
374 Range = this.currentLimits[i];
378 if (EndFilters is
null)
379 EndFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
381 SearchParameters.Add(
new KeyValuePair<string, object>(Range.FieldName, Range.Point));
382 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldEqualTo(Range.FieldName, Range.Point)));
390 if (this.ascending[i])
392 if (EndFilters is
null)
393 EndFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
395 if (Range.MinInclusive)
396 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
398 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
402 if (StartFilters is
null)
403 StartFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
405 if (Range.MinInclusive)
406 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
409 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldGreaterThan(Range.FieldName, Value)));
411 if (!Comparison.Increment(ref Value))
415 SearchParameters.Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
423 if (this.ascending[i])
425 if (StartFilters is
null)
426 StartFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
428 if (Range.MaxInclusive)
429 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
432 StartFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
434 if (!Comparison.Decrement(ref Value))
438 SearchParameters.Add(
new KeyValuePair<string, object>(Range.FieldName, Value));
442 if (EndFilters is
null)
443 EndFilters =
new List<KeyValuePair<string, IApplicableFilter>>();
445 if (Range.MaxInclusive)
446 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
448 EndFilters.Add(
new KeyValuePair<string, IApplicableFilter>(Range.FieldName,
new FilterFieldLesserThan(Range.FieldName, Value)));
454 if (this.firstAscending)
455 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(SearchParameters.ToArray());
457 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(SearchParameters.ToArray());
459 this.startRangeFilters = StartFilters?.ToArray();
460 this.endRangeFilters = EndFilters?.ToArray();
461 this.limitsUpdatedAt = this.nrRanges;
464 if (!await this.currentRange.MovePreviousAsyncLocked())
466 this.currentRange =
null;
468 if (this.limitsUpdatedAt >= this.nrRanges)
474 if (!this.currentRange.CurrentTypeCompatible)
477 object CurrentValue = this.currentRange.Current;
479 string OutOfStartRangeField =
null;
480 string OutOfEndRangeField =
null;
484 if (!(this.additionalfilters is
null))
486 foreach (IApplicableFilter Filter
in this.additionalfilters)
488 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
496 if (!(this.startRangeFilters is
null))
498 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.startRangeFilters)
500 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
502 OutOfStartRangeField = Filter.Key;
509 if (!(this.endRangeFilters is
null) && OutOfStartRangeField is
null)
511 foreach (KeyValuePair<string, IApplicableFilter> Filter
in this.endRangeFilters)
513 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer,
this.provider))
515 OutOfEndRangeField = Filter.Key;
522 for (i = 0; i < this.limitsUpdatedAt; i++)
524 object FieldValue = await CurrentSerializer.
TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
526 if (!(FieldValue is
null))
528 if (this.ascending[i])
530 if (this.currentLimits[i].SetMax(FieldValue, !(OutOfStartRangeField is
null), out Smaller) && Smaller)
533 this.limitsUpdatedAt = i;
535 while (i < this.nrRanges)
537 this.ranges[i].CopyTo(this.currentLimits[i]);
544 if (this.currentLimits[i].SetMin(FieldValue, !(OutOfStartRangeField is
null), out Smaller) && Smaller)
547 this.limitsUpdatedAt = i;
549 while (i < this.nrRanges)
551 this.ranges[i].CopyTo(this.currentLimits[i]);
561 else if (!(OutOfStartRangeField is
null) || !(OutOfEndRangeField is
null))
563 this.currentRange =
null;
565 if (this.limitsUpdatedAt >= this.nrRanges)
578 public bool SameSortOrder(
string[] ConstantFields,
string[] SortOrder)
580 return this.index.SameSortOrder(ConstantFields, SortOrder);
590 public bool ReverseSortOrder(
string[] ConstantFields,
string[] SortOrder)
592 return this.index.ReverseSortOrder(ConstantFields, SortOrder);
599 public Task ContinueAfterLocked(T LastItem)
601 throw new NotSupportedException(
"Paginated search is not supported for queries with multiple ranges.");
608 public Task ContinueBeforeLocked(T LastItem)
610 throw new NotSupportedException(
"Paginated search is not supported for queries with multiple ranges.");
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.