@azure/cosmos
Version:
Microsoft Azure Cosmos DB Service Node.js SDK for NOSQL API
762 lines • 34.4 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { bearerTokenAuthenticationPolicy, createEmptyPipeline } from "@azure/core-rest-pipeline";
import { Constants, HTTPMethod, OperationType, ResourceType } from "./common/constants.js";
import { getIdFromLink, getPathFromLink, parseLink } from "./common/helper.js";
import { StatusCodes, SubStatusCodes } from "./common/statusCodes.js";
import { ConsistencyLevel, DatabaseAccount, convertToInternalPartitionKey, } from "./documents/index.js";
import { PluginOn, executePlugins } from "./plugins/Plugin.js";
import { QueryIterator } from "./queryIterator.js";
import { getHeaders } from "./request/request.js";
import { RequestHandler } from "./request/RequestHandler.js";
import { SessionContainer } from "./session/sessionContainer.js";
import { sanitizeEndpoint } from "./utils/checkURL.js";
import { supportedQueryFeaturesBuilder } from "./utils/supportedQueryFeaturesBuilder.js";
import { createClientLogger } from "@azure/logger";
import { LogDiagnosticWriter, NoOpDiagnosticWriter } from "./diagnostics/DiagnosticWriter.js";
import { DefaultDiagnosticFormatter } from "./diagnostics/DiagnosticFormatter.js";
import { CosmosDbDiagnosticLevel } from "./diagnostics/CosmosDbDiagnosticLevel.js";
import { randomUUID } from "@azure/core-util";
import { getUserAgent } from "./common/platform.js";
import { PartitionKeyRangeCache } from "./routing/partitionKeyRangeCache.js";
import { AAD_DEFAULT_SCOPE, AAD_AUTH_PREFIX, AAD_RESOURCE_NOT_FOUND_ERROR, } from "./common/constants.js";
const logger = createClientLogger("ClientContext");
const QueryJsonContentType = "application/query+json";
const HttpHeaders = Constants.HttpHeaders;
/**
* @hidden
*/
export class ClientContext {
cosmosClientOptions;
globalEndpointManager;
clientConfig;
diagnosticLevel;
globalPartitionEndpointManager;
sessionContainer;
connectionPolicy;
pipeline;
diagnosticWriter;
diagnosticFormatter;
partitionKeyDefinitionCache; // TODO: PartitionKeyDefinitionCache
/** @internal */
partitionKeyRangeCache;
/** boolean flag to support operations with client-side encryption */
enableEncryption = false;
constructor(cosmosClientOptions, globalEndpointManager, clientConfig, diagnosticLevel, globalPartitionEndpointManager) {
this.cosmosClientOptions = cosmosClientOptions;
this.globalEndpointManager = globalEndpointManager;
this.clientConfig = clientConfig;
this.diagnosticLevel = diagnosticLevel;
this.globalPartitionEndpointManager = globalPartitionEndpointManager;
if (cosmosClientOptions.clientEncryptionOptions) {
this.enableEncryption = true;
}
this.connectionPolicy = cosmosClientOptions.connectionPolicy;
this.sessionContainer = new SessionContainer();
this.partitionKeyDefinitionCache = {};
this.pipeline = null;
if (cosmosClientOptions.aadCredentials) {
this.pipeline = createEmptyPipeline();
const hrefEndpoint = sanitizeEndpoint(cosmosClientOptions.endpoint);
// Use custom AAD scope if provided, otherwise use account-based scope
const accountScope = `${hrefEndpoint}/.default`;
const primaryScope = cosmosClientOptions.aadScope || accountScope;
const fallbackScope = AAD_DEFAULT_SCOPE;
this.pipeline.addPolicy(bearerTokenAuthenticationPolicy({
credential: cosmosClientOptions.aadCredentials,
scopes: primaryScope,
challengeCallbacks: {
async authorizeRequest({ request, getAccessToken }) {
try {
const tokenResponse = await getAccessToken([primaryScope], {});
const authorizationToken = `${AAD_AUTH_PREFIX}${tokenResponse.token}`;
request.headers.set(Constants.HttpHeaders.Authorization, authorizationToken);
}
catch (error) {
// If no custom scope is provided and we get AADSTS500011 error,
// fallback to the default Cosmos scope
if (!cosmosClientOptions.aadScope &&
error?.message?.includes(AAD_RESOURCE_NOT_FOUND_ERROR)) {
try {
const fallbackTokenResponse = await getAccessToken([fallbackScope], {});
const authorizationToken = `${AAD_AUTH_PREFIX}${fallbackTokenResponse.token}`;
request.headers.set(Constants.HttpHeaders.Authorization, authorizationToken);
}
catch (fallbackError) {
// If fallback also fails, throw the original error
throw error;
}
}
else {
// If custom scope is provided or error is not AADSTS500011, throw the original error
throw error;
}
}
},
},
}));
}
this.initializeDiagnosticSettings(diagnosticLevel);
this.partitionKeyRangeCache = new PartitionKeyRangeCache(this);
}
/** @hidden */
async read({ path, resourceType, resourceId, options = {}, partitionKey, diagnosticNode, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.get,
path,
operationType: OperationType.Read,
resourceId,
options,
resourceType,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Read,
resourceType,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
if (resourceType === ResourceType.clientencryptionkey) {
request.headers[HttpHeaders.AllowCachedReadsHeader] = true;
if (options.databaseRid) {
request.headers[HttpHeaders.DatabaseRidHeader] = options.databaseRid;
}
}
this.applySessionToken(request);
// read will use ReadEndpoint since it uses GET operation
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Read, response.headers);
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
async queryFeed({ path, resourceType, resourceId, resultFn, query, options, diagnosticNode, partitionKeyRangeId, partitionKey, startEpk, endEpk, correlatedActivityId, }) {
// Query operations will use ReadEndpoint even though it uses
// GET(for queryFeed) and POST(for regular query operations)
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.get,
path,
operationType: OperationType.Query,
partitionKeyRangeId,
resourceId,
resourceType,
options,
body: query,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Query,
resourceType,
});
const requestId = randomUUID();
if (query !== undefined) {
request.method = HTTPMethod.post;
}
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
request.headers = await this.buildHeaders(request);
if (startEpk !== undefined && endEpk !== undefined) {
request.headers[HttpHeaders.StartEpk] = startEpk;
request.headers[HttpHeaders.EndEpk] = endEpk;
request.headers[HttpHeaders.ReadFeedKeyType] = "EffectivePartitionKeyRange";
}
if (query !== undefined) {
if (correlatedActivityId !== undefined) {
request.headers[HttpHeaders.CorrelatedActivityId] = correlatedActivityId;
}
request.headers[HttpHeaders.IsQuery] = "true";
request.headers[HttpHeaders.ContentType] = QueryJsonContentType;
if (typeof query === "string") {
request.body = { query }; // Converts query text to query object.
}
}
this.applySessionToken(request);
logger.info("query " +
requestId +
" started" +
(request.partitionKeyRangeId ? " pkrid: " + request.partitionKeyRangeId : ""));
logger.verbose(request);
const start = Date.now();
const response = await RequestHandler.request(request, diagnosticNode);
logger.info("query " + requestId + " finished - " + (Date.now() - start) + "ms");
this.captureSessionToken(undefined, path, OperationType.Query, response.headers);
return this.processQueryFeedResponse(response, !!query, resultFn);
}
async getQueryPlan(path, resourceType, resourceId, query, options = {}, diagnosticNode, correlatedActivityId) {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.post,
path,
operationType: OperationType.Read,
resourceId,
resourceType,
options,
body: query,
};
diagnosticNode.addData({
operationType: OperationType.Read,
resourceType,
});
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
request.headers = await this.buildHeaders(request);
if (correlatedActivityId !== undefined) {
request.headers[HttpHeaders.CorrelatedActivityId] = correlatedActivityId;
}
request.headers[HttpHeaders.IsQueryPlan] = "True";
request.headers[HttpHeaders.QueryVersion] = "1.4";
request.headers[HttpHeaders.ContentType] = QueryJsonContentType;
request.headers[HttpHeaders.SupportedQueryFeatures] = supportedQueryFeaturesBuilder(options);
if (typeof query === "string") {
request.body = { query }; // Converts query text to query object.
}
this.applySessionToken(request);
const response = await RequestHandler.request(request, diagnosticNode);
this.captureSessionToken(undefined, path, OperationType.Query, response.headers);
return response;
}
queryPartitionKeyRanges(collectionLink, query, options) {
const path = getPathFromLink(collectionLink, ResourceType.pkranges);
const id = getIdFromLink(collectionLink);
const cb = async (diagNode, innerOptions) => {
const response = await this.queryFeed({
path,
resourceType: ResourceType.pkranges,
resourceId: id,
resultFn: (result) => result.PartitionKeyRanges,
query,
options: innerOptions,
diagnosticNode: diagNode,
});
return response;
};
return new QueryIterator(this, query, options, cb);
}
async delete({ path, resourceType, resourceId, options = {}, partitionKey, method = HTTPMethod.delete, diagnosticNode, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: method,
operationType: OperationType.Delete,
path,
resourceType,
options,
resourceId,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Delete,
resourceType,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
this.applySessionToken(request);
// deleteResource will use WriteEndpoint since it uses DELETE operation
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
if (parseLink(path).type !== "colls") {
this.captureSessionToken(undefined, path, OperationType.Delete, response.headers);
}
else {
this.clearSessionToken(path);
}
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
async patch({ body, path, resourceType, resourceId, options = {}, partitionKey, diagnosticNode, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.patch,
operationType: OperationType.Patch,
path,
resourceType,
body,
resourceId,
options,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Patch,
resourceType,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
this.applySessionToken(request);
// patch will use WriteEndpoint
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Patch, response.headers);
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
async create({ body, path, resourceType, resourceId, diagnosticNode, options = {}, partitionKey, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.post,
operationType: OperationType.Create,
path,
resourceType,
resourceId,
body,
options,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Create,
resourceType,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
// create will use WriteEndpoint since it uses POST operation
this.applySessionToken(request);
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Create, response.headers);
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
processQueryFeedResponse(res, isQuery, resultFn) {
if (isQuery) {
return {
result: resultFn(res.result),
headers: res.headers,
code: res.code,
};
}
else {
const newResult = resultFn(res.result).map((body) => body);
return {
result: newResult,
headers: res.headers,
code: res.code,
};
}
}
applySessionToken(requestContext) {
const request = this.getSessionParams(requestContext.path);
if (requestContext.headers && requestContext.headers[HttpHeaders.SessionToken]) {
return;
}
const sessionConsistency = requestContext.headers[HttpHeaders.ConsistencyLevel];
if (!sessionConsistency) {
return;
}
if (sessionConsistency !== ConsistencyLevel.Session) {
return;
}
if (request.resourceAddress) {
const sessionToken = this.sessionContainer.get(request);
if (sessionToken) {
requestContext.headers[HttpHeaders.SessionToken] = sessionToken;
}
}
}
async replace({ body, path, resourceType, resourceId, options = {}, partitionKey, diagnosticNode, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.put,
operationType: OperationType.Replace,
path,
resourceType,
body,
resourceId,
options,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Replace,
resourceType,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
this.applySessionToken(request);
// replace will use WriteEndpoint since it uses PUT operation
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Replace, response.headers);
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
async upsert({ body, path, resourceType, resourceId, options = {}, partitionKey, diagnosticNode, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.post,
operationType: OperationType.Upsert,
path,
resourceType,
body,
resourceId,
options,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Upsert,
resourceType,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
request.headers[HttpHeaders.IsUpsert] = true;
this.applySessionToken(request);
// upsert will use WriteEndpoint since it uses POST operation
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Upsert, response.headers);
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
async execute({ sprocLink, params, options = {}, partitionKey, diagnosticNode, partitionKeyRangeId, }) {
// Accept a single parameter or an array of parameters.
// Didn't add type annotation for this because we should legacy this behavior
if (params !== null && params !== undefined && !Array.isArray(params)) {
params = [params];
}
const path = getPathFromLink(sprocLink);
const id = getIdFromLink(sprocLink);
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.post,
operationType: OperationType.Execute,
path,
resourceType: ResourceType.sproc,
options,
resourceId: id,
body: params,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Execute,
resourceType: ResourceType.sproc,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
// executeStoredProcedure will use WriteEndpoint since it uses POST operation
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
return response;
}
/**
* Gets the Database account information.
* @param options - `urlConnection` in the options is the endpoint url whose database account needs to be retrieved.
* If not present, current client's url will be used.
*/
async getDatabaseAccount(diagnosticNode, options = {}) {
const endpoint = options.urlConnection || this.cosmosClientOptions.endpoint;
const request = {
...this.getContextDerivedPropsForRequestCreation(),
endpoint,
method: HTTPMethod.get,
operationType: OperationType.Read,
path: "",
resourceType: ResourceType.none,
options,
};
diagnosticNode.addData({
operationType: OperationType.Read,
resourceType: ResourceType.none,
});
request.headers = await this.buildHeaders(request);
// await options.beforeOperation({ endpoint, request, headers: requestHeaders });
const { result, headers, code, substatus, diagnostics } = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
const databaseAccount = new DatabaseAccount(result, headers);
return {
result: databaseAccount,
headers,
diagnostics,
code: code,
substatus: substatus,
};
}
getWriteEndpoint(diagnosticNode) {
return this.globalEndpointManager.getWriteEndpoint(diagnosticNode);
}
getReadEndpoint(diagnosticNode) {
return this.globalEndpointManager.getReadEndpoint(diagnosticNode);
}
getWriteEndpoints() {
return this.globalEndpointManager.getWriteEndpoints();
}
getReadEndpoints() {
return this.globalEndpointManager.getReadEndpoints();
}
async batch({ body, path, partitionKey, resourceId, options = {}, diagnosticNode, partitionKeyRangeId, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.post,
operationType: OperationType.Batch,
path,
body,
resourceType: ResourceType.item,
resourceId,
options,
partitionKey,
};
diagnosticNode.addData({
operationType: OperationType.Batch,
resourceType: ResourceType.item,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
request.headers[HttpHeaders.IsBatchRequest] = true;
request.headers[HttpHeaders.IsBatchAtomic] = true;
this.applySessionToken(request);
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Batch, response.headers);
response.diagnostics = diagnosticNode.toDiagnostic(this.getClientConfig());
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
async bulk({ body, path, partitionKeyRangeId, resourceId, bulkOptions = {}, options = {}, diagnosticNode, }) {
try {
const request = {
...this.getContextDerivedPropsForRequestCreation(),
method: HTTPMethod.post,
operationType: OperationType.Batch,
path,
body,
resourceType: ResourceType.item,
resourceId,
options,
};
diagnosticNode.addData({
operationType: OperationType.Batch,
resourceType: ResourceType.item,
});
request.headers = await this.buildHeaders(request);
request.partitionKeyRangeId = partitionKeyRangeId;
request.headers[HttpHeaders.IsBatchRequest] = true;
request.headers[HttpHeaders.PartitionKeyRangeID] = partitionKeyRangeId;
request.headers[HttpHeaders.IsBatchAtomic] = false;
request.headers[HttpHeaders.BatchContinueOnError] = bulkOptions.continueOnError ?? true;
this.applySessionToken(request);
request.endpoint = await this.globalEndpointManager.resolveServiceEndpointInternal({
diagnosticNode: diagnosticNode,
resourceType: request.resourceType,
operationType: request.operationType,
startServiceEndpointIndex: 0,
excludedLocations: options?.excludedLocations,
});
const response = await executePlugins(diagnosticNode, request, RequestHandler.request, PluginOn.operation);
this.captureSessionToken(undefined, path, OperationType.Batch, response.headers);
return response;
}
catch (err) {
this.captureSessionToken(err, path, OperationType.Upsert, err.headers);
throw err;
}
}
captureSessionToken(err, path, operationType, resHeaders) {
const request = this.getSessionParams(path);
request.operationType = operationType;
if (!err ||
(!this.isMasterResource(request.resourceType) &&
(err.code === StatusCodes.PreconditionFailed ||
err.code === StatusCodes.Conflict ||
(err.code === StatusCodes.NotFound &&
err.substatus !== SubStatusCodes.ReadSessionNotAvailable)))) {
this.sessionContainer.set(request, resHeaders);
}
}
clearSessionToken(path) {
const request = this.getSessionParams(path);
this.sessionContainer.remove(request);
}
recordDiagnostics(diagnostic) {
const formatted = this.diagnosticFormatter.format(diagnostic);
this.diagnosticWriter.write(formatted);
}
initializeDiagnosticSettings(diagnosticLevel) {
this.diagnosticFormatter = new DefaultDiagnosticFormatter();
switch (diagnosticLevel) {
case CosmosDbDiagnosticLevel.info:
this.diagnosticWriter = new NoOpDiagnosticWriter();
break;
default:
this.diagnosticWriter = new LogDiagnosticWriter();
}
}
// TODO: move
getSessionParams(resourceLink) {
const resourceId = null;
let resourceAddress = null;
const parserOutput = parseLink(resourceLink);
resourceAddress = parserOutput.objectBody.self;
const resourceType = parserOutput.type;
return {
resourceId,
resourceAddress,
resourceType,
isNameBased: true,
};
}
isMasterResource(resourceType) {
if (resourceType === Constants.Path.OffersPathSegment ||
resourceType === Constants.Path.DatabasesPathSegment ||
resourceType === Constants.Path.UsersPathSegment ||
resourceType === Constants.Path.PermissionsPathSegment ||
resourceType === Constants.Path.TopologyPathSegment ||
resourceType === Constants.Path.DatabaseAccountPathSegment ||
resourceType === Constants.Path.PartitionKeyRangesPathSegment ||
resourceType === Constants.Path.CollectionsPathSegment) {
return true;
}
return false;
}
buildHeaders(requestContext) {
return getHeaders({
clientOptions: this.cosmosClientOptions,
defaultHeaders: {
...this.cosmosClientOptions.defaultHeaders,
...requestContext.options.initialHeaders,
},
verb: requestContext.method,
path: requestContext.path,
resourceId: requestContext.resourceId,
resourceType: requestContext.resourceType,
options: requestContext.options,
partitionKeyRangeId: requestContext.partitionKeyRangeId,
useMultipleWriteLocations: this.connectionPolicy.useMultipleWriteLocations,
partitionKey: requestContext.partitionKey !== undefined
? convertToInternalPartitionKey(requestContext.partitionKey)
: undefined, // TODO: Move this check from here to PartitionKey
operationType: requestContext.operationType,
});
}
/**
* Returns collection of properties which are derived from the context for Request Creation.
* These properties have client wide scope, as opposed to request specific scope.
* @returns
*/
getContextDerivedPropsForRequestCreation() {
return {
globalEndpointManager: this.globalEndpointManager,
requestAgent: this.cosmosClientOptions.agent,
connectionPolicy: this.connectionPolicy,
client: this,
plugins: this.cosmosClientOptions.plugins,
pipeline: this.pipeline,
httpClient: this.cosmosClientOptions.httpClient,
globalPartitionEndpointManager: this.globalPartitionEndpointManager,
};
}
getClientConfig() {
return this.clientConfig;
}
/**
* @internal
*/
refreshUserAgent(hostFramework) {
const updatedUserAgent = getUserAgent(this.cosmosClientOptions, hostFramework);
this.cosmosClientOptions.defaultHeaders[Constants.HttpHeaders.UserAgent] = updatedUserAgent;
this.cosmosClientOptions.defaultHeaders[Constants.HttpHeaders.CustomUserAgent] =
updatedUserAgent;
}
/**
* @internal
*/
getRetryOptions() {
return this.connectionPolicy.retryOptions;
}
/**
* @internal
*/
isPartitionLevelFailOverEnabled() {
return (this.globalEndpointManager.lastKnownPPAFEnabled ||
this.globalEndpointManager.lastKnownPPCBEnabled);
}
}
//# sourceMappingURL=ClientContext.js.map