UNPKG

5.32 kBJavaScriptView Raw
1import { Constants } from "../common/constants";
2import { PartitionKeyRangeCache } from "./partitionKeyRangeCache";
3import { QueryRange } from "./QueryRange";
4/** @hidden */
5export const PARITIONKEYRANGE = Constants.PartitionKeyRange;
6/** @hidden */
7export 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 // r.min < #previous_r.max
20 return false;
21 }
22 else {
23 if (range1.max === range2.min && range1.isMaxInclusive && range2.isMinInclusive) {
24 // the inclusive ending endpoint of previous_r is the same as the inclusive beginning endpoint of r
25 // they share a point
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 * Given the sorted ranges and a collection, invokes the callback on the list of overlapping partition key ranges
54 * @param callback - Function execute on the overlapping partition key ranges result,
55 * takes two parameters error, partition key ranges
56 * @hidden
57 */
58 async getOverlappingRanges(collectionLink, sortedRanges) {
59 // validate if the list is non- overlapping and sorted TODO: any PartitionKeyRanges
60 if (!SmartRoutingMapProvider._isSortedAndNonOverlapping(sortedRanges)) {
61 throw new Error("the list of ranges is not a non-overlapping sorted ranges");
62 }
63 let partitionKeyRanges = []; // TODO: any ParitionKeyRanges
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 // skip and go to the next item
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 // the overlapping ranges must contain the requested range
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 // the current range is contained in partitionKeyRanges just move forward
102 if (++index >= sortedRanges.length) {
103 return partitionKeyRanges;
104 }
105 currentProvidedRange = sortedRanges[index];
106 while (SmartRoutingMapProvider._stringCompare(currentProvidedRange.max, lastKnownTargetRange.max) <= 0) {
107 // the current range is covered too.just move forward
108 if (++index >= sortedRanges.length) {
109 return partitionKeyRanges;
110 }
111 currentProvidedRange = sortedRanges[index];
112 }
113 }
114 }
115}
116//# sourceMappingURL=smartRoutingMapProvider.js.map
\No newline at end of file