@azure/cosmos
Version:
Microsoft Azure Cosmos DB Service Node.js SDK for NOSQL API
129 lines • 6.37 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { BaseContinuationTokenManager } from "./BaseContinuationTokenManager.js";
import { createOrderByQueryContinuationToken, parseOrderByQueryContinuationToken, serializeOrderByQueryContinuationToken, } from "../../documents/ContinuationToken/OrderByQueryContinuationToken.js";
import { convertRangeMappingToQueryRange } from "../../documents/ContinuationToken/CompositeQueryContinuationToken.js";
/**
* Manages continuation tokens for ORDER BY queries using single-range sequential processing.
* Uses OrderByQueryContinuationToken for tracking ORDER BY items and skip counts.
* @internal
*/
export class OrderByQueryContinuationTokenManager extends BaseContinuationTokenManager {
continuationToken;
orderByItemsArray;
collectionLink;
constructor(collectionLink, initialContinuationToken) {
super(initialContinuationToken);
this.collectionLink = collectionLink;
this.orderByItemsArray = [];
if (initialContinuationToken) {
this.continuationToken = parseOrderByQueryContinuationToken(initialContinuationToken);
}
}
processQuerySpecificResponse(responseResult) {
// Clear existing items and add new ones without reassigning the array reference
this.orderByItemsArray.length = 0;
if (responseResult.orderByItems) {
this.orderByItemsArray.push(...responseResult.orderByItems);
}
}
performQuerySpecificDataTrim(_processedRanges, endIndex) {
this.sliceOrderByItemsArray(endIndex);
}
sliceOrderByItemsArray(endIndex) {
if (endIndex === 0 || endIndex >= this.orderByItemsArray.length) {
// Clear the array without reassigning
this.orderByItemsArray.length = 0;
}
else {
// Remove items from 0 to endIndex-1, keeping items from endIndex onwards
this.orderByItemsArray.splice(0, endIndex);
}
}
processRangesForPagination(pageSize, isResponseEmpty = false) {
// Handle empty response case - update the previous valid continuation token
if (isResponseEmpty && this.continuationToken) {
let rangeProcessingResult;
if (this.rangeList.length === 0) {
rangeProcessingResult = this.partitionManager.processOrderByRanges(pageSize);
}
else {
rangeProcessingResult = this.partitionManager.processEmptyOrderByRanges(this.rangeList);
}
const { lastRangeBeforePageLimit } = rangeProcessingResult;
if (lastRangeBeforePageLimit) {
// Use the range matching the continuation token for empty response
this.continuationToken.rangeMappings = [
convertRangeMappingToQueryRange(lastRangeBeforePageLimit),
];
}
else {
// Range is exhausted - clear the continuation token
this.continuationToken = undefined;
}
return {
endIndex: rangeProcessingResult.endIndex,
processedRanges: rangeProcessingResult.processedRanges,
};
}
// Normal processing path - handle non-empty responses
const rangeProcessingResult = this.partitionManager.processOrderByRanges(pageSize);
const { lastRangeBeforePageLimit } = rangeProcessingResult;
// Check if we have a valid range to continue with
if (!lastRangeBeforePageLimit) {
this.continuationToken = undefined;
return {
endIndex: rangeProcessingResult.endIndex,
processedRanges: rangeProcessingResult.processedRanges,
};
}
const queryRange = convertRangeMappingToQueryRange(lastRangeBeforePageLimit);
// Extract ORDER BY items from the last item on the page
let lastOrderByItems;
let documentRid;
let skipCount = 0;
if (rangeProcessingResult.endIndex > 0 && this.orderByItemsArray.length > 0) {
const lastItemIndexOnPage = rangeProcessingResult.endIndex - 1;
if (lastItemIndexOnPage < this.orderByItemsArray.length) {
lastOrderByItems = this.orderByItemsArray[lastItemIndexOnPage].orderByItems;
documentRid = this.orderByItemsArray[lastItemIndexOnPage]._rid;
// Calculate skip count: count how many documents in the page have the same RID
// This handles JOIN queries where multiple documents can have the same RID
skipCount = 0;
for (let i = 0; i <= lastItemIndexOnPage; i++) {
if (this.orderByItemsArray[i]._rid === documentRid) {
skipCount++;
}
}
}
}
// If we don't have valid ORDER BY items, we cannot create a proper continuation token
// This can happen when the response doesn't contain ORDER BY metadata or when there are no results
if (!lastOrderByItems || lastOrderByItems.length === 0) {
this.continuationToken = undefined;
return {
endIndex: rangeProcessingResult.endIndex,
processedRanges: rangeProcessingResult.processedRanges,
};
}
const rangeMappings = [queryRange];
// Create new ORDER BY continuation token
this.continuationToken = createOrderByQueryContinuationToken(rangeMappings, lastOrderByItems, this.collectionLink, // Container RID/link
skipCount, // Number of documents with the same RID already processed
documentRid, // Document RID from the last item in the page
lastRangeBeforePageLimit.offset, // Current offset for OFFSET/LIMIT queries
lastRangeBeforePageLimit.limit, // Current limit for OFFSET/LIMIT queries
lastRangeBeforePageLimit.hashedLastResult);
return {
endIndex: rangeProcessingResult.endIndex,
processedRanges: rangeProcessingResult.processedRanges,
};
}
getCurrentContinuationToken() {
return this.continuationToken;
}
getSerializationFunction() {
return serializeOrderByQueryContinuationToken;
}
}
//# sourceMappingURL=OrderByQueryContinuationTokenManager.js.map