mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 01:11:25 +00:00
Add support for multi-partition key (#1252)
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user