@azure/cosmos
Version:
Microsoft Azure Cosmos DB Service Node.js SDK for NOSQL API
102 lines • 4.01 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
/**
* Strategy for filtering partition ranges in parallel query execution context
* Supports resuming from composite continuation tokens with multi-range aggregation
* @hidden
*/
export class ParallelQueryRangeStrategy {
getStrategyType() {
return "ParallelQuery";
}
validateContinuationToken(continuationToken) {
// Check for null, undefined, or empty string inputs
if (!continuationToken) {
return false;
}
try {
const parsed = JSON.parse(continuationToken);
// Check if it's a composite continuation token (has rangeMappings)
if (!parsed || !Array.isArray(parsed.rangeMappings)) {
return false;
}
// Validate each range mapping has a non-null partitionKeyRange
for (const rangeMapping of parsed.rangeMappings) {
if (!rangeMapping || !rangeMapping.partitionKeyRange) {
return false;
}
}
return true;
}
catch {
return false;
}
}
filterPartitionRanges(targetRanges, continuationRanges) {
if (!targetRanges || targetRanges.length === 0) {
return { rangeTokenPairs: [] };
}
// If no continuation ranges, return all ranges as range-token pairs
if (!continuationRanges || continuationRanges.length === 0) {
const rangeTokenPairs = targetRanges.map((range) => ({
range,
continuationToken: undefined,
filteringCondition: undefined,
}));
return { rangeTokenPairs };
}
const rangeTokenPairs = [];
let lastProcessedRange = null;
// sort continuationRanges in ascending order using their minInclusive values
continuationRanges.sort((a, b) => {
return a.range.minInclusive.localeCompare(b.range.minInclusive);
});
for (const range of continuationRanges) {
// Always track the last processed range, even if it's exhausted
lastProcessedRange = range.range;
if (range && !this.isPartitionExhausted(range.continuationToken)) {
rangeTokenPairs.push({
range: range.range,
continuationToken: range.continuationToken,
filteringCondition: range.filteringCondition,
});
}
}
// Add any new target ranges that come after the last processed range
if (lastProcessedRange) {
for (const targetRange of targetRanges) {
// Only include ranges whose minInclusive value is greater than or equal to maxExclusive of lastProcessedRange
if (targetRange.minInclusive >= lastProcessedRange.maxExclusive) {
rangeTokenPairs.push({
range: targetRange,
continuationToken: undefined,
filteringCondition: undefined,
});
}
}
}
else {
// If no ranges were processed from continuation token, add all target ranges
for (const targetRange of targetRanges) {
rangeTokenPairs.push({
range: targetRange,
continuationToken: undefined,
filteringCondition: undefined,
});
}
}
return {
rangeTokenPairs,
};
}
/**
* Checks if a partition is exhausted based on its continuation token
*/
isPartitionExhausted(continuationToken) {
return (!continuationToken ||
continuationToken === "" ||
continuationToken === "null" ||
continuationToken.toLowerCase() === "null");
}
}
//# sourceMappingURL=ParallelQueryRangeStrategy.js.map