UNPKG

@azure/cosmos

Version:
129 lines 6.37 kB
// 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