Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
RangesCursor.cs
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Threading.Tasks;
6
8{
13 internal class RangesCursor<T> : ICursor<T>
14 {
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;
27
36 public RangesCursor(IndexBTreeFile Index, RangeInfo[] Ranges, IApplicableFilter[] AdditionalFilters, FilesProvider Provider)
37 {
38 this.index = Index;
39 this.ranges = Ranges;
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;
46
47 this.Reset();
48 }
49
55 public T Current => this.CurrentCursor.Current;
56
57 private ICursor<T> CurrentCursor
58 {
59 get
60 {
61 if (this.currentRange is null)
62 throw new InvalidOperationException("Enumeration not started or has already ended.");
63 else
64 return this.currentRange;
65 }
66 }
67
71 public IObjectSerializer CurrentSerializer => this.CurrentCursor.CurrentSerializer;
72
77 public bool CurrentTypeCompatible => this.CurrentCursor.CurrentTypeCompatible;
78
84 public Guid CurrentObjectId => this.CurrentCursor.CurrentObjectId;
85
89 public void Dispose()
90 {
91 this.currentRange = null;
92 }
93
101 Task<bool> IAsyncEnumerator.MoveNextAsync() => this.MoveNextAsyncLocked();
102
108 object IEnumerator.Current => this.Current;
109
117 public bool MoveNext() => this.MoveNextAsyncLocked().Result;
118
122 public void Reset()
123 {
124 int i;
125
126 this.currentLimits = new RangeInfo[this.nrRanges];
127 this.currentRange = null;
128
129 for (i = 0; i < this.nrRanges; i++)
130 this.currentLimits[i] = this.ranges[i].Copy();
131 }
132
139 public async Task<bool> MoveNextAsyncLocked()
140 {
141 int i;
142
143 while (true)
144 {
145 if (this.currentRange is null)
146 {
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;
150 RangeInfo Range;
151 object Value;
152
153 for (i = 0; i < this.nrRanges; i++)
154 {
155 Range = this.currentLimits[i];
156
157 if (Range.IsPoint)
158 {
159 if (EndFilters is null)
160 EndFilters = new List<KeyValuePair<string, IApplicableFilter>>();
161
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)));
164 }
165 else
166 {
167 if (Range.HasMin)
168 {
169 Value = Range.Min;
170
171 if (this.ascending[i])
172 {
173 if (StartFilters is null)
174 StartFilters = new List<KeyValuePair<string, IApplicableFilter>>();
175
176 if (Range.MinInclusive)
177 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
178 else
179 {
180 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
181
182 if (!Comparison.Increment(ref Value))
183 return false;
184 }
185
186 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
187 }
188 else
189 {
190 if (EndFilters is null)
191 EndFilters = new List<KeyValuePair<string, IApplicableFilter>>();
192
193 if (Range.MinInclusive)
194 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
195 else
196 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
197 }
198 }
199
200 if (Range.HasMax)
201 {
202 Value = Range.Max;
203
204 if (!this.ascending[i])
205 {
206 if (StartFilters is null)
207 StartFilters = new List<KeyValuePair<string, IApplicableFilter>>();
208
209 if (Range.MaxInclusive)
210 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
211 else
212 {
213 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
214
215 if (!Comparison.Decrement(ref Value))
216 return false;
217 }
218
219 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
220 }
221 else
222 {
223 if (EndFilters is null)
224 EndFilters = new List<KeyValuePair<string, IApplicableFilter>>();
225
226 if (Range.MaxInclusive)
227 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
228 else
229 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
230 }
231 }
232 }
233 }
234
235 if (this.firstAscending)
236 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(SearchParameters.ToArray());
237 else
238 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(SearchParameters.ToArray());
239
240 this.startRangeFilters = StartFilters?.ToArray();
241 this.endRangeFilters = EndFilters?.ToArray();
242 this.limitsUpdatedAt = this.nrRanges;
243 }
244
245 if (!await this.currentRange.MoveNextAsyncLocked())
246 {
247 this.currentRange = null;
248
249 if (this.limitsUpdatedAt >= this.nrRanges)
250 return false;
251
252 continue;
253 }
254
255 if (!this.currentRange.CurrentTypeCompatible)
256 continue;
257
258 object CurrentValue = this.currentRange.Current;
259 IObjectSerializer CurrentSerializer = this.currentRange.CurrentSerializer;
260 string OutOfStartRangeField = null;
261 string OutOfEndRangeField = null;
262 bool Ok = true;
263 bool Smaller;
264
265 if (!(this.additionalfilters is null))
266 {
267 foreach (IApplicableFilter Filter in this.additionalfilters)
268 {
269 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
270 {
271 Ok = false;
272 break;
273 }
274 }
275 }
276
277 if (!(this.startRangeFilters is null))
278 {
279 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.startRangeFilters)
280 {
281 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
282 {
283 OutOfStartRangeField = Filter.Key;
284 Ok = false;
285 break;
286 }
287 }
288 }
289
290 if (!(this.endRangeFilters is null) && OutOfStartRangeField is null)
291 {
292 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.endRangeFilters)
293 {
294 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
295 {
296 OutOfEndRangeField = Filter.Key;
297 Ok = false;
298 break;
299 }
300 }
301 }
302
303 for (i = 0; i < this.limitsUpdatedAt; i++)
304 {
305 object FieldValue = await CurrentSerializer.TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
306
307 if (!(FieldValue is null))
308 {
309 if (this.ascending[i])
310 {
311 if (this.currentLimits[i].SetMin(FieldValue, !(OutOfStartRangeField is null), out Smaller) && Smaller)
312 {
313 i++;
314 this.limitsUpdatedAt = i;
315
316 while (i < this.nrRanges)
317 {
318 this.ranges[i].CopyTo(this.currentLimits[i]);
319 i++;
320 }
321 }
322 }
323 else
324 {
325 if (this.currentLimits[i].SetMax(FieldValue, !(OutOfStartRangeField is null), out Smaller) && Smaller)
326 {
327 i++;
328 this.limitsUpdatedAt = i;
329
330 while (i < this.nrRanges)
331 {
332 this.ranges[i].CopyTo(this.currentLimits[i]);
333 i++;
334 }
335 }
336 }
337 }
338 }
339
340 if (Ok)
341 return true;
342 else if (!(OutOfStartRangeField is null) || !(OutOfEndRangeField is null))
343 {
344 this.currentRange = null;
345
346 if (this.limitsUpdatedAt >= this.nrRanges)
347 return false;
348 }
349 }
350 }
351
358 public async Task<bool> MovePreviousAsyncLocked()
359 {
360 int i;
361
362 while (true)
363 {
364 if (this.currentRange is null)
365 {
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;
369 RangeInfo Range;
370 object Value;
371
372 for (i = 0; i < this.nrRanges; i++)
373 {
374 Range = this.currentLimits[i];
375
376 if (Range.IsPoint)
377 {
378 if (EndFilters is null)
379 EndFilters = new List<KeyValuePair<string, IApplicableFilter>>();
380
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)));
383 }
384 else
385 {
386 if (Range.HasMin)
387 {
388 Value = Range.Min;
389
390 if (this.ascending[i])
391 {
392 if (EndFilters is null)
393 EndFilters = new List<KeyValuePair<string, IApplicableFilter>>();
394
395 if (Range.MinInclusive)
396 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
397 else
398 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
399 }
400 else
401 {
402 if (StartFilters is null)
403 StartFilters = new List<KeyValuePair<string, IApplicableFilter>>();
404
405 if (Range.MinInclusive)
406 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterOrEqualTo(Range.FieldName, Value)));
407 else
408 {
409 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldGreaterThan(Range.FieldName, Value)));
410
411 if (!Comparison.Increment(ref Value))
412 return false;
413 }
414
415 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
416 }
417 }
418
419 if (Range.HasMax)
420 {
421 Value = Range.Max;
422
423 if (this.ascending[i])
424 {
425 if (StartFilters is null)
426 StartFilters = new List<KeyValuePair<string, IApplicableFilter>>();
427
428 if (Range.MaxInclusive)
429 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
430 else
431 {
432 StartFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
433
434 if (!Comparison.Decrement(ref Value))
435 return false;
436 }
437
438 SearchParameters.Add(new KeyValuePair<string, object>(Range.FieldName, Value));
439 }
440 else
441 {
442 if (EndFilters is null)
443 EndFilters = new List<KeyValuePair<string, IApplicableFilter>>();
444
445 if (Range.MaxInclusive)
446 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserOrEqualTo(Range.FieldName, Value)));
447 else
448 EndFilters.Add(new KeyValuePair<string, IApplicableFilter>(Range.FieldName, new FilterFieldLesserThan(Range.FieldName, Value)));
449 }
450 }
451 }
452 }
453
454 if (this.firstAscending)
455 this.currentRange = await this.index.FindLastLesserOrEqualToLocked<T>(SearchParameters.ToArray());
456 else
457 this.currentRange = await this.index.FindFirstGreaterOrEqualToLocked<T>(SearchParameters.ToArray());
458
459 this.startRangeFilters = StartFilters?.ToArray();
460 this.endRangeFilters = EndFilters?.ToArray();
461 this.limitsUpdatedAt = this.nrRanges;
462 }
463
464 if (!await this.currentRange.MovePreviousAsyncLocked())
465 {
466 this.currentRange = null;
467
468 if (this.limitsUpdatedAt >= this.nrRanges)
469 return false;
470
471 continue;
472 }
473
474 if (!this.currentRange.CurrentTypeCompatible)
475 continue;
476
477 object CurrentValue = this.currentRange.Current;
478 IObjectSerializer CurrentSerializer = this.currentRange.CurrentSerializer;
479 string OutOfStartRangeField = null;
480 string OutOfEndRangeField = null;
481 bool Ok = true;
482 bool Smaller;
483
484 if (!(this.additionalfilters is null))
485 {
486 foreach (IApplicableFilter Filter in this.additionalfilters)
487 {
488 if (!await Filter.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
489 {
490 Ok = false;
491 break;
492 }
493 }
494 }
495
496 if (!(this.startRangeFilters is null))
497 {
498 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.startRangeFilters)
499 {
500 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
501 {
502 OutOfStartRangeField = Filter.Key;
503 Ok = false;
504 break;
505 }
506 }
507 }
508
509 if (!(this.endRangeFilters is null) && OutOfStartRangeField is null)
510 {
511 foreach (KeyValuePair<string, IApplicableFilter> Filter in this.endRangeFilters)
512 {
513 if (!await Filter.Value.AppliesTo(CurrentValue, CurrentSerializer, this.provider))
514 {
515 OutOfEndRangeField = Filter.Key;
516 Ok = false;
517 break;
518 }
519 }
520 }
521
522 for (i = 0; i < this.limitsUpdatedAt; i++)
523 {
524 object FieldValue = await CurrentSerializer.TryGetFieldValue(this.ranges[i].FieldName, CurrentValue);
525
526 if (!(FieldValue is null))
527 {
528 if (this.ascending[i])
529 {
530 if (this.currentLimits[i].SetMax(FieldValue, !(OutOfStartRangeField is null), out Smaller) && Smaller)
531 {
532 i++;
533 this.limitsUpdatedAt = i;
534
535 while (i < this.nrRanges)
536 {
537 this.ranges[i].CopyTo(this.currentLimits[i]);
538 i++;
539 }
540 }
541 }
542 else
543 {
544 if (this.currentLimits[i].SetMin(FieldValue, !(OutOfStartRangeField is null), out Smaller) && Smaller)
545 {
546 i++;
547 this.limitsUpdatedAt = i;
548
549 while (i < this.nrRanges)
550 {
551 this.ranges[i].CopyTo(this.currentLimits[i]);
552 i++;
553 }
554 }
555 }
556 }
557 }
558
559 if (Ok)
560 return true;
561 else if (!(OutOfStartRangeField is null) || !(OutOfEndRangeField is null))
562 {
563 this.currentRange = null;
564
565 if (this.limitsUpdatedAt >= this.nrRanges)
566 return false;
567 }
568 }
569 }
570
578 public bool SameSortOrder(string[] ConstantFields, string[] SortOrder)
579 {
580 return this.index.SameSortOrder(ConstantFields, SortOrder);
581 }
582
590 public bool ReverseSortOrder(string[] ConstantFields, string[] SortOrder)
591 {
592 return this.index.ReverseSortOrder(ConstantFields, SortOrder);
593 }
594
599 public Task ContinueAfterLocked(T LastItem)
600 {
601 throw new NotSupportedException("Paginated search is not supported for queries with multiple ranges.");
602 }
603
608 public Task ContinueBeforeLocked(T LastItem)
609 {
610 throw new NotSupportedException("Paginated search is not supported for queries with multiple ranges.");
611 }
612 }
613}
Interface for asynchronous enumerators.
Task< bool > MoveNextAsync()
Advances the enumerator to the next element of the collection.
Task< object > TryGetFieldValue(string FieldName, object Object)
Gets the value of a field or property of an object, given its name.