From 8e2c46301d049a3f2cd1c4433c96ecb235fd07e4 Mon Sep 17 00:00:00 2001 From: asier-isayas Date: Mon, 18 Aug 2025 12:30:04 -0700 Subject: [PATCH] Allow Mongo users to change thee Guid Representation when conducting CRUD operations for documents (#2204) * mongo guid representation * format * fix return type --------- Co-authored-by: Asier Isayas --- src/Common/Constants.ts | 7 +++ src/Common/MongoProxyClient.ts | 13 +++++ .../Panes/SettingsPane/SettingsPane.tsx | 55 +++++++++++++++++++ src/Shared/StorageUtility.ts | 11 ++++ 4 files changed, 86 insertions(+) diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index b5b50d8fd..44d2b8b90 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -765,3 +765,10 @@ export const ShortenedQueryCopilotSampleContainerSchema = { userPrompt: "find all products", }; + +export enum MongoGuidRepresentation { + Standard = "Standard", + CSharpLegacy = "CSharpLegacy", + JavaLegacy = "JavaLegacy", + PythonLegacy = "PythonLegacy", +} diff --git a/src/Common/MongoProxyClient.ts b/src/Common/MongoProxyClient.ts index 89156e50c..a07572bd3 100644 --- a/src/Common/MongoProxyClient.ts +++ b/src/Common/MongoProxyClient.ts @@ -1,4 +1,5 @@ import { Constants as CosmosSDKConstants } from "@azure/cosmos"; +import { getMongoGuidRepresentation } from "Shared/StorageUtility"; import { AuthType } from "../AuthType"; import { configContext } from "../ConfigContext"; import * as DataModels from "../Contracts/DataModels"; @@ -139,6 +140,9 @@ export function readDocument( documentId && documentId.partitionKey && !documentId.partitionKey.systemKey ? documentId.partitionKeyProperties?.[0] : "", + clientSettings: { + guidRepresentation: getMongoGuidRepresentation(), + }, }; const endpoint = getEndpoint(configContext.MONGO_PROXY_ENDPOINT); @@ -181,6 +185,9 @@ export function createDocument( partitionKey: collection && collection.partitionKey && !collection.partitionKey.systemKey ? partitionKeyProperty : "", documentContent: JSON.stringify(documentContent), + clientSettings: { + guidRepresentation: getMongoGuidRepresentation(), + }, }; const endpoint = getEndpoint(configContext.MONGO_PROXY_ENDPOINT); @@ -228,6 +235,9 @@ export function updateDocument( ? documentId.partitionKeyProperties?.[0] : "", documentContent, + clientSettings: { + guidRepresentation: getMongoGuidRepresentation(), + }, }; const endpoint = getEndpoint(configContext.MONGO_PROXY_ENDPOINT); @@ -274,6 +284,9 @@ export function deleteDocuments( subscriptionID: userContext.subscriptionId, resourceGroup: userContext.resourceGroup, databaseAccountName: databaseAccount.name, + clientSettings: { + guidRepresentation: getMongoGuidRepresentation(), + }, }; const endpoint = getEndpoint(configContext.MONGO_PROXY_ENDPOINT); diff --git a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx index ac842a7d1..f2cf73768 100644 --- a/src/Explorer/Panes/SettingsPane/SettingsPane.tsx +++ b/src/Explorer/Panes/SettingsPane/SettingsPane.tsx @@ -199,6 +199,12 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ LocalStorageUtility.getEntryString(StorageKey.CopilotSampleDBEnabled) === "true", ); + const [mongoGuidRepresentation, setMongoGuidRepresentation] = useState( + LocalStorageUtility.hasItem(StorageKey.MongoGuidRepresentation) + ? (LocalStorageUtility.getEntryString(StorageKey.MongoGuidRepresentation) as Constants.MongoGuidRepresentation) + : Constants.MongoGuidRepresentation.CSharpLegacy, + ); + const styles = useStyles(); const explorerVersion = configContext.gitSha; @@ -261,6 +267,8 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ useDatabases.getState().sampleDataResourceTokenCollection && !isEmulator; + const shouldShowMongoGuidRepresentationOption = userContext.apiType === "Mongo"; + const handlerOnSubmit = async () => { setIsExecuting(true); @@ -412,6 +420,10 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ ); } + if (shouldShowMongoGuidRepresentationOption) { + LocalStorageUtility.setEntryString(StorageKey.MongoGuidRepresentation, mongoGuidRepresentation); + } + setIsExecuting(false); logConsoleInfo( `Updated items per page setting to ${LocalStorageUtility.getEntryNumber(StorageKey.ActualItemPerPage)}`, @@ -433,6 +445,14 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ ); } + if (shouldShowMongoGuidRepresentationOption) { + logConsoleInfo( + `Updated Mongo Guid Representation to ${LocalStorageUtility.getEntryString( + StorageKey.MongoGuidRepresentation, + )}`, + ); + } + refreshExplorer && (await explorer.refreshExplorer()); closeSidePanel(); }; @@ -477,6 +497,13 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ { key: SplitterDirection.Horizontal, text: "Horizontal" }, ]; + const mongoGuidRepresentationDropdownOptions: IDropdownOption[] = [ + { key: Constants.MongoGuidRepresentation.CSharpLegacy, text: Constants.MongoGuidRepresentation.CSharpLegacy }, + { key: Constants.MongoGuidRepresentation.JavaLegacy, text: Constants.MongoGuidRepresentation.JavaLegacy }, + { key: Constants.MongoGuidRepresentation.PythonLegacy, text: Constants.MongoGuidRepresentation.PythonLegacy }, + { key: Constants.MongoGuidRepresentation.Standard, text: Constants.MongoGuidRepresentation.Standard }, + ]; + const handleOnPriorityLevelOptionChange = ( ev: React.FormEvent, option: IChoiceGroupOption, @@ -559,6 +586,13 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ setRefreshExplorer(false); }; + const handleOnMongoGuidRepresentationOptionChange = ( + ev: React.FormEvent, + option: IDropdownOption, + ): void => { + setMongoGuidRepresentation(option.key as Constants.MongoGuidRepresentation); + }; + const choiceButtonStyles = { root: { clear: "both", @@ -1082,6 +1116,27 @@ export const SettingsPane: FunctionComponent<{ explorer: Explorer }> = ({ )} + {shouldShowMongoGuidRepresentationOption && ( + + +
Guid Representation
+
+ +
+
+ GuidRepresentation in MongoDB refers to how Globally Unique Identifiers (GUIDs) are serialized and + deserialized when stored in BSON documents. This will apply to all document operations. +
+ +
+
+
+ )} )} diff --git a/src/Shared/StorageUtility.ts b/src/Shared/StorageUtility.ts index c5b2f18dd..ba29f8826 100644 --- a/src/Shared/StorageUtility.ts +++ b/src/Shared/StorageUtility.ts @@ -1,3 +1,4 @@ +import { MongoGuidRepresentation } from "Common/Constants"; import { SplitterDirection } from "Common/Splitter"; import * as LocalStorageUtility from "./LocalStorageUtility"; import * as SessionStorageUtility from "./SessionStorageUtility"; @@ -33,6 +34,7 @@ export enum StorageKey { DocumentsTabPrefs, DefaultQueryResultsView, AppState, + MongoGuidRepresentation, } export const hasRUThresholdBeenConfigured = (): boolean => { @@ -65,4 +67,13 @@ export const getDefaultQueryResultsView = (): SplitterDirection => { return SplitterDirection.Horizontal; }; +export const getMongoGuidRepresentation = (): MongoGuidRepresentation => { + const mongoGuidRepresentation: string | null = LocalStorageUtility.getEntryString(StorageKey.MongoGuidRepresentation); + if (mongoGuidRepresentation) { + return mongoGuidRepresentation as MongoGuidRepresentation; + } + + return MongoGuidRepresentation.CSharpLegacy; +}; + export const DefaultRUThreshold = 5000;