Add support for multi-partition key (#1252)

This commit is contained in:
victor-meng
2022-04-21 13:37:02 -07:00
committed by GitHub
parent 9e7bbcfab6
commit 22f7d588a1
21 changed files with 175 additions and 158 deletions

View File

@@ -74,7 +74,7 @@ export default class ConflictsTab extends TabsBase {
this.partitionKey = options.partitionKey || (this.collection && this.collection.partitionKey);
this.conflictIds = options.conflictIds;
this.partitionKeyPropertyHeader =
(this.collection && this.collection.partitionKeyPropertyHeader) || this._getPartitionKeyPropertyHeader();
this.collection?.partitionKeyPropertyHeaders?.[0] || this._getPartitionKeyPropertyHeader();
this.partitionKeyProperty = !!this.partitionKeyPropertyHeader
? this.partitionKeyPropertyHeader.replace(/[/]+/g, ".").substr(1).replace(/[']+/g, "")
: null;

View File

@@ -143,16 +143,18 @@
<tr>
<th class="documentsGridHeader" data-bind="text: idHeader" tabindex="0"></th>
<!-- ko if: showPartitionKey -->
<!-- ko foreach: partitionKeyPropertyHeaders -->
<th
class="documentsGridHeader documentsGridPartition evenlySpacedHeader"
data-bind="
attr: {
title: partitionKeyPropertyHeader
title: $data
},
text: partitionKeyPropertyHeader"
text: $data"
tabindex="0"
></th>
<!-- /ko -->
<!-- /ko -->
<th
class="refreshColHeader"
role="button"
@@ -182,13 +184,13 @@
tabindex="0"
>
<td class="tabdocumentsGridElement"><a data-bind="text: $data.id, attr: { title: $data.id }"></a></td>
<!-- ko if: $data.partitionKeyProperty -->
<td class="tabdocumentsGridElement" colspan="2">
<a
data-bind="text: $data.stringPartitionKeyValue, attr: { title: $data.stringPartitionKeyValue }"
></a>
<!-- ko if: $data.partitionKeyProperties -->
<!-- ko foreach: $data.stringPartitionKeyValues -->
<td class="tabdocumentsGridElement" data-bind="colspan: $parent.stringPartitionKeyValues.length + 1">
<a data-bind="text: $data, attr: { title: $data }"></a>
</td>
<!-- /ko -->
<!-- /ko -->
</tr>
<!-- /ko -->
</tbody>

View File

@@ -50,7 +50,7 @@ export default class DocumentsTab extends TabsBase {
public editorState: ko.Observable<ViewModels.DocumentExplorerState>;
public newDocumentButton: ViewModels.Button;
public saveNewDocumentButton: ViewModels.Button;
public saveExisitingDocumentButton: ViewModels.Button;
public saveExistingDocumentButton: ViewModels.Button;
public discardNewDocumentChangesButton: ViewModels.Button;
public discardExisitingDocumentChangesButton: ViewModels.Button;
public deleteExisitingDocumentButton: ViewModels.Button;
@@ -65,8 +65,8 @@ export default class DocumentsTab extends TabsBase {
// TODO need to refactor
public partitionKey: DataModels.PartitionKey;
public partitionKeyPropertyHeader: string;
public partitionKeyProperty: string;
public partitionKeyPropertyHeaders: string[];
public partitionKeyProperties: string[];
public documentIds: ko.ObservableArray<DocumentId>;
private _documentsIterator: QueryIterator<ItemDefinition & Resource>;
@@ -90,11 +90,10 @@ export default class DocumentsTab extends TabsBase {
this._resourceTokenPartitionKey = options.resourceTokenPartitionKey;
this.documentIds = options.documentIds;
this.partitionKeyPropertyHeader =
(this.collection && this.collection.partitionKeyPropertyHeader) || this._getPartitionKeyPropertyHeader();
this.partitionKeyProperty = !!this.partitionKeyPropertyHeader
? this.partitionKeyPropertyHeader.replace(/[/]+/g, ".").substr(1).replace(/[']+/g, "")
: null;
this.partitionKeyPropertyHeaders = this.collection?.partitionKeyPropertyHeaders || this.partitionKey?.paths;
this.partitionKeyProperties = this.partitionKeyPropertyHeaders?.map((partitionKeyPropertyHeader) =>
partitionKeyPropertyHeader.replace(/[/]+/g, ".").substring(1).replace(/[']+/g, "")
);
this.isFilterExpanded = ko.observable<boolean>(false);
this.isFilterCreated = ko.observable<boolean>(true);
@@ -227,7 +226,7 @@ export default class DocumentsTab extends TabsBase {
}),
};
this.saveExisitingDocumentButton = {
this.saveExistingDocumentButton = {
enabled: ko.computed<boolean>(() => {
switch (this.editorState()) {
case ViewModels.DocumentExplorerState.exisitingDocumentDirtyValid:
@@ -445,8 +444,7 @@ export default class DocumentsTab extends TabsBase {
savedDocument,
this.partitionKey as PartitionKeyDefinition
);
const partitionKeyValue = partitionKeyValueArray && partitionKeyValueArray[0];
let id = new DocumentId(this, savedDocument, partitionKeyValue);
let id = new DocumentId(this, savedDocument, partitionKeyValueArray);
let ids = this.documentIds();
ids.push(id);
@@ -489,14 +487,12 @@ export default class DocumentsTab extends TabsBase {
return Q();
};
public onSaveExisitingDocumentClick = (): Promise<any> => {
public onSaveExistingDocumentClick = (): Promise<any> => {
const selectedDocumentId = this.selectedDocumentId();
const documentContent = JSON.parse(this.selectedDocumentContent());
const partitionKeyValueArray = extractPartitionKey(documentContent, this.partitionKey as PartitionKeyDefinition);
const partitionKeyValue = partitionKeyValueArray && partitionKeyValueArray[0];
selectedDocumentId.partitionKeyValue = partitionKeyValue;
selectedDocumentId.partitionKeyValue = partitionKeyValueArray;
this.isExecutionError(false);
const startKey: number = TelemetryProcessor.traceStart(Action.UpdateDocument, {
@@ -800,7 +796,7 @@ export default class DocumentsTab extends TabsBase {
}
public buildQuery(filter: string): string {
return QueryUtils.buildDocumentsQuery(filter, this.partitionKeyProperty, this.partitionKey);
return QueryUtils.buildDocumentsQuery(filter, this.partitionKeyProperties, this.partitionKey);
}
protected getTabsButtons(): CommandButtonComponentProps[] {
@@ -844,16 +840,16 @@ export default class DocumentsTab extends TabsBase {
});
}
if (this.saveExisitingDocumentButton.visible()) {
if (this.saveExistingDocumentButton.visible()) {
const label = "Update";
buttons.push({
iconSrc: SaveIcon,
iconAlt: label,
onCommandClick: this.onSaveExisitingDocumentClick,
onCommandClick: this.onSaveExistingDocumentClick,
commandButtonLabel: label,
ariaLabel: label,
hasPopup: false,
disabled: !this.saveExisitingDocumentButton.enabled(),
disabled: !this.saveExistingDocumentButton.enabled(),
});
}
@@ -899,8 +895,8 @@ export default class DocumentsTab extends TabsBase {
this.saveNewDocumentButton.enabled,
this.discardNewDocumentChangesButton.visible,
this.discardNewDocumentChangesButton.enabled,
this.saveExisitingDocumentButton.visible,
this.saveExisitingDocumentButton.enabled,
this.saveExistingDocumentButton.visible,
this.saveExistingDocumentButton.enabled,
this.discardExisitingDocumentChangesButton.visible,
this.discardExisitingDocumentChangesButton.enabled,
this.deleteExisitingDocumentButton.visible,
@@ -910,16 +906,6 @@ export default class DocumentsTab extends TabsBase {
this.updateNavbarWithTabsButtons();
}
private _getPartitionKeyPropertyHeader(): string {
return (
(this.partitionKey &&
this.partitionKey.paths &&
this.partitionKey.paths.length > 0 &&
this.partitionKey.paths[0]) ||
null
);
}
public static _createUploadButton(container: Explorer): CommandButtonComponentProps {
const label = "Upload Item";
return {

View File

@@ -29,15 +29,19 @@ export default class MongoDocumentsTab extends DocumentsTab {
super(options);
this.lastFilterContents = ko.observableArray<string>(['{"id":"foo"}', "{ qty: { $gte: 20 } }"]);
if (this.partitionKeyProperty && ~this.partitionKeyProperty.indexOf(`"`)) {
this.partitionKeyProperty = this.partitionKeyProperty.replace(/["]+/g, "");
}
this.partitionKeyProperties = this.partitionKeyProperties?.map((partitionKeyProperty, i) => {
if (partitionKeyProperty && ~partitionKeyProperty.indexOf(`"`)) {
partitionKeyProperty = partitionKeyProperty.replace(/["]+/g, "");
}
if (this.partitionKeyProperty && this.partitionKeyProperty.indexOf("$v") > -1) {
// From $v.shard.$v.key.$v > shard.key
this.partitionKeyProperty = this.partitionKeyProperty.replace(/.\$v/g, "").replace(/\$v./g, "");
this.partitionKeyPropertyHeader = "/" + this.partitionKeyProperty;
}
if (partitionKeyProperty && partitionKeyProperty.indexOf("$v") > -1) {
// From $v.shard.$v.key.$v > shard.key
partitionKeyProperty = partitionKeyProperty.replace(/.\$v/g, "").replace(/\$v./g, "");
this.partitionKeyPropertyHeaders[i] = "/" + partitionKeyProperty;
}
return partitionKeyProperty;
});
this.isFilterExpanded = ko.observable<boolean>(true);
super.buildCommandBarOptions.bind(this);
@@ -52,12 +56,9 @@ export default class MongoDocumentsTab extends DocumentsTab {
tabTitle: this.tabTitle(),
});
if (
this.partitionKeyProperty &&
this.partitionKeyProperty !== "_id" &&
!this._hasShardKeySpecified(documentContent)
) {
const message = `The document is lacking the shard property: ${this.partitionKeyProperty}`;
const partitionKeyProperty = this.partitionKeyProperties?.[0];
if (partitionKeyProperty !== "_id" && !this._hasShardKeySpecified(documentContent)) {
const message = `The document is lacking the shard property: ${partitionKeyProperty}`;
this.displayedError(message);
let that = this;
setTimeout(() => {
@@ -79,7 +80,12 @@ export default class MongoDocumentsTab extends DocumentsTab {
this.isExecutionError(false);
this.isExecuting(true);
return createDocument(this.collection.databaseId, this.collection, this.partitionKeyProperty, documentContent)
return createDocument(
this.collection.databaseId,
this.collection,
this.partitionKeyProperties?.[0],
documentContent
)
.then(
(savedDocument: any) => {
let partitionKeyArray = extractPartitionKey(
@@ -87,9 +93,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
this._getPartitionKeyDefinition() as PartitionKeyDefinition
);
let partitionKeyValue = partitionKeyArray && partitionKeyArray[0];
let id = new ObjectId(this, savedDocument, partitionKeyValue);
let id = new ObjectId(this, savedDocument, partitionKeyArray);
let ids = this.documentIds();
ids.push(id);
delete savedDocument._self;
@@ -128,7 +132,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
.finally(() => this.isExecuting(false));
};
public onSaveExisitingDocumentClick = (): Promise<any> => {
public onSaveExistingDocumentClick = (): Promise<any> => {
const selectedDocumentId = this.selectedDocumentId();
const documentContent = this.selectedDocumentContent();
this.isExecutionError(false);
@@ -151,9 +155,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
this._getPartitionKeyDefinition() as PartitionKeyDefinition
);
let partitionKeyValue = partitionKeyArray && partitionKeyArray[0];
const id = new ObjectId(this, updatedDocument, partitionKeyValue);
const id = new ObjectId(this, updatedDocument, partitionKeyArray);
documentId.id(id.id());
}
});
@@ -214,7 +216,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
})
.map((rawDocument: any) => {
const partitionKeyValue = rawDocument._partitionKeyValue;
return new DocumentId(this, rawDocument, partitionKeyValue);
return new DocumentId(this, rawDocument, [partitionKeyValue]);
});
const merged = currentDocuments.concat(nextDocumentIds);
@@ -303,7 +305,7 @@ export default class MongoDocumentsTab extends DocumentsTab {
// Convert BsonSchema2 to /path format
partitionKey = {
kind: partitionKey.kind,
paths: ["/" + this.partitionKeyProperty.replace(/\./g, "/")],
paths: ["/" + this.partitionKeyProperties?.[0].replace(/\./g, "/")],
version: partitionKey.version,
};
}