1 | import { Constants } from "../common/constants";
|
2 | import { PartitionKeyRangeCache } from "./partitionKeyRangeCache";
|
3 | import { QueryRange } from "./QueryRange";
|
4 |
|
5 | export const PARITIONKEYRANGE = Constants.PartitionKeyRange;
|
6 |
|
7 | export class SmartRoutingMapProvider {
|
8 | constructor(clientContext) {
|
9 | this.partitionKeyRangeCache = new PartitionKeyRangeCache(clientContext);
|
10 | }
|
11 | static _secondRangeIsAfterFirstRange(range1, range2) {
|
12 | if (typeof range1.max === "undefined") {
|
13 | throw new Error("range1 must have max");
|
14 | }
|
15 | if (typeof range2.min === "undefined") {
|
16 | throw new Error("range2 must have min");
|
17 | }
|
18 | if (range1.max > range2.min) {
|
19 |
|
20 | return false;
|
21 | }
|
22 | else {
|
23 | if (range1.max === range2.min && range1.isMaxInclusive && range2.isMinInclusive) {
|
24 |
|
25 |
|
26 | return false;
|
27 | }
|
28 | return true;
|
29 | }
|
30 | }
|
31 | static _isSortedAndNonOverlapping(ranges) {
|
32 | for (let idx = 1; idx < ranges.length; idx++) {
|
33 | const previousR = ranges[idx - 1];
|
34 | const r = ranges[idx];
|
35 | if (!this._secondRangeIsAfterFirstRange(previousR, r)) {
|
36 | return false;
|
37 | }
|
38 | }
|
39 | return true;
|
40 | }
|
41 | static _stringMax(a, b) {
|
42 | return a >= b ? a : b;
|
43 | }
|
44 | static _stringCompare(a, b) {
|
45 | return a === b ? 0 : a > b ? 1 : -1;
|
46 | }
|
47 | static _subtractRange(r, partitionKeyRange) {
|
48 | const left = this._stringMax(partitionKeyRange[PARITIONKEYRANGE.MaxExclusive], r.min);
|
49 | const leftInclusive = this._stringCompare(left, r.min) === 0 ? r.isMinInclusive : false;
|
50 | return new QueryRange(left, r.max, leftInclusive, r.isMaxInclusive);
|
51 | }
|
52 | |
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | async getOverlappingRanges(collectionLink, sortedRanges) {
|
59 |
|
60 | if (!SmartRoutingMapProvider._isSortedAndNonOverlapping(sortedRanges)) {
|
61 | throw new Error("the list of ranges is not a non-overlapping sorted ranges");
|
62 | }
|
63 | let partitionKeyRanges = [];
|
64 | if (sortedRanges.length === 0) {
|
65 | return partitionKeyRanges;
|
66 | }
|
67 | const collectionRoutingMap = await this.partitionKeyRangeCache.onCollectionRoutingMap(collectionLink);
|
68 | let index = 0;
|
69 | let currentProvidedRange = sortedRanges[index];
|
70 | for (;;) {
|
71 | if (currentProvidedRange.isEmpty()) {
|
72 |
|
73 | if (++index >= sortedRanges.length) {
|
74 | return partitionKeyRanges;
|
75 | }
|
76 | currentProvidedRange = sortedRanges[index];
|
77 | continue;
|
78 | }
|
79 | let queryRange;
|
80 | if (partitionKeyRanges.length > 0) {
|
81 | queryRange = SmartRoutingMapProvider._subtractRange(currentProvidedRange, partitionKeyRanges[partitionKeyRanges.length - 1]);
|
82 | }
|
83 | else {
|
84 | queryRange = currentProvidedRange;
|
85 | }
|
86 | const overlappingRanges = collectionRoutingMap.getOverlappingRanges(queryRange);
|
87 | if (overlappingRanges.length <= 0) {
|
88 | throw new Error(`error: returned overlapping ranges for queryRange ${queryRange} is empty`);
|
89 | }
|
90 | partitionKeyRanges = partitionKeyRanges.concat(overlappingRanges);
|
91 | const lastKnownTargetRange = QueryRange.parsePartitionKeyRange(partitionKeyRanges[partitionKeyRanges.length - 1]);
|
92 | if (!lastKnownTargetRange) {
|
93 | throw new Error("expected lastKnowTargetRange to be truthy");
|
94 | }
|
95 |
|
96 | if (SmartRoutingMapProvider._stringCompare(currentProvidedRange.max, lastKnownTargetRange.max) >
|
97 | 0) {
|
98 | throw new Error(`error: returned overlapping ranges ${overlappingRanges} \
|
99 | does not contain the requested range ${queryRange}`);
|
100 | }
|
101 |
|
102 | if (++index >= sortedRanges.length) {
|
103 | return partitionKeyRanges;
|
104 | }
|
105 | currentProvidedRange = sortedRanges[index];
|
106 | while (SmartRoutingMapProvider._stringCompare(currentProvidedRange.max, lastKnownTargetRange.max) <= 0) {
|
107 |
|
108 | if (++index >= sortedRanges.length) {
|
109 | return partitionKeyRanges;
|
110 | }
|
111 | currentProvidedRange = sortedRanges[index];
|
112 | }
|
113 | }
|
114 | }
|
115 | }
|
116 |
|
\ | No newline at end of file |