From 2a34e96fca80e412ded6194b7577f80fe2ea2659 Mon Sep 17 00:00:00 2001 From: Asier Isayas Date: Fri, 9 May 2025 13:43:55 -0400 Subject: [PATCH] Upgrade Cosmos SDK to v4.3 --- package.json | 2 +- src/Common/IteratorUtilities.ts | 11 ++--- src/Common/QueryError.ts | 16 +------- src/Common/dataAccess/queryDocuments.ts | 1 + src/Common/dataAccess/queryDocumentsPage.ts | 4 +- .../Panes/SettingsPane/SettingsPane.tsx | 41 ++++++++++++++++++- .../Tabs/QueryTab/QueryTabComponent.tsx | 19 ++------- src/Shared/StorageUtility.ts | 1 + src/Utils/QueryUtils.ts | 12 ++++++ 9 files changed, 64 insertions(+), 43 deletions(-) diff --git a/package.json b/package.json index f4b10a66d..b65027455 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "index.js", "dependencies": { "@azure/arm-cosmosdb": "9.1.0", - "@azure/cosmos": "4.2.0-beta.1", + "@azure/cosmos": "4.3.0", "@azure/cosmos-language-service": "0.0.5", "@azure/identity": "4.5.0", "@azure/msal-browser": "2.14.2", diff --git a/src/Common/IteratorUtilities.ts b/src/Common/IteratorUtilities.ts index 0cbe8ea63..827033fd7 100644 --- a/src/Common/IteratorUtilities.ts +++ b/src/Common/IteratorUtilities.ts @@ -1,4 +1,3 @@ -import { QueryOperationOptions } from "@azure/cosmos"; import { Action } from "Shared/Telemetry/TelemetryConstants"; import * as Constants from "../Common/Constants"; import { QueryResults } from "../Contracts/ViewModels"; @@ -14,18 +13,14 @@ interface QueryResponse { } export interface MinimalQueryIterator { - fetchNext: (queryOperationOptions?: QueryOperationOptions) => Promise; + fetchNext: () => Promise; } // Pick, "fetchNext">; -export function nextPage( - documentsIterator: MinimalQueryIterator, - firstItemIndex: number, - queryOperationOptions?: QueryOperationOptions, -): Promise { +export function nextPage(documentsIterator: MinimalQueryIterator, firstItemIndex: number): Promise { TelemetryProcessor.traceStart(Action.ExecuteQuery); - return documentsIterator.fetchNext(queryOperationOptions).then((response) => { + return documentsIterator.fetchNext().then((response) => { TelemetryProcessor.traceSuccess(Action.ExecuteQuery, { dataExplorerArea: Constants.Areas.Tab }); const documents = response.resources; // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/Common/QueryError.ts b/src/Common/QueryError.ts index c1bab1c02..de84deee7 100644 --- a/src/Common/QueryError.ts +++ b/src/Common/QueryError.ts @@ -1,5 +1,4 @@ import { monaco } from "Explorer/LazyMonaco"; -import { getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility"; export enum QueryErrorSeverity { Error = "Error", @@ -103,20 +102,9 @@ export interface ErrorEnrichment { learnMoreUrl?: string; } -const REPLACEMENT_MESSAGES: Record string> = { - OPERATION_RU_LIMIT_EXCEEDED: (original) => { - if (ruThresholdEnabled()) { - const threshold = getRUThreshold(); - return `Query exceeded the Request Unit (RU) limit of ${threshold} RUs. You can change this limit in Data Explorer settings.`; - } - return original; - }, -}; +const REPLACEMENT_MESSAGES: Record string> = {}; -const HELP_LINKS: Record = { - OPERATION_RU_LIMIT_EXCEEDED: - "https://learn.microsoft.com/en-us/azure/cosmos-db/data-explorer#configure-request-unit-threshold", -}; +const HELP_LINKS: Record = {}; export default class QueryError { message: string; diff --git a/src/Common/dataAccess/queryDocuments.ts b/src/Common/dataAccess/queryDocuments.ts index 223fe987d..44cd6f4e9 100644 --- a/src/Common/dataAccess/queryDocuments.ts +++ b/src/Common/dataAccess/queryDocuments.ts @@ -26,6 +26,7 @@ export const getCommonQueryOptions = (options: FeedOptions): FeedOptions => { options.maxItemCount || (storedItemPerPageSetting !== undefined && storedItemPerPageSetting) || Queries.itemsPerPage; + options.enableQueryControl = LocalStorageUtility.getEntryBoolean(StorageKey.QueryControlEnabled); options.maxDegreeOfParallelism = LocalStorageUtility.getEntryNumber(StorageKey.MaxDegreeOfParellism); options.disableNonStreamingOrderByQuery = !isVectorSearchEnabled(); return options; diff --git a/src/Common/dataAccess/queryDocumentsPage.ts b/src/Common/dataAccess/queryDocumentsPage.ts index 17e84ba28..556ed290c 100644 --- a/src/Common/dataAccess/queryDocumentsPage.ts +++ b/src/Common/dataAccess/queryDocumentsPage.ts @@ -1,4 +1,3 @@ -import { QueryOperationOptions } from "@azure/cosmos"; import { QueryResults } from "../../Contracts/ViewModels"; import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; import { getEntityName } from "../DocumentUtility"; @@ -9,13 +8,12 @@ export const queryDocumentsPage = async ( resourceName: string, documentsIterator: MinimalQueryIterator, firstItemIndex: number, - queryOperationOptions?: QueryOperationOptions, ): Promise => { const entityName = getEntityName(); const clearMessage = logConsoleProgress(`Querying ${entityName} for container ${resourceName}`); try { - const result: QueryResults = await nextPage(documentsIterator, firstItemIndex, queryOperationOptions); + const result: QueryResults = await nextPage(documentsIterator, firstItemIndex); const itemCount = (result.documents && result.documents.length) || 0; logConsoleInfo(`Successfully fetched ${itemCount} ${entityName} for container ${resourceName}`); return result; diff --git a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx index ca92b59ed..dd6072727 100644 --- a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx +++ b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx @@ -180,6 +180,11 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ ? LocalStorageUtility.getEntryNumber(StorageKey.MaxWaitTimeInSeconds) : Constants.Queries.DefaultMaxWaitTimeInSeconds, ); + const [queryControlEnabled, setQueryControlEnabled] = useState( + LocalStorageUtility.hasItem(StorageKey.QueryControlEnabled) + ? LocalStorageUtility.getEntryString(StorageKey.QueryControlEnabled) === "true" + : false, + ); const [maxDegreeOfParallelism, setMaxDegreeOfParallelism] = useState( LocalStorageUtility.hasItem(StorageKey.MaxDegreeOfParellism) ? LocalStorageUtility.getEntryNumber(StorageKey.MaxDegreeOfParellism) @@ -204,6 +209,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ !isEmulator; const shouldShowGraphAutoVizOption = userContext.apiType === "Gremlin" && !isEmulator; const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin" && !isEmulator; + const shouldShowEnhancedQueryControl = userContext.apiType === "SQL"; const shouldShowParallelismOption = userContext.apiType !== "Gremlin" && !isEmulator; const showEnableEntraIdRbac = isDataplaneRbacSupported(userContext.apiType) && @@ -381,6 +387,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ LocalStorageUtility.setEntryNumber(StorageKey.MaxWaitTimeInSeconds, MaxWaitTimeInSeconds); LocalStorageUtility.setEntryString(StorageKey.ContainerPaginationEnabled, containerPaginationEnabled.toString()); LocalStorageUtility.setEntryString(StorageKey.IsCrossPartitionQueryEnabled, crossPartitionQueryEnabled.toString()); + LocalStorageUtility.setEntryString(StorageKey.QueryControlEnabled, queryControlEnabled.toString()); LocalStorageUtility.setEntryNumber(StorageKey.MaxDegreeOfParellism, maxDegreeOfParallelism); LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, priorityLevel.toString()); LocalStorageUtility.setEntryString(StorageKey.CopilotSampleDBEnabled, copilotSampleDBEnabled.toString()); @@ -410,6 +417,7 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ `Updated items per page setting to ${LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage)}`, ); logConsoleInfo(`${crossPartitionQueryEnabled ? "Enabled" : "Disabled"} cross-partition query feed option`); + logConsoleInfo(`${queryControlEnabled ? "Enabled" : "Disabled"} query control option`); logConsoleInfo( `Updated the max degree of parallelism query feed option to ${LocalStorageUtility.getEntryNumber( StorageKey.MaxDegreeOfParellism, @@ -760,7 +768,6 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ )} -
RU Limit
@@ -943,6 +950,38 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({
)} + {shouldShowEnhancedQueryControl && ( + + +
Enhanced query control
+
+ +
+
+ Query up to the max degree of parallelism. + + {" "} + Learn more{" "} + +
+ setQueryControlEnabled(!queryControlEnabled)} + label="Enable query control" + /> +
+
+
+ )} {shouldShowParallelismOption && ( diff --git a/src/Explorer/Tabs/QueryTab/QueryTabComponent.tsx b/src/Explorer/Tabs/QueryTab/QueryTabComponent.tsx index 747ff3349..245f52105 100644 --- a/src/Explorer/Tabs/QueryTab/QueryTabComponent.tsx +++ b/src/Explorer/Tabs/QueryTab/QueryTabComponent.tsx @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable no-console */ -import { FeedOptions, QueryOperationOptions } from "@azure/cosmos"; +import { FeedOptions } from "@azure/cosmos"; import { AuthType } from "AuthType"; import QueryError, { createMonacoErrorLocationResolver, createMonacoMarkersForQueryErrors } from "Common/QueryError"; import { SplitterDirection } from "Common/Splitter"; @@ -19,7 +19,7 @@ import { CosmosFluentProvider } from "Explorer/Theme/ThemeUtil"; import { useSelectedNode } from "Explorer/useSelectedNode"; import { KeyboardAction } from "KeyboardShortcuts"; import { QueryConstants } from "Shared/Constants"; -import { LocalStorageUtility, StorageKey, getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility"; +import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility"; import { Action } from "Shared/Telemetry/TelemetryConstants"; import { Allotment } from "allotment"; import { useClientWriteEnabled } from "hooks/useClientWriteEnabled"; @@ -370,21 +370,8 @@ class QueryTabComponentImpl extends React.Component - await queryDocumentsPage( - this.props.collection && this.props.collection.id(), - this._iterator, - firstItemIndex, - queryOperationOptions, - ); + await queryDocumentsPage(this.props.collection && this.props.collection.id(), this._iterator, firstItemIndex); this.props.tabsBaseInstance.isExecuting(true); this.setState({ isExecuting: true, diff --git a/src/Shared/StorageUtility.ts b/src/Shared/StorageUtility.ts index f2baa85da..c5b2f18dd 100644 --- a/src/Shared/StorageUtility.ts +++ b/src/Shared/StorageUtility.ts @@ -21,6 +21,7 @@ export enum StorageKey { DatabaseAccountId, EncryptedKeyToken, IsCrossPartitionQueryEnabled, + QueryControlEnabled, MaxDegreeOfParellism, IsGraphAutoVizDisabled, TenantId, diff --git a/src/Utils/QueryUtils.ts b/src/Utils/QueryUtils.ts index 07822a422..8543d6873 100644 --- a/src/Utils/QueryUtils.ts +++ b/src/Utils/QueryUtils.ts @@ -1,4 +1,7 @@ import { PartitionKey, PartitionKeyDefinition } from "@azure/cosmos"; +import { getRUThreshold, ruThresholdEnabled } from "Shared/StorageUtility"; +import { userContext } from "UserContext"; +import { logConsoleError } from "Utils/NotificationConsoleUtils"; import * as DataModels from "../Contracts/DataModels"; import * as ViewModels from "../Contracts/ViewModels"; @@ -86,6 +89,15 @@ export const queryPagesUntilContentPresent = async ( results.roundTrips = roundTrips; results.requestCharge = Number(results.requestCharge) + netRequestCharge; netRequestCharge = Number(results.requestCharge); + + if (results.hasMoreResults && userContext.apiType === "SQL" && ruThresholdEnabled()) { + const ruThreshold: number = getRUThreshold(); + if (netRequestCharge > ruThreshold) { + logConsoleError(`Request discontinued after exceeding the Request Unit threshold of ${ruThreshold}.`); + return results; + } + } + const resultsMetadata = { hasMoreResults: results.hasMoreResults, itemCount: results.itemCount,