mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2026-01-01 07:11:23 +00:00
Migrated Hosted Explorer to React (#360)
Co-authored-by: Victor Meng <vimeng@microsoft.com> Co-authored-by: Steve Faulkner <stfaul@microsoft.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { ConnectionStringParser } from "./ConnectionStringParser";
|
||||
import { parseConnectionString } from "./ConnectionStringParser";
|
||||
|
||||
describe("ConnectionStringParser", () => {
|
||||
const mockAccountName: string = "Test";
|
||||
const mockMasterKey: string = "some-key";
|
||||
|
||||
it("should parse a valid sql account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`AccountEndpoint=https://${mockAccountName}.documents.azure.com:443/;AccountKey=${mockMasterKey};`
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid mongo account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`mongodb://${mockAccountName}:${mockMasterKey}@${mockAccountName}.documents.azure.com:10255`
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid compute mongo account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`mongodb://${mockAccountName}:${mockMasterKey}@${mockAccountName}.mongo.cosmos.azure.com:10255`
|
||||
);
|
||||
|
||||
@@ -33,7 +33,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid graph account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`AccountEndpoint=https://${mockAccountName}.documents.azure.com:443/;AccountKey=${mockMasterKey};ApiKind=Gremlin;`
|
||||
);
|
||||
|
||||
@@ -42,7 +42,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid table account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`DefaultEndpointsProtocol=https;AccountName=${mockAccountName};AccountKey=${mockMasterKey};TableEndpoint=https://${mockAccountName}.table.cosmosdb.azure.com:443/;`
|
||||
);
|
||||
|
||||
@@ -51,7 +51,7 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should parse a valid cassandra account connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
const metadata = parseConnectionString(
|
||||
`AccountEndpoint=${mockAccountName}.cassandra.cosmosdb.azure.com;AccountKey=${mockMasterKey};`
|
||||
);
|
||||
|
||||
@@ -60,15 +60,13 @@ describe("ConnectionStringParser", () => {
|
||||
});
|
||||
|
||||
it("should fail to parse an invalid connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString(
|
||||
"some-rogue-connection-string"
|
||||
);
|
||||
const metadata = parseConnectionString("some-rogue-connection-string");
|
||||
|
||||
expect(metadata).toBe(undefined);
|
||||
});
|
||||
|
||||
it("should fail to parse an empty connection string", () => {
|
||||
const metadata: DataModels.AccessInputMetadata = ConnectionStringParser.parseConnectionString("");
|
||||
const metadata = parseConnectionString("");
|
||||
|
||||
expect(metadata).toBe(undefined);
|
||||
});
|
||||
|
||||
@@ -1,50 +1,48 @@
|
||||
import * as Constants from "../../../Common/Constants";
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import { AccessInputMetadata, ApiKind } from "../../../Contracts/DataModels";
|
||||
|
||||
export class ConnectionStringParser {
|
||||
public static parseConnectionString(connectionString: string): DataModels.AccessInputMetadata {
|
||||
if (!!connectionString) {
|
||||
try {
|
||||
const accessInput: DataModels.AccessInputMetadata = {} as DataModels.AccessInputMetadata;
|
||||
const connectionStringParts = connectionString.split(";");
|
||||
export function parseConnectionString(connectionString: string): AccessInputMetadata {
|
||||
if (connectionString) {
|
||||
try {
|
||||
const accessInput = {} as AccessInputMetadata;
|
||||
const connectionStringParts = connectionString.split(";");
|
||||
|
||||
connectionStringParts.forEach((connectionStringPart: string) => {
|
||||
if (RegExp(Constants.EndpointsRegex.sql).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.sql)[1];
|
||||
accessInput.apiKind = DataModels.ApiKind.SQL;
|
||||
} else if (RegExp(Constants.EndpointsRegex.mongo).test(connectionStringPart)) {
|
||||
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongo);
|
||||
accessInput.accountName = matches && matches.length > 1 && matches[2];
|
||||
accessInput.apiKind = DataModels.ApiKind.MongoDB;
|
||||
} else if (RegExp(Constants.EndpointsRegex.mongoCompute).test(connectionStringPart)) {
|
||||
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongoCompute);
|
||||
accessInput.accountName = matches && matches.length > 1 && matches[2];
|
||||
accessInput.apiKind = DataModels.ApiKind.MongoDBCompute;
|
||||
} else if (Constants.EndpointsRegex.cassandra.some(regex => RegExp(regex).test(connectionStringPart))) {
|
||||
Constants.EndpointsRegex.cassandra.forEach(regex => {
|
||||
if (RegExp(regex).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(regex)[1];
|
||||
accessInput.apiKind = DataModels.ApiKind.Cassandra;
|
||||
}
|
||||
});
|
||||
} else if (RegExp(Constants.EndpointsRegex.table).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.table)[1];
|
||||
accessInput.apiKind = DataModels.ApiKind.Table;
|
||||
} else if (connectionStringPart.indexOf("ApiKind=Gremlin") >= 0) {
|
||||
accessInput.apiKind = DataModels.ApiKind.Graph;
|
||||
}
|
||||
});
|
||||
|
||||
if (Object.keys(accessInput).length === 0) {
|
||||
return undefined;
|
||||
connectionStringParts.forEach((connectionStringPart: string) => {
|
||||
if (RegExp(Constants.EndpointsRegex.sql).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.sql)[1];
|
||||
accessInput.apiKind = ApiKind.SQL;
|
||||
} else if (RegExp(Constants.EndpointsRegex.mongo).test(connectionStringPart)) {
|
||||
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongo);
|
||||
accessInput.accountName = matches && matches.length > 1 && matches[2];
|
||||
accessInput.apiKind = ApiKind.MongoDB;
|
||||
} else if (RegExp(Constants.EndpointsRegex.mongoCompute).test(connectionStringPart)) {
|
||||
const matches: string[] = connectionStringPart.match(Constants.EndpointsRegex.mongoCompute);
|
||||
accessInput.accountName = matches && matches.length > 1 && matches[2];
|
||||
accessInput.apiKind = ApiKind.MongoDBCompute;
|
||||
} else if (Constants.EndpointsRegex.cassandra.some(regex => RegExp(regex).test(connectionStringPart))) {
|
||||
Constants.EndpointsRegex.cassandra.forEach(regex => {
|
||||
if (RegExp(regex).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(regex)[1];
|
||||
accessInput.apiKind = ApiKind.Cassandra;
|
||||
}
|
||||
});
|
||||
} else if (RegExp(Constants.EndpointsRegex.table).test(connectionStringPart)) {
|
||||
accessInput.accountName = connectionStringPart.match(Constants.EndpointsRegex.table)[1];
|
||||
accessInput.apiKind = ApiKind.Table;
|
||||
} else if (connectionStringPart.indexOf("ApiKind=Gremlin") >= 0) {
|
||||
accessInput.apiKind = ApiKind.Graph;
|
||||
}
|
||||
});
|
||||
|
||||
return accessInput;
|
||||
} catch (error) {
|
||||
if (Object.keys(accessInput).length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return accessInput;
|
||||
} catch (error) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
44
src/Platform/Hosted/Helpers/ResourceTokenUtils.test.ts
Normal file
44
src/Platform/Hosted/Helpers/ResourceTokenUtils.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { isResourceTokenConnectionString, parseResourceTokenConnectionString } from "./ResourceTokenUtils";
|
||||
|
||||
describe("parseResourceTokenConnectionString", () => {
|
||||
it("correctly parses resource token connection string", () => {
|
||||
const connectionString =
|
||||
"AccountEndpoint=fakeEndpoint;DatabaseId=fakeDatabaseId;CollectionId=fakeCollectionId;type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;";
|
||||
const properties = parseResourceTokenConnectionString(connectionString);
|
||||
|
||||
expect(properties).toEqual({
|
||||
accountEndpoint: "fakeEndpoint",
|
||||
collectionId: "fakeCollectionId",
|
||||
databaseId: "fakeDatabaseId",
|
||||
partitionKey: undefined,
|
||||
resourceToken: "type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;"
|
||||
});
|
||||
});
|
||||
|
||||
it("correctly parses resource token connection string with partition key", () => {
|
||||
const connectionString =
|
||||
"type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;AccountEndpoint=fakeEndpoint;DatabaseId=fakeDatabaseId;CollectionId=fakeCollectionId;PartitionKey=fakePartitionKey;";
|
||||
const properties = parseResourceTokenConnectionString(connectionString);
|
||||
|
||||
expect(properties).toEqual({
|
||||
accountEndpoint: "fakeEndpoint",
|
||||
collectionId: "fakeCollectionId",
|
||||
databaseId: "fakeDatabaseId",
|
||||
partitionKey: "fakePartitionKey",
|
||||
resourceToken: "type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("isResourceToken", () => {
|
||||
it("valid resource connection string", () => {
|
||||
const connectionString =
|
||||
"AccountEndpoint=fakeEndpoint;DatabaseId=fakeDatabaseId;CollectionId=fakeCollectionId;type=resource&ver=1&sig=2dIP+CdIfT1ScwHWdv5GGw==;fakeToken;";
|
||||
expect(isResourceTokenConnectionString(connectionString)).toBe(true);
|
||||
});
|
||||
|
||||
it("non-resource connection string", () => {
|
||||
const connectionString = "AccountEndpoint=https://stfaul-sql.documents.azure.com:443/;AccountKey=foo;";
|
||||
expect(isResourceTokenConnectionString(connectionString)).toBe(false);
|
||||
});
|
||||
});
|
||||
43
src/Platform/Hosted/Helpers/ResourceTokenUtils.ts
Normal file
43
src/Platform/Hosted/Helpers/ResourceTokenUtils.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
export interface ParsedResourceTokenConnectionString {
|
||||
accountEndpoint: string;
|
||||
collectionId: string;
|
||||
databaseId: string;
|
||||
partitionKey?: string;
|
||||
resourceToken: string;
|
||||
}
|
||||
|
||||
export function parseResourceTokenConnectionString(connectionString: string): ParsedResourceTokenConnectionString {
|
||||
let accountEndpoint: string;
|
||||
let collectionId: string;
|
||||
let databaseId: string;
|
||||
let partitionKey: string;
|
||||
let resourceToken: string;
|
||||
const connectionStringParts = connectionString.split(";");
|
||||
connectionStringParts.forEach((part: string) => {
|
||||
if (part.startsWith("type=resource")) {
|
||||
resourceToken = part + ";";
|
||||
} else if (part.startsWith("AccountEndpoint=")) {
|
||||
accountEndpoint = part.substring(16);
|
||||
} else if (part.startsWith("DatabaseId=")) {
|
||||
databaseId = part.substring(11);
|
||||
} else if (part.startsWith("CollectionId=")) {
|
||||
collectionId = part.substring(13);
|
||||
} else if (part.startsWith("PartitionKey=")) {
|
||||
partitionKey = part.substring(13);
|
||||
} else if (part !== "") {
|
||||
resourceToken += part + ";";
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
accountEndpoint,
|
||||
collectionId,
|
||||
databaseId,
|
||||
partitionKey,
|
||||
resourceToken
|
||||
};
|
||||
}
|
||||
|
||||
export function isResourceTokenConnectionString(connectionString: string): boolean {
|
||||
return connectionString && connectionString.includes("type=resource");
|
||||
}
|
||||
Reference in New Issue
Block a user