UNPKG

@azure/cosmos

Version:
151 lines 6.77 kB
import { ChangeFeedIteratorResponse } from "./ChangeFeedIteratorResponse.js"; import { Constants, copyObject, ResourceType, StatusCodes } from "../../common/index.js"; import { ErrorResponse } from "../../request/index.js"; import { ContinuationTokenForPartitionKey } from "./ContinuationTokenForPartitionKey.js"; import { convertToInternalPartitionKey } from "../../documents/index.js"; import { getEmptyCosmosDiagnostics, withDiagnostics } from "../../utils/diagnostics.js"; import { buildFeedOptions, decryptChangeFeedResponse } from "./changeFeedUtils.js"; import { computePartitionKeyRangeId } from "../ClientUtils.js"; /** * @hidden * Provides iterator for change feed for one partition key. * * Use `Items.getChangeFeedIterator()` to get an instance of the iterator. */ export class ChangeFeedForPartitionKey { clientContext; container; resourceId; resourceLink; partitionKey; changeFeedOptions; continuationToken; startTime; rId; isInstantiated; startFromNow; /** * @internal */ constructor(clientContext, container, resourceId, resourceLink, partitionKey, changeFeedOptions) { this.clientContext = clientContext; this.container = container; this.resourceId = resourceId; this.resourceLink = resourceLink; this.partitionKey = partitionKey; this.changeFeedOptions = changeFeedOptions; this.continuationToken = changeFeedOptions.continuationToken ? JSON.parse(changeFeedOptions.continuationToken) : undefined; this.isInstantiated = false; // startTime is used to store and specify time from which change feed should start reading new changes. StartFromNow flag is used to indicate fetching changes from now. if (changeFeedOptions.startFromNow) { this.startFromNow = true; } else if (changeFeedOptions.startTime) { this.startTime = changeFeedOptions.startTime.toUTCString(); } } async instantiateIterator(diagnosticNode) { await this.setIteratorRid(diagnosticNode); if (this.clientContext.enableEncryption) { await this.container.checkAndInitializeEncryption(); // returns copy of object to avoid encryption of original partition key passed this.partitionKey = copyObject(this.partitionKey); diagnosticNode.beginEncryptionDiagnostics(Constants.Encryption.DiagnosticsEncryptOperation); const { partitionKeyList, encryptedCount } = await this.container.encryptionProcessor.getEncryptedPartitionKeyValue(convertToInternalPartitionKey(this.partitionKey)); this.partitionKey = partitionKeyList; diagnosticNode.endEncryptionDiagnostics(Constants.Encryption.DiagnosticsEncryptOperation, encryptedCount); } if (this.continuationToken) { if (!this.continuationTokenRidMatchContainerRid()) { throw new ErrorResponse("The continuation is not for the current container definition."); } } else { this.continuationToken = new ContinuationTokenForPartitionKey(this.rId, this.partitionKey, ""); } this.isInstantiated = true; } continuationTokenRidMatchContainerRid() { if (this.continuationToken.rid !== this.rId) { return false; } return true; } async setIteratorRid(diagnosticNode) { const { resource } = await this.container.readInternal(diagnosticNode); this.rId = resource._rid; } /** * Change feed is an infinite feed. hasMoreResults is always true. */ get hasMoreResults() { return true; } /** * Gets an async iterator which will yield change feed results. */ async *getAsyncIterator() { do { const result = await this.readNext(); yield result; } while (this.hasMoreResults); } /** * Returns the result of change feed from Azure Cosmos DB. */ async readNext() { return withDiagnostics(async (diagnosticNode) => { if (!this.isInstantiated) { await this.instantiateIterator(diagnosticNode); } const result = await this.fetchNext(diagnosticNode); if (result.statusCode === StatusCodes.Ok) { if (this.clientContext.enableEncryption) { await decryptChangeFeedResponse(result, diagnosticNode, this.changeFeedOptions.changeFeedMode, this.container.encryptionProcessor); } } return result; }, this.clientContext); } /** * Read feed and retrieves the next set of results in Azure Cosmos DB. */ async fetchNext(diagnosticNode) { const response = await this.getFeedResponse(diagnosticNode); this.continuationToken.Continuation = response.headers[Constants.HttpHeaders.ETag]; response.headers[Constants.HttpHeaders.ContinuationToken] = JSON.stringify(this.continuationToken); return response; } async getFeedResponse(diagnosticNode) { const feedOptions = buildFeedOptions(this.changeFeedOptions, this.continuationToken?.Continuation, this.startFromNow, this.startTime); if (this.clientContext.enableEncryption) { feedOptions.containerRid = this.container._rid; } try { const isPartitionLevelFailOverEnabled = this.clientContext.isPartitionLevelFailOverEnabled(); const partitionKeyRangeId = await computePartitionKeyRangeId(diagnosticNode, convertToInternalPartitionKey(this.partitionKey), this.clientContext.partitionKeyRangeCache, isPartitionLevelFailOverEnabled, this.container); const response = await this.clientContext.queryFeed({ path: this.resourceLink, resourceType: ResourceType.item, resourceId: this.resourceId, resultFn: (result) => (result ? result.Documents : []), diagnosticNode, query: undefined, options: feedOptions, partitionKey: this.partitionKey, partitionKeyRangeId, }); return new ChangeFeedIteratorResponse(response.result, response.result ? response.result.length : 0, response.code, response.headers, getEmptyCosmosDiagnostics()); } catch (err) { // If any errors are encountered, throw the error. const errorResponse = new ErrorResponse(err.message); errorResponse.code = err.code; errorResponse.headers = err.headers; throw errorResponse; } } } //# sourceMappingURL=ChangeFeedForPartitionKey.js.map