mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-12-20 01:11:25 +00:00
DDM in DE for NOSQL (#2224)
* ddm for DE for noSQL * ddm for DE for noSQL * ddm for DE for noSQL * ddm fix for the default case and test fix * formatting issue * updated the text change * added validation errors --------- Co-authored-by: Sakshi Gupta <sakshig@microsoft.com>
This commit is contained in:
@@ -14,17 +14,30 @@ describe("Collection", () => {
|
||||
defaultTtl: 1,
|
||||
indexingPolicy: {} as DataModels.IndexingPolicy,
|
||||
partitionKey,
|
||||
_rid: "",
|
||||
_self: "",
|
||||
_etag: "",
|
||||
_rid: "testRid",
|
||||
_self: "testSelf",
|
||||
_etag: "testEtag",
|
||||
_ts: 1,
|
||||
id: "",
|
||||
id: "testCollection",
|
||||
};
|
||||
};
|
||||
|
||||
const generateMockCollectionWithDataModel = (data: DataModels.Collection): Collection => {
|
||||
const mockContainer = {} as Explorer;
|
||||
return generateCollection(mockContainer, "abc", data);
|
||||
const mockContainer = {
|
||||
isReadOnly: () => false,
|
||||
isFabricCapable: () => true,
|
||||
databaseAccount: () => ({
|
||||
name: () => "testAccount",
|
||||
id: () => "testAccount",
|
||||
properties: {
|
||||
enablePartitionKey: true,
|
||||
partitionKeyDefinitionVersion: 2,
|
||||
capabilities: [] as string[],
|
||||
databaseAccountEndpoint: "test.documents.azure.com",
|
||||
},
|
||||
}),
|
||||
} as unknown as Explorer;
|
||||
return generateCollection(mockContainer, "testDb", data);
|
||||
};
|
||||
|
||||
describe("Partition key path parsing", () => {
|
||||
@@ -78,7 +91,7 @@ describe("Collection", () => {
|
||||
expect(collection.partitionKeyPropertyHeaders[0]).toBe("/somePartitionKey");
|
||||
});
|
||||
|
||||
it("should be null if there is no partition key", () => {
|
||||
it("should be empty if there is no partition key", () => {
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
version: 2,
|
||||
paths: [],
|
||||
@@ -88,4 +101,103 @@ describe("Collection", () => {
|
||||
expect(collection.partitionKeyPropertyHeaders.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Collection properties", () => {
|
||||
let collection: Collection;
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: ["/id"],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
collection = generateMockCollectionWithDataModel(collectionsDataModel);
|
||||
});
|
||||
|
||||
it("should return correct collection id", () => {
|
||||
expect(collection.id()).toBe("testCollection");
|
||||
});
|
||||
|
||||
it("should return correct rid", () => {
|
||||
expect(collection.rid).toBe("testRid");
|
||||
});
|
||||
|
||||
it("should return correct self", () => {
|
||||
expect(collection.self).toBe("testSelf");
|
||||
});
|
||||
|
||||
it("should return correct collection type", () => {
|
||||
expect(collection.partitionKey).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("Collection type", () => {
|
||||
it("should identify large partitioned collection for v2 partition key", () => {
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: ["/id"],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
});
|
||||
const collection = generateMockCollectionWithDataModel(collectionsDataModel);
|
||||
expect(collection.partitionKey.version).toBe(2);
|
||||
expect(collection.partitionKey.paths).toEqual(["/id"]);
|
||||
});
|
||||
|
||||
it("should identify standard partitioned collection for v1 partition key", () => {
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: ["/id"],
|
||||
kind: "Hash",
|
||||
version: 1,
|
||||
});
|
||||
const collection = generateMockCollectionWithDataModel(collectionsDataModel);
|
||||
expect(collection.partitionKey.version).toBe(1);
|
||||
expect(collection.partitionKey.paths).toEqual(["/id"]);
|
||||
});
|
||||
|
||||
it("should identify collection without partition key", () => {
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: [],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
});
|
||||
const collection = generateMockCollectionWithDataModel(collectionsDataModel);
|
||||
expect(collection.partitionKey.paths).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Partition key handling", () => {
|
||||
it("should return correct partition key paths for multiple paths", () => {
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: ["/id", "/pk"],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
});
|
||||
const collection = generateMockCollectionWithDataModel(collectionsDataModel);
|
||||
expect(collection.partitionKey.paths).toEqual(["/id", "/pk"]);
|
||||
expect(collection.partitionKeyProperties).toEqual(["id", "pk"]);
|
||||
});
|
||||
|
||||
it("should handle empty partition key paths", () => {
|
||||
const collectionsDataModel = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: [],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
});
|
||||
const collection = generateMockCollectionWithDataModel(collectionsDataModel);
|
||||
expect(collection.partitionKey.paths).toEqual([]);
|
||||
expect(collection.partitionKeyProperties).toEqual([]);
|
||||
});
|
||||
|
||||
it("should handle undefined partition key", () => {
|
||||
const collectionData = generateMockCollectionsDataModelWithPartitionKey({
|
||||
paths: ["/id"],
|
||||
kind: "Hash",
|
||||
version: 2,
|
||||
});
|
||||
delete collectionData.partitionKey;
|
||||
const collection = generateMockCollectionWithDataModel(collectionData);
|
||||
expect(collection.partitionKey).toBeUndefined();
|
||||
expect(collection.partitionKeyProperties).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -67,6 +67,7 @@ export default class Collection implements ViewModels.Collection {
|
||||
public computedProperties: ko.Observable<DataModels.ComputedProperties>;
|
||||
public materializedViews: ko.Observable<DataModels.MaterializedView[]>;
|
||||
public materializedViewDefinition: ko.Observable<DataModels.MaterializedViewDefinition>;
|
||||
public dataMaskingPolicy: ko.Observable<DataModels.DataMaskingPolicy>;
|
||||
|
||||
public offer: ko.Observable<DataModels.Offer>;
|
||||
public conflictResolutionPolicy: ko.Observable<DataModels.ConflictResolutionPolicy>;
|
||||
@@ -136,25 +137,36 @@ export default class Collection implements ViewModels.Collection {
|
||||
this.materializedViews = ko.observable(data.materializedViews);
|
||||
this.materializedViewDefinition = ko.observable(data.materializedViewDefinition);
|
||||
|
||||
this.partitionKeyPropertyHeaders = this.partitionKey?.paths;
|
||||
this.partitionKeyProperties = this.partitionKeyPropertyHeaders?.map((partitionKeyPropertyHeader, i) => {
|
||||
// TODO fix this to only replace non-excaped single quotes
|
||||
let partitionKeyProperty = partitionKeyPropertyHeader.replace(/[/]+/g, ".").substring(1).replace(/[']+/g, "");
|
||||
// Initialize dataMaskingPolicy with default values if not present
|
||||
const defaultDataMaskingPolicy: DataModels.DataMaskingPolicy = {
|
||||
includedPaths: Array<{ path: string; strategy: string; startPosition: number; length: number }>(),
|
||||
excludedPaths: Array<string>(),
|
||||
policyFormatVersion: 2,
|
||||
isPolicyEnabled: false,
|
||||
};
|
||||
const observablePolicy = ko.observable(data.dataMaskingPolicy || defaultDataMaskingPolicy);
|
||||
observablePolicy.subscribe(() => {});
|
||||
this.dataMaskingPolicy = observablePolicy;
|
||||
this.partitionKeyPropertyHeaders = this.partitionKey?.paths || [];
|
||||
this.partitionKeyProperties =
|
||||
this.partitionKeyPropertyHeaders?.map((partitionKeyPropertyHeader, i) => {
|
||||
// TODO fix this to only replace non-excaped single quotes
|
||||
let partitionKeyProperty = partitionKeyPropertyHeader.replace(/[/]+/g, ".").substring(1).replace(/[']+/g, "");
|
||||
|
||||
if (userContext.apiType === "Mongo" && partitionKeyProperty) {
|
||||
if (~partitionKeyProperty.indexOf(`"`)) {
|
||||
partitionKeyProperty = partitionKeyProperty.replace(/["]+/g, "");
|
||||
if (userContext.apiType === "Mongo" && partitionKeyProperty) {
|
||||
if (~partitionKeyProperty.indexOf(`"`)) {
|
||||
partitionKeyProperty = partitionKeyProperty.replace(/["]+/g, "");
|
||||
}
|
||||
// TODO #10738269 : Add this logic in a derived class for Mongo
|
||||
if (partitionKeyProperty.indexOf("$v") > -1) {
|
||||
// From $v.shard.$v.key.$v > shard.key
|
||||
partitionKeyProperty = partitionKeyProperty.replace(/.\$v/g, "").replace(/\$v./g, "");
|
||||
this.partitionKeyPropertyHeaders[i] = "/" + partitionKeyProperty;
|
||||
}
|
||||
}
|
||||
// TODO #10738269 : Add this logic in a derived class for Mongo
|
||||
if (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;
|
||||
});
|
||||
return partitionKeyProperty;
|
||||
}) || [];
|
||||
|
||||
this.documentIds = ko.observableArray<DocumentId>([]);
|
||||
this.isCollectionExpanded = ko.observable<boolean>(false);
|
||||
@@ -163,7 +175,6 @@ export default class Collection implements ViewModels.Collection {
|
||||
|
||||
this.documentsFocused = ko.observable<boolean>();
|
||||
this.documentsFocused.subscribe((focus) => {
|
||||
console.log("Focus set on Documents: " + focus);
|
||||
this.focusedSubnodeKind(ViewModels.CollectionTabKind.Documents);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user