diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index 2e877f872..c9a458558 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -45,6 +45,8 @@ export class ArmResourceTypes { export class BackendDefaults { public static partitionKeyKind = "Hash"; + public static partitionKeyMultiHash = "MultiHash"; + public static maxNumMultiHashPartition = 2; public static singlePartitionStorageInGb: string = "10"; public static multiPartitionStorageInGb: string = "100"; public static maxChangeFeedRetentionDuration: number = 10; diff --git a/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts b/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts index aca891f24..c06596531 100644 --- a/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts +++ b/src/Explorer/DataSamples/ContainerSampleGenerator.test.ts @@ -133,7 +133,6 @@ describe("ContainerSampleGenerator", () => { } as DatabaseAccount, }); - // Rejects with error that contains experience expect(ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub)).rejects.toMatch(experience); }); diff --git a/src/Explorer/Panes/AddCollectionPanel.tsx b/src/Explorer/Panes/AddCollectionPanel.tsx index dfaf5975c..9a49f3fcd 100644 --- a/src/Explorer/Panes/AddCollectionPanel.tsx +++ b/src/Explorer/Panes/AddCollectionPanel.tsx @@ -89,9 +89,10 @@ export interface AddCollectionPanelState { enableIndexing: boolean; isSharded: boolean; partitionKey: string; + subPartitionKeys: string[]; enableDedicatedThroughput: boolean; createMongoWildCardIndex: boolean; - useHashV2: boolean; + useHashV1: boolean; enableAnalyticalStore: boolean; uniqueKeys: string[]; errorMessage: string; @@ -121,10 +122,11 @@ export class AddCollectionPanel extends React.Component + {userContext.apiType === "SQL" && + this.state.subPartitionKeys.map((subPartitionKey: string, index: number) => { + return ( + +
+ 0 ? 1 : 0} + className="panelTextField" + autoComplete="off" + placeholder={this.getPartitionKeyPlaceHolder(index)} + aria-label={this.getPartitionKeyName()} + pattern={".*"} + title={""} + value={subPartitionKey} + onChange={(event: React.ChangeEvent) => { + const subPartitionKeys = [...this.state.subPartitionKeys]; + if (!this.state.subPartitionKeys[index] && !event.target.value.startsWith("/")) { + subPartitionKeys[index] = "/" + event.target.value.trim(); + this.setState({ subPartitionKeys }); + } else { + subPartitionKeys[index] = event.target.value.trim(); + this.setState({ subPartitionKeys }); + } + }} + /> + { + const subPartitionKeys = this.state.subPartitionKeys.filter((uniqueKey, j) => index !== j); + this.setState({ subPartitionKeys }); + }} + /> +
+ ); + })} + {userContext.apiType === "SQL" && userContext.features.enableHierarchicalKeys && ( + + + {this.state.subPartitionKeys.length > 0 && ( + + This feature allows you to + partition your data with up to three levels of keys for better data distribution. Requires preview + version of .NET V3 or Java V4 SDK.{" "} + + Learn more + + + )} + + )} )} @@ -603,9 +676,9 @@ export class AddCollectionPanel extends React.Component @@ -767,18 +840,29 @@ export class AddCollectionPanel extends React.Component, isChecked: boolean) => - this.setState({ useHashV2: isChecked }) - } - /> + + , isChecked: boolean) => + this.setState({ useHashV1: isChecked, subPartitionKeys: [] }) + } + /> + + To ensure compatibility with + older SDKs, the created container will use a legacy partitioning scheme that supports partition + key values of size only up to 101 bytes. If this is enabled, you will not be able to use + hierarchical partition keys.{" "} + + Learn more + + + )} @@ -833,12 +917,20 @@ export class AddCollectionPanel extends React.Component 0 + ? this.state.subPartitionKeys + : []), + ], + kind: userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0 ? "MultiHash" : "Hash", version: partitionKeyVersion, } : undefined; diff --git a/src/Explorer/Panes/__snapshots__/AddCollectionPanel.test.tsx.snap b/src/Explorer/Panes/__snapshots__/AddCollectionPanel.test.tsx.snap index 903a6dd4e..2df43e44b 100644 --- a/src/Explorer/Panes/__snapshots__/AddCollectionPanel.test.tsx.snap +++ b/src/Explorer/Panes/__snapshots__/AddCollectionPanel.test.tsx.snap @@ -223,7 +223,7 @@ exports[`AddCollectionPanel should render Default properly 1`] = ` id="addCollection-partitionKeyValue" onChange={[Function]} pattern=".*" - placeholder="e.g., /address/zipCode" + placeholder="Required - first partition key e.g., /TenantId" required={true} size={40} title="" @@ -396,26 +396,49 @@ exports[`AddCollectionPanel should render Default properly 1`] = ` className="panelGroupSpacing" id="collapsibleSectionContent" > - + + /> + + + To ensure compatibility with older SDKs, the created container will use a legacy partitioning scheme that supports partition key values of size only up to 101 bytes. If this is enabled, you will not be able to use hierarchical partition keys. + + + Learn more + + + diff --git a/src/Platform/Hosted/extractFeatures.ts b/src/Platform/Hosted/extractFeatures.ts index 368f09eb2..2804bd666 100644 --- a/src/Platform/Hosted/extractFeatures.ts +++ b/src/Platform/Hosted/extractFeatures.ts @@ -29,6 +29,7 @@ export type Features = { readonly mongoProxyEndpoint?: string; readonly mongoProxyAPIs?: string; readonly enableThroughputCap: boolean; + readonly enableHierarchicalKeys: boolean; // can be set via both flight and feature flag autoscaleDefault: boolean; @@ -90,6 +91,7 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear partitionKeyDefault2: "true" === get("pkpartitionkeytest"), notebooksDownBanner: "true" === get("notebooksDownBanner"), enableThroughputCap: "true" === get("enablethroughputcap"), + enableHierarchicalKeys: "true" === get("enablehierarchicalkeys"), }; }