Refactor DocumentClientUtilityBase to not be a class (#115)
This commit is contained in:
parent
6d142f16f9
commit
2e49ed45c3
|
@ -52,6 +52,7 @@ jobs:
|
|||
- run: npm run test
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [lint, format, compile, unittest]
|
||||
name: "Build"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -75,6 +76,7 @@ jobs:
|
|||
path: dist/
|
||||
endtoendemulator:
|
||||
name: "End To End Tests | Emulator | SQL"
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -101,6 +103,7 @@ jobs:
|
|||
CYPRESS_CACHE_FOLDER: ~/.cache/Cypress
|
||||
endtoendsql:
|
||||
name: "End To End Tests | SQL"
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -129,6 +132,7 @@ jobs:
|
|||
CYPRESS_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_SQL }}
|
||||
endtoendmongo:
|
||||
name: "End To End Tests | Mongo"
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -157,6 +161,7 @@ jobs:
|
|||
CYPRESS_CONNECTION_STRING: ${{ secrets.CONNECTION_STRING_MONGO }}
|
||||
accessibility:
|
||||
name: "Accessibility | Hosted"
|
||||
needs: [lint, format, compile, unittest]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
|
|
@ -39,10 +39,10 @@ module.exports = {
|
|||
// An object that configures minimum threshold enforcement for coverage results
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 18,
|
||||
functions: 22,
|
||||
lines: 28,
|
||||
statements: 27
|
||||
branches: 19.5,
|
||||
functions: 24,
|
||||
lines: 29.5,
|
||||
statements: 28.5
|
||||
}
|
||||
},
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,6 +11,13 @@ import * as Logger from "./Logger";
|
|||
import { NotificationConsoleUtils } from "../Utils/NotificationConsoleUtils";
|
||||
import { QueryUtils } from "../Utils/QueryUtils";
|
||||
import Explorer from "../Explorer/Explorer";
|
||||
import {
|
||||
getOrCreateDatabaseAndCollection,
|
||||
createDocument,
|
||||
queryDocuments,
|
||||
queryDocumentsPage,
|
||||
deleteDocument
|
||||
} from "./DocumentClientUtilityBase";
|
||||
|
||||
export class QueriesClient implements ViewModels.QueriesClient {
|
||||
private static readonly PartitionKey: DataModels.PartitionKey = {
|
||||
|
@ -33,14 +40,13 @@ export class QueriesClient implements ViewModels.QueriesClient {
|
|||
ConsoleDataType.InProgress,
|
||||
"Setting up account for saving queries"
|
||||
);
|
||||
return this.container.documentClientUtility
|
||||
.getOrCreateDatabaseAndCollection({
|
||||
collectionId: SavedQueries.CollectionName,
|
||||
databaseId: SavedQueries.DatabaseName,
|
||||
partitionKey: QueriesClient.PartitionKey,
|
||||
offerThroughput: SavedQueries.OfferThroughput,
|
||||
databaseLevelThroughput: undefined
|
||||
})
|
||||
return getOrCreateDatabaseAndCollection({
|
||||
collectionId: SavedQueries.CollectionName,
|
||||
databaseId: SavedQueries.DatabaseName,
|
||||
partitionKey: QueriesClient.PartitionKey,
|
||||
offerThroughput: SavedQueries.OfferThroughput,
|
||||
databaseLevelThroughput: undefined
|
||||
})
|
||||
.then(
|
||||
(collection: DataModels.Collection) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
|
@ -89,8 +95,7 @@ export class QueriesClient implements ViewModels.QueriesClient {
|
|||
`Saving query ${query.queryName}`
|
||||
);
|
||||
query.id = query.queryName;
|
||||
return this.container.documentClientUtility
|
||||
.createDocument(queriesCollection, query)
|
||||
return createDocument(queriesCollection, query)
|
||||
.then(
|
||||
(savedQuery: DataModels.Query) => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
|
@ -131,17 +136,11 @@ export class QueriesClient implements ViewModels.QueriesClient {
|
|||
|
||||
const options: any = { enableCrossPartitionQuery: true };
|
||||
const id = NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.InProgress, "Fetching saved queries");
|
||||
return this.container.documentClientUtility
|
||||
.queryDocuments(SavedQueries.DatabaseName, SavedQueries.CollectionName, this.fetchQueriesQuery(), options)
|
||||
return queryDocuments(SavedQueries.DatabaseName, SavedQueries.CollectionName, this.fetchQueriesQuery(), options)
|
||||
.then(
|
||||
(queryIterator: QueryIterator<ItemDefinition & Resource>) => {
|
||||
const fetchQueries = (firstItemIndex: number): Q.Promise<ViewModels.QueryResults> =>
|
||||
this.container.documentClientUtility.queryDocumentsPage(
|
||||
queriesCollection.id(),
|
||||
queryIterator,
|
||||
firstItemIndex,
|
||||
options
|
||||
);
|
||||
queryDocumentsPage(queriesCollection.id(), queryIterator, firstItemIndex, options);
|
||||
return QueryUtils.queryAllPages(fetchQueries).then(
|
||||
(results: ViewModels.QueryResults) => {
|
||||
let queries: DataModels.Query[] = _.map(results.documents, (document: DataModels.Query) => {
|
||||
|
@ -226,8 +225,7 @@ export class QueriesClient implements ViewModels.QueriesClient {
|
|||
query.queryName
|
||||
); // TODO: Remove DocumentId's dependency on DocumentsTab
|
||||
const options: any = { partitionKey: query.resourceId };
|
||||
return this.container.documentClientUtility
|
||||
.deleteDocument(queriesCollection, documentId)
|
||||
return deleteDocument(queriesCollection, documentId)
|
||||
.then(
|
||||
() => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import * as DataModels from "./DataModels";
|
||||
import * as monaco from "monaco-editor";
|
||||
import DocumentClientUtilityBase from "../Common/DocumentClientUtilityBase";
|
||||
import Q from "q";
|
||||
import { AccessibleVerticalList } from "../Explorer/Tree/AccessibleVerticalList";
|
||||
import { CassandraTableKey, CassandraTableKeys } from "../Explorer/Tables/TableDataClient";
|
||||
|
@ -18,7 +17,6 @@ import ConflictsTab from "../Explorer/Tabs/ConflictsTab";
|
|||
import Trigger from "../Explorer/Tree/Trigger";
|
||||
|
||||
export interface ExplorerOptions {
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
notificationsClient: NotificationsClient;
|
||||
isEmulator: boolean;
|
||||
}
|
||||
|
@ -245,13 +243,11 @@ export interface ConflictId {
|
|||
*/
|
||||
export interface PaneOptions {
|
||||
id: string;
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
visible: ko.Observable<boolean>;
|
||||
container?: Explorer;
|
||||
}
|
||||
|
||||
export interface ContextualPane {
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
formErrors: ko.Observable<string>;
|
||||
formErrorsDetails: ko.Observable<string>;
|
||||
id: string;
|
||||
|
@ -406,7 +402,6 @@ export interface TabOptions {
|
|||
tabKind: CollectionTabKind;
|
||||
title: string;
|
||||
tabPath: string;
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
selfLink: string;
|
||||
isActive: ko.Observable<boolean>;
|
||||
hashLocation: string;
|
||||
|
@ -493,11 +488,9 @@ export interface ScriptTabOption extends TabOptions {
|
|||
|
||||
// Tabs
|
||||
export interface Tab {
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
node: TreeNode; // Can be null
|
||||
collection: CollectionBase;
|
||||
rid: string;
|
||||
|
||||
tabKind: CollectionTabKind;
|
||||
tabId: string;
|
||||
isActive: ko.Observable<boolean>;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
jest.mock("../../Common/DocumentClientUtilityBase");
|
||||
import * as ko from "knockout";
|
||||
import * as sinon from "sinon";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Q from "q";
|
||||
import { ContainerSampleGenerator } from "./ContainerSampleGenerator";
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import * as DocumentClientUtility from "../../Common/DocumentClientUtilityBase";
|
||||
import { GremlinClient } from "../Graph/GraphExplorerComponent/GremlinClient";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
|
@ -62,19 +63,12 @@ describe("ContainerSampleGenerator", () => {
|
|||
|
||||
const explorerStub = createExplorerStub(database);
|
||||
explorerStub.isPreferredApiDocumentDB = ko.computed<boolean>(() => true);
|
||||
|
||||
const fakeDocumentClientUtility = sinon.createStubInstance(DocumentClientUtilityBase);
|
||||
fakeDocumentClientUtility.getOrCreateDatabaseAndCollection.returns(Q.resolve(collection));
|
||||
fakeDocumentClientUtility.createDocument.returns(Q.resolve());
|
||||
|
||||
explorerStub.documentClientUtility = fakeDocumentClientUtility;
|
||||
|
||||
const generator = await ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub);
|
||||
generator.setData(sampleData);
|
||||
|
||||
await generator.createSampleContainerAsync();
|
||||
|
||||
expect(fakeDocumentClientUtility.createDocument.called).toBe(true);
|
||||
expect(DocumentClientUtility.createDocument).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should send gremlin queries for Graph API account", async () => {
|
||||
|
@ -109,18 +103,12 @@ describe("ContainerSampleGenerator", () => {
|
|||
const explorerStub = createExplorerStub(database);
|
||||
explorerStub.isPreferredApiGraph = ko.computed<boolean>(() => true);
|
||||
|
||||
const fakeDocumentClientUtility = sinon.createStubInstance(DocumentClientUtilityBase);
|
||||
fakeDocumentClientUtility.getOrCreateDatabaseAndCollection.returns(Q.resolve(collection));
|
||||
fakeDocumentClientUtility.createDocument.returns(Q.resolve());
|
||||
|
||||
explorerStub.documentClientUtility = fakeDocumentClientUtility;
|
||||
|
||||
const generator = await ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub);
|
||||
generator.setData(sampleData);
|
||||
|
||||
await generator.createSampleContainerAsync();
|
||||
|
||||
expect(fakeDocumentClientUtility.createDocument.called).toBe(false);
|
||||
expect(DocumentClientUtility.createDocument).toHaveBeenCalled();
|
||||
expect(executeStub.called).toBe(true);
|
||||
});
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import { CosmosClient } from "../../Common/CosmosClient";
|
|||
import { GremlinClient } from "../Graph/GraphExplorerComponent/GremlinClient";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../Explorer";
|
||||
import { createDocument, getOrCreateDatabaseAndCollection } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
interface SampleDataFile extends DataModels.CreateDatabaseAndCollectionRequest {
|
||||
data: any[];
|
||||
|
@ -64,7 +65,7 @@ export class ContainerSampleGenerator {
|
|||
options.initialHeaders[Constants.HttpHeaders.usePolygonsSmallerThanAHemisphere] = true;
|
||||
}
|
||||
|
||||
await this.container.documentClientUtility.getOrCreateDatabaseAndCollection(createRequest, options);
|
||||
await getOrCreateDatabaseAndCollection(createRequest, options);
|
||||
await this.container.refreshAllDatabases();
|
||||
const database = this.container.findDatabaseWithId(this.sampleDataFile.databaseId);
|
||||
if (!database) {
|
||||
|
@ -103,7 +104,7 @@ export class ContainerSampleGenerator {
|
|||
} else {
|
||||
// For SQL all queries are executed at the same time
|
||||
this.sampleDataFile.data.forEach(doc => {
|
||||
const subPromise = this.container.documentClientUtility.createDocument(collection, doc);
|
||||
const subPromise = createDocument(collection, doc);
|
||||
subPromise.catch(reason => NotificationConsoleUtils.logConsoleMessage(ConsoleDataType.Error, reason));
|
||||
promises.push(subPromise);
|
||||
});
|
||||
|
|
|
@ -15,7 +15,7 @@ import CassandraAddCollectionPane from "./Panes/CassandraAddCollectionPane";
|
|||
import Database from "./Tree/Database";
|
||||
import DeleteCollectionConfirmationPane from "./Panes/DeleteCollectionConfirmationPane";
|
||||
import DeleteDatabaseConfirmationPane from "./Panes/DeleteDatabaseConfirmationPane";
|
||||
import DocumentClientUtilityBase from "../Common/DocumentClientUtilityBase";
|
||||
import { readDatabases, readCollection, readOffers, refreshCachedResources } from "../Common/DocumentClientUtilityBase";
|
||||
import EditTableEntityPane from "./Panes/Tables/EditTableEntityPane";
|
||||
import EnvironmentUtility from "../Common/EnvironmentUtility";
|
||||
import GraphStylingPane from "./Panes/GraphStylingPane";
|
||||
|
@ -127,7 +127,6 @@ export default class Explorer {
|
|||
public extensionEndpoint: ko.Observable<string>;
|
||||
public armEndpoint: ko.Observable<string>;
|
||||
public isTryCosmosDBSubscription: ko.Observable<boolean>;
|
||||
public documentClientUtility: DocumentClientUtilityBase;
|
||||
public notificationsClient: ViewModels.NotificationsClient;
|
||||
public queriesClient: ViewModels.QueriesClient;
|
||||
public tableDataClient: TableDataClient;
|
||||
|
@ -358,7 +357,6 @@ export default class Explorer {
|
|||
}
|
||||
});
|
||||
this.memoryUsageInfo = ko.observable<DataModels.MemoryUsageInfo>();
|
||||
this.documentClientUtility = options.documentClientUtility;
|
||||
this.notificationsClient = options.notificationsClient;
|
||||
this.isEmulator = options.isEmulator;
|
||||
|
||||
|
@ -584,7 +582,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.addDatabasePane = new AddDatabasePane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "adddatabasepane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -593,7 +590,6 @@ export default class Explorer {
|
|||
|
||||
this.addCollectionPane = new AddCollectionPane({
|
||||
isPreferredApiTable: ko.computed(() => this.isPreferredApiTable()),
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "addcollectionpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -601,7 +597,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.deleteCollectionConfirmationPane = new DeleteCollectionConfirmationPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "deletecollectionconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -609,7 +604,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.deleteDatabaseConfirmationPane = new DeleteDatabaseConfirmationPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "deletedatabaseconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -617,7 +611,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.graphStylingPane = new GraphStylingPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "graphstylingpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -625,7 +618,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.addTableEntityPane = new AddTableEntityPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "addtableentitypane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -633,7 +625,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.editTableEntityPane = new EditTableEntityPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "edittableentitypane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -641,7 +632,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.tableColumnOptionsPane = new TableColumnOptionsPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "tablecolumnoptionspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -649,7 +639,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.querySelectPane = new QuerySelectPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "queryselectpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -657,7 +646,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.newVertexPane = new NewVertexPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "newvertexpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -665,7 +653,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.cassandraAddCollectionPane = new CassandraAddCollectionPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "cassandraaddcollectionpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -673,7 +660,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.settingsPane = new SettingsPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "settingspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -681,7 +667,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.executeSprocParamsPane = new ExecuteSprocParamsPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "executesprocparamspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -689,7 +674,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.renewAdHocAccessPane = new RenewAdHocAccessPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "renewadhocaccesspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -697,7 +681,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.uploadItemsPane = new UploadItemsPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "uploaditemspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -707,7 +690,6 @@ export default class Explorer {
|
|||
this.uploadItemsPaneAdapter = new UploadItemsPaneAdapter(this);
|
||||
|
||||
this.loadQueryPane = new LoadQueryPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "loadquerypane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -715,7 +697,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.saveQueryPane = new SaveQueryPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "savequerypane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -723,7 +704,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.browseQueriesPane = new BrowseQueriesPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "browsequeriespane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -731,7 +711,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.uploadFilePane = new UploadFilePane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "uploadfilepane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -739,7 +718,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.stringInputPane = new StringInputPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "stringinputpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -747,7 +725,6 @@ export default class Explorer {
|
|||
});
|
||||
|
||||
this.setupNotebooksPane = new SetupNotebooksPane({
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
id: "setupnotebookspane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
|
||||
|
@ -780,7 +757,6 @@ export default class Explorer {
|
|||
this.setupNotebooksPane
|
||||
];
|
||||
this.addDatabaseText.subscribe((addDatabaseText: string) => this.addDatabasePane.title(addDatabaseText));
|
||||
this.rebindDocumentClientUtility.bind(this);
|
||||
this.isTabsContentExpanded = ko.observable(false);
|
||||
|
||||
document.addEventListener(
|
||||
|
@ -862,7 +838,7 @@ export default class Explorer {
|
|||
this.editTableEntityPane.title("Edit Table Entity");
|
||||
this.deleteCollectionConfirmationPane.title("Delete Table");
|
||||
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the table id");
|
||||
this.tableDataClient = new TablesAPIDataClient(this.documentClientUtility);
|
||||
this.tableDataClient = new TablesAPIDataClient();
|
||||
break;
|
||||
case Constants.DefaultAccountExperience.Cassandra.toLowerCase():
|
||||
this.addCollectionText("New Table");
|
||||
|
@ -881,7 +857,7 @@ export default class Explorer {
|
|||
this.deleteCollectionConfirmationPane.collectionIdConfirmationText("Confirm by typing the table id");
|
||||
this.deleteDatabaseConfirmationPane.title("Delete Keyspace");
|
||||
this.deleteDatabaseConfirmationPane.databaseIdConfirmationText("Confirm by typing the keyspace id");
|
||||
this.tableDataClient = new CassandraAPIDataClient(this.documentClientUtility);
|
||||
this.tableDataClient = new CassandraAPIDataClient();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
@ -1066,13 +1042,6 @@ export default class Explorer {
|
|||
// TODO: return result
|
||||
}
|
||||
|
||||
public rebindDocumentClientUtility(documentClientUtility: DocumentClientUtilityBase): void {
|
||||
this.documentClientUtility = documentClientUtility;
|
||||
this._panes.forEach((pane: ViewModels.ContextualPane) => {
|
||||
pane.documentClientUtility = documentClientUtility;
|
||||
});
|
||||
}
|
||||
|
||||
public copyUrlLink(src: any, event: MouseEvent): void {
|
||||
const urlLinkInput: HTMLInputElement = document.getElementById("shareUrlLink") as HTMLInputElement;
|
||||
urlLinkInput && urlLinkInput.select();
|
||||
|
@ -1391,7 +1360,7 @@ export default class Explorer {
|
|||
}
|
||||
|
||||
const deferred: Q.Deferred<void> = Q.defer();
|
||||
this.documentClientUtility.readCollection(databaseId, collectionId).then((collection: DataModels.Collection) => {
|
||||
readCollection(databaseId, collectionId).then((collection: DataModels.Collection) => {
|
||||
this.resourceTokenCollection(new ResourceTokenCollection(this, databaseId, collection));
|
||||
this.selectedNode(this.resourceTokenCollection());
|
||||
deferred.resolve();
|
||||
|
@ -1421,7 +1390,7 @@ export default class Explorer {
|
|||
|
||||
const refreshDatabases = (offers?: DataModels.Offer[]) => {
|
||||
this._setLoadingStatusText("Fetching databases...");
|
||||
this.documentClientUtility.readDatabases(null /*options*/).then(
|
||||
readDatabases(null /*options*/).then(
|
||||
(databases: DataModels.Database[]) => {
|
||||
this._setLoadingStatusText("Successfully fetched databases.");
|
||||
TelemetryProcessor.traceSuccess(
|
||||
|
@ -1478,7 +1447,7 @@ export default class Explorer {
|
|||
// Serverless accounts don't support offers call
|
||||
refreshDatabases();
|
||||
} else {
|
||||
const offerPromise: Q.Promise<DataModels.Offer[]> = this.documentClientUtility.readOffers();
|
||||
const offerPromise: Q.Promise<DataModels.Offer[]> = readOffers();
|
||||
this._setLoadingStatusText("Fetching offers...");
|
||||
offerPromise.then(
|
||||
(offers: DataModels.Offer[]) => {
|
||||
|
@ -1554,7 +1523,7 @@ export default class Explorer {
|
|||
dataExplorerArea: Constants.Areas.ResourceTree
|
||||
});
|
||||
this.isRefreshingExplorer(true);
|
||||
this.documentClientUtility.refreshCachedResources().then(
|
||||
refreshCachedResources().then(
|
||||
() => {
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadDatabases,
|
||||
|
@ -2480,8 +2449,6 @@ export default class Explorer {
|
|||
node: null,
|
||||
title: notebookContentItem.name,
|
||||
tabPath: notebookContentItem.path,
|
||||
documentClientUtility: null,
|
||||
|
||||
collection: null,
|
||||
selfLink: null,
|
||||
masterKey: CosmosClient.masterKey() || "",
|
||||
|
@ -2923,8 +2890,6 @@ export default class Explorer {
|
|||
node: null,
|
||||
title: title,
|
||||
tabPath: title,
|
||||
documentClientUtility: null,
|
||||
|
||||
collection: null,
|
||||
selfLink: null,
|
||||
hashLocation: hashLocation,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
jest.mock("../../../Common/DocumentClientUtilityBase");
|
||||
import React from "react";
|
||||
import * as sinon from "sinon";
|
||||
import { mount, ReactWrapper } from "enzyme";
|
||||
|
@ -7,11 +8,11 @@ import { GraphExplorer, GraphExplorerProps, GraphAccessor, GraphHighlightedNodeD
|
|||
import * as D3ForceGraph from "./D3ForceGraph";
|
||||
import { GraphData } from "./GraphData";
|
||||
import { TabComponent } from "../../Controls/Tabs/TabComponent";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import * as DataModels from "../../../Contracts/DataModels";
|
||||
import * as StorageUtility from "../../../Shared/StorageUtility";
|
||||
import GraphTab from "../../Tabs/GraphTab";
|
||||
import { ConsoleDataType } from "../../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { queryDocuments, queryDocumentsPage } from "../../../Common/DocumentClientUtilityBase";
|
||||
|
||||
describe("Check whether query result is vertex array", () => {
|
||||
it("should reject null as vertex array", () => {
|
||||
|
@ -134,7 +135,7 @@ describe("GraphExplorer", () => {
|
|||
const COLLECTION_SELF_LINK = "collectionSelfLink";
|
||||
const gremlinRU = 789.12;
|
||||
|
||||
const createMockProps = (documentClientUtility?: any): GraphExplorerProps => {
|
||||
const createMockProps = (): GraphExplorerProps => {
|
||||
const graphConfig = GraphTab.createGraphConfig();
|
||||
const graphConfigUi = GraphTab.createGraphConfigUiData(graphConfig);
|
||||
|
||||
|
@ -149,7 +150,6 @@ describe("GraphExplorer", () => {
|
|||
onIsValidQueryChange: (isValidQuery: boolean): void => {},
|
||||
|
||||
collectionPartitionKeyProperty: "collectionPartitionKeyProperty",
|
||||
documentClientUtility: documentClientUtility,
|
||||
collectionRid: COLLECTION_RID,
|
||||
collectionSelfLink: COLLECTION_SELF_LINK,
|
||||
graphBackendEndpoint: "graphBackendEndpoint",
|
||||
|
@ -188,7 +188,6 @@ describe("GraphExplorer", () => {
|
|||
let wrapper: ReactWrapper;
|
||||
|
||||
let connectStub: sinon.SinonSpy;
|
||||
let queryDocStub: sinon.SinonSpy;
|
||||
let submitToBackendSpy: sinon.SinonSpy;
|
||||
let renderResultAsJsonStub: sinon.SinonSpy;
|
||||
let onMiddlePaneInitializedStub: sinon.SinonSpy;
|
||||
|
@ -215,46 +214,6 @@ describe("GraphExplorer", () => {
|
|||
[query: string]: AjaxResponse;
|
||||
}
|
||||
|
||||
const createDocumentClientUtilityMock = (docDBResponse: AjaxResponse) => {
|
||||
const mock = {
|
||||
queryDocuments: () => {},
|
||||
queryDocumentsPage: (
|
||||
rid: string,
|
||||
iterator: any,
|
||||
firstItemIndex: number,
|
||||
options: any
|
||||
): Q.Promise<ViewModels.QueryResults> => {
|
||||
const qresult = {
|
||||
hasMoreResults: false,
|
||||
firstItemIndex: firstItemIndex,
|
||||
lastItemIndex: 0,
|
||||
itemCount: 0,
|
||||
documents: docDBResponse.response,
|
||||
activityId: "",
|
||||
headers: [] as any[],
|
||||
requestCharge: gVRU
|
||||
};
|
||||
|
||||
return Q.resolve(qresult);
|
||||
}
|
||||
};
|
||||
|
||||
const fakeIterator: any = {
|
||||
nextItem: (callback: (error: any, document: DataModels.DocumentId) => void): void => {},
|
||||
hasMoreResults: () => false,
|
||||
executeNext: (callback: (error: any, documents: DataModels.DocumentId[], headers: any) => void): void => {}
|
||||
};
|
||||
|
||||
queryDocStub = sinon.stub(mock, "queryDocuments").callsFake(
|
||||
(container: ViewModels.DocumentRequestContainer, query: string, options: any): Q.Promise<any> => {
|
||||
(fakeIterator as any)._query = query;
|
||||
return Q.resolve(fakeIterator);
|
||||
}
|
||||
);
|
||||
|
||||
return mock;
|
||||
};
|
||||
|
||||
const setupMocks = (
|
||||
graphExplorer: GraphExplorer,
|
||||
backendResponses: BackendResponses,
|
||||
|
@ -333,7 +292,29 @@ describe("GraphExplorer", () => {
|
|||
done: any,
|
||||
ignoreD3Update: boolean
|
||||
): GraphExplorer => {
|
||||
const props: GraphExplorerProps = createMockProps(createDocumentClientUtilityMock(docDBResponse));
|
||||
(queryDocuments as jest.Mock).mockImplementation((container: any, query: string, options: any) => {
|
||||
return Q.resolve({
|
||||
_query: query,
|
||||
nextItem: (callback: (error: any, document: DataModels.DocumentId) => void): void => {},
|
||||
hasMoreResults: () => false,
|
||||
executeNext: (callback: (error: any, documents: DataModels.DocumentId[], headers: any) => void): void => {}
|
||||
});
|
||||
});
|
||||
(queryDocumentsPage as jest.Mock).mockImplementation(
|
||||
(rid: string, iterator: any, firstItemIndex: number, options: any) => {
|
||||
return Q.resolve({
|
||||
hasMoreResults: false,
|
||||
firstItemIndex: firstItemIndex,
|
||||
lastItemIndex: 0,
|
||||
itemCount: 0,
|
||||
documents: docDBResponse.response,
|
||||
activityId: "",
|
||||
headers: [] as any[],
|
||||
requestCharge: gVRU
|
||||
});
|
||||
}
|
||||
);
|
||||
const props: GraphExplorerProps = createMockProps();
|
||||
wrapper = mount(<GraphExplorer {...props} />);
|
||||
graphExplorerInstance = wrapper.instance() as GraphExplorer;
|
||||
setupMocks(graphExplorerInstance, backendResponses, done, ignoreD3Update);
|
||||
|
@ -341,7 +322,7 @@ describe("GraphExplorer", () => {
|
|||
};
|
||||
|
||||
const cleanUpStubsWrapper = () => {
|
||||
queryDocStub.restore();
|
||||
jest.resetAllMocks();
|
||||
connectStub.restore();
|
||||
submitToBackendSpy.restore();
|
||||
renderResultAsJsonStub.restore();
|
||||
|
@ -378,22 +359,11 @@ describe("GraphExplorer", () => {
|
|||
expect((graphExplorerInstance.submitToBackend as sinon.SinonSpy).calledWith("g.V()")).toBe(false);
|
||||
});
|
||||
|
||||
it("should submit g.V() as docdb query with proper query", () => {
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[2]
|
||||
).toBe(DOCDB_G_DOT_V_QUERY);
|
||||
});
|
||||
|
||||
it("should submit g.V() as docdb query with proper parameters", () => {
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[0]
|
||||
).toEqual("databaseId");
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[1]
|
||||
).toEqual("collectionId");
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[3]
|
||||
).toEqual({ maxItemCount: GraphExplorer.ROOT_LIST_PAGE_SIZE, enableCrossPartitionQuery: true });
|
||||
expect(queryDocuments).toBeCalledWith("databaseId", "collectionId", DOCDB_G_DOT_V_QUERY, {
|
||||
maxItemCount: GraphExplorer.ROOT_LIST_PAGE_SIZE,
|
||||
enableCrossPartitionQuery: true
|
||||
});
|
||||
});
|
||||
|
||||
it("should call backend thrice (user query, fetch outE, then fetch inE)", () => {
|
||||
|
@ -426,22 +396,11 @@ describe("GraphExplorer", () => {
|
|||
expect((graphExplorerInstance.submitToBackend as sinon.SinonSpy).calledWith("g.V()")).toBe(false);
|
||||
});
|
||||
|
||||
it("should submit g.V() as docdb query with proper query", () => {
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[2]
|
||||
).toBe(DOCDB_G_DOT_V_QUERY);
|
||||
});
|
||||
|
||||
it("should submit g.V() as docdb query with proper parameters", () => {
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[0]
|
||||
).toEqual("databaseId");
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[1]
|
||||
).toEqual("collectionId");
|
||||
expect(
|
||||
(graphExplorerInstance.props.documentClientUtility.queryDocuments as sinon.SinonSpy).getCall(0).args[3]
|
||||
).toEqual({ maxItemCount: GraphExplorer.ROOT_LIST_PAGE_SIZE, enableCrossPartitionQuery: true });
|
||||
expect(queryDocuments).toBeCalledWith("databaseId", "collectionId", DOCDB_G_DOT_V_QUERY, {
|
||||
maxItemCount: GraphExplorer.ROOT_LIST_PAGE_SIZE,
|
||||
enableCrossPartitionQuery: true
|
||||
});
|
||||
});
|
||||
|
||||
it("should call backend thrice (user query, fetch outE, then fetch inE)", () => {
|
||||
|
|
|
@ -28,7 +28,7 @@ import * as Constants from "../../../Common/Constants";
|
|||
import { InputProperty } from "../../../Contracts/ViewModels";
|
||||
import { QueryIterator, ItemDefinition, Resource } from "@azure/cosmos";
|
||||
import LoadingIndicatorIcon from "../../../../images/LoadingIndicator_3Squares.gif";
|
||||
import DocumentClientUtilityBase from "../../../Common/DocumentClientUtilityBase";
|
||||
import { queryDocuments, queryDocumentsPage } from "../../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export interface GraphAccessor {
|
||||
applyFilter: () => void;
|
||||
|
@ -47,7 +47,6 @@ export interface GraphExplorerProps {
|
|||
onIsValidQueryChange: (isValidQuery: boolean) => void;
|
||||
|
||||
collectionPartitionKeyProperty: string;
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
collectionRid: string;
|
||||
collectionSelfLink: string;
|
||||
graphBackendEndpoint: string;
|
||||
|
@ -697,7 +696,6 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||
* @param cmd
|
||||
*/
|
||||
public submitToBackend(cmd: string): Q.Promise<GremlinClient.GremlinRequestResult> {
|
||||
console.log("submit:", cmd);
|
||||
const id = GraphExplorer.reportToConsole(ConsoleDataType.InProgress, `Executing: ${cmd}`);
|
||||
this.setExecuteCounter(this.executeCounter + 1);
|
||||
|
||||
|
@ -730,26 +728,24 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||
*/
|
||||
public executeNonPagedDocDbQuery(query: string): Q.Promise<DataModels.DocumentId[]> {
|
||||
// TODO maxItemCount: this reduces throttling, but won't cap the # of results
|
||||
return this.props.documentClientUtility
|
||||
.queryDocuments(this.props.databaseId, this.props.collectionId, query, {
|
||||
maxItemCount: GraphExplorer.PAGE_ALL,
|
||||
enableCrossPartitionQuery:
|
||||
StorageUtility.LocalStorageUtility.getEntryString(StorageUtility.StorageKey.IsCrossPartitionQueryEnabled) ===
|
||||
"true"
|
||||
})
|
||||
.then(
|
||||
(iterator: QueryIterator<ItemDefinition & Resource>) => {
|
||||
return iterator.fetchNext().then(response => response.resources);
|
||||
},
|
||||
(reason: any) => {
|
||||
GraphExplorer.reportToConsole(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to execute non-paged query ${query}. Reason:${reason}`,
|
||||
reason
|
||||
);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
return queryDocuments(this.props.databaseId, this.props.collectionId, query, {
|
||||
maxItemCount: GraphExplorer.PAGE_ALL,
|
||||
enableCrossPartitionQuery:
|
||||
StorageUtility.LocalStorageUtility.getEntryString(StorageUtility.StorageKey.IsCrossPartitionQueryEnabled) ===
|
||||
"true"
|
||||
}).then(
|
||||
(iterator: QueryIterator<ItemDefinition & Resource>) => {
|
||||
return iterator.fetchNext().then(response => response.resources);
|
||||
},
|
||||
(reason: any) => {
|
||||
GraphExplorer.reportToConsole(
|
||||
ConsoleDataType.Error,
|
||||
`Failed to execute non-paged query ${query}. Reason:${reason}`,
|
||||
reason
|
||||
);
|
||||
return null;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1732,12 +1728,10 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||
query = `select root.id, root.${this.props.collectionPartitionKeyProperty} from root where IS_DEFINED(root._isEdge) = false order by root._ts asc`;
|
||||
}
|
||||
|
||||
return this.props.documentClientUtility
|
||||
.queryDocuments(this.props.databaseId, this.props.collectionId, query, {
|
||||
maxItemCount: GraphExplorer.ROOT_LIST_PAGE_SIZE,
|
||||
enableCrossPartitionQuery:
|
||||
LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true"
|
||||
})
|
||||
return queryDocuments(this.props.databaseId, this.props.collectionId, query, {
|
||||
maxItemCount: GraphExplorer.ROOT_LIST_PAGE_SIZE,
|
||||
enableCrossPartitionQuery: LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true"
|
||||
})
|
||||
.then(
|
||||
(iterator: QueryIterator<ItemDefinition & Resource>) => {
|
||||
this.currentDocDBQueryInfo = {
|
||||
|
@ -1766,16 +1760,15 @@ export class GraphExplorer extends React.Component<GraphExplorerProps, GraphExpl
|
|||
.currentDocDBQueryInfo.index + GraphExplorer.ROOT_LIST_PAGE_SIZE})`;
|
||||
const id = GraphExplorer.reportToConsole(ConsoleDataType.InProgress, `Executing: ${queryInfoStr}`);
|
||||
|
||||
return this.props.documentClientUtility
|
||||
.queryDocumentsPage(
|
||||
this.props.collectionRid,
|
||||
this.currentDocDBQueryInfo.iterator,
|
||||
this.currentDocDBQueryInfo.index,
|
||||
{
|
||||
enableCrossPartitionQuery:
|
||||
LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true"
|
||||
}
|
||||
)
|
||||
return queryDocumentsPage(
|
||||
this.props.collectionRid,
|
||||
this.currentDocDBQueryInfo.iterator,
|
||||
this.currentDocDBQueryInfo.index,
|
||||
{
|
||||
enableCrossPartitionQuery:
|
||||
LocalStorageUtility.getEntryString(StorageKey.IsCrossPartitionQueryEnabled) === "true"
|
||||
}
|
||||
)
|
||||
.then((results: ViewModels.QueryResults) => {
|
||||
GraphExplorer.clearConsoleProgress(id);
|
||||
this.currentDocDBQueryInfo.index = results.lastItemIndex + 1;
|
||||
|
|
|
@ -3,7 +3,6 @@ import { ReactAdapter } from "../../../Bindings/ReactBindingHandler";
|
|||
import { GraphConfig } from "../../Tabs/GraphTab";
|
||||
import * as ViewModels from "../../../Contracts/ViewModels";
|
||||
import { GraphExplorer, GraphAccessor } from "./GraphExplorer";
|
||||
import DocumentClientUtilityBase from "../../../Common/DocumentClientUtilityBase";
|
||||
|
||||
interface Parameter {
|
||||
onIsNewVertexDisabledChange: (isEnabled: boolean) => void;
|
||||
|
@ -18,7 +17,6 @@ interface Parameter {
|
|||
graphConfig?: GraphConfig;
|
||||
|
||||
collectionPartitionKeyProperty: string;
|
||||
documentClientUtility: DocumentClientUtilityBase;
|
||||
collectionRid: string;
|
||||
collectionSelfLink: string;
|
||||
graphBackendEndpoint: string;
|
||||
|
@ -51,7 +49,6 @@ export class GraphExplorerAdapter implements ReactAdapter {
|
|||
onIsGraphDisplayed={this.params.onIsGraphDisplayed}
|
||||
onResetDefaultGraphConfigValues={this.params.onResetDefaultGraphConfigValues}
|
||||
collectionPartitionKeyProperty={this.params.collectionPartitionKeyProperty}
|
||||
documentClientUtility={this.params.documentClientUtility}
|
||||
collectionRid={this.params.collectionRid}
|
||||
collectionSelfLink={this.params.collectionSelfLink}
|
||||
graphBackendEndpoint={this.params.graphBackendEndpoint}
|
||||
|
|
|
@ -57,7 +57,6 @@ export default class NotebookManager {
|
|||
this.gitHubOAuthService = new GitHubOAuthService(this.junoClient);
|
||||
this.gitHubClient = new GitHubClient(this.onGitHubClientError);
|
||||
this.gitHubReposPane = new GitHubReposPane({
|
||||
documentClientUtility: this.params.container.documentClientUtility,
|
||||
id: "gitHubReposPane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
container: this.params.container,
|
||||
|
|
|
@ -41,7 +41,7 @@ describe("Add Collection Pane", () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import { createMongoCollectionWithARM, createMongoCollectionWithProxy } from "..
|
|||
import { DynamicListItem } from "../Controls/DynamicList/DynamicListComponent";
|
||||
import { HashMap } from "../../Common/HashMap";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
import { refreshCachedResources, getOrCreateDatabaseAndCollection } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class AddCollectionPane extends ContextualPaneBase {
|
||||
public defaultExperience: ko.Computed<string>;
|
||||
|
@ -941,8 +942,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
)
|
||||
);
|
||||
} else {
|
||||
createCollectionFunc = () =>
|
||||
this.container.documentClientUtility.getOrCreateDatabaseAndCollection(createRequest, options);
|
||||
createCollectionFunc = () => getOrCreateDatabaseAndCollection(createRequest, options);
|
||||
}
|
||||
|
||||
createCollectionFunc().then(
|
||||
|
@ -978,7 +978,7 @@ export default class AddCollectionPane extends ContextualPaneBase {
|
|||
};
|
||||
TelemetryProcessor.traceSuccess(Action.CreateCollection, addCollectionPaneSuccessMessage, startKey);
|
||||
this.resetData();
|
||||
return this.container.documentClientUtility.refreshCachedResources().then(() => {
|
||||
return refreshCachedResources().then(() => {
|
||||
this.container.refreshAllDatabases();
|
||||
});
|
||||
},
|
||||
|
|
|
@ -40,7 +40,6 @@ describe("Add Database Pane", () => {
|
|||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({
|
||||
documentClientUtility: null,
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@ import { CassandraAPIDataClient } from "../Tables/TableDataClient";
|
|||
import { ContextualPaneBase } from "./ContextualPaneBase";
|
||||
import { CosmosClient } from "../../Common/CosmosClient";
|
||||
import { PlatformType } from "../../PlatformType";
|
||||
import { refreshCachedOffers, refreshCachedResources, createDatabase } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class AddDatabasePane extends ContextualPaneBase {
|
||||
public defaultExperience: ko.Computed<string>;
|
||||
|
@ -334,10 +335,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
) {
|
||||
AddDbUtilities.createSqlDatabase(this.container.armEndpoint(), createDatabaseParameters, autoPilotSettings).then(
|
||||
() => {
|
||||
Promise.all([
|
||||
this.container.documentClientUtility.refreshCachedOffers(),
|
||||
this.container.documentClientUtility.refreshCachedResources()
|
||||
]).then(() => {
|
||||
Promise.all([refreshCachedOffers(), refreshCachedResources()]).then(() => {
|
||||
this._onCreateDatabaseSuccess(createDatabaseParameters.offerThroughput, startKey);
|
||||
});
|
||||
}
|
||||
|
@ -354,10 +352,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
createDatabaseParameters,
|
||||
autoPilotSettings
|
||||
).then(() => {
|
||||
Promise.all([
|
||||
this.container.documentClientUtility.refreshCachedOffers(),
|
||||
this.container.documentClientUtility.refreshCachedResources()
|
||||
]).then(() => {
|
||||
Promise.all([refreshCachedOffers(), refreshCachedResources()]).then(() => {
|
||||
this._onCreateDatabaseSuccess(createDatabaseParameters.offerThroughput, startKey);
|
||||
});
|
||||
});
|
||||
|
@ -373,10 +368,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
createDatabaseParameters,
|
||||
autoPilotSettings
|
||||
).then(() => {
|
||||
Promise.all([
|
||||
this.container.documentClientUtility.refreshCachedOffers(),
|
||||
this.container.documentClientUtility.refreshCachedResources()
|
||||
]).then(() => {
|
||||
Promise.all([refreshCachedOffers(), refreshCachedResources()]).then(() => {
|
||||
this._onCreateDatabaseSuccess(createDatabaseParameters.offerThroughput, startKey);
|
||||
});
|
||||
});
|
||||
|
@ -413,7 +405,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
autoPilot,
|
||||
hasAutoPilotV2FeatureFlag: this.hasAutoPilotV2FeatureFlag()
|
||||
};
|
||||
this.container.documentClientUtility.createDatabase(createRequest).then(
|
||||
createDatabase(createRequest).then(
|
||||
(database: DataModels.Database) => {
|
||||
this._onCreateDatabaseSuccess(offerThroughput, telemetryStartKey);
|
||||
},
|
||||
|
@ -464,10 +456,7 @@ export default class AddDatabasePane extends ContextualPaneBase {
|
|||
startKey: number
|
||||
): void {
|
||||
AddDbUtilities.createCassandraKeyspace(armEndpoint, createKeyspaceParameters, autoPilotSettings).then(() => {
|
||||
Promise.all([
|
||||
this.container.documentClientUtility.refreshCachedOffers(),
|
||||
this.container.documentClientUtility.refreshCachedResources()
|
||||
]).then(() => {
|
||||
Promise.all([refreshCachedOffers(), refreshCachedResources()]).then(() => {
|
||||
this._onCreateDatabaseSuccess(createKeyspaceParameters.offerThroughput, startKey);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,7 +5,6 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||
import { KeyCodes } from "../../Common/Constants";
|
||||
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
// TODO: Use specific actions for logging telemetry data
|
||||
|
@ -17,14 +16,12 @@ export abstract class ContextualPaneBase extends WaitsForTemplateViewModel imple
|
|||
public formErrors: ko.Observable<string>;
|
||||
public title: ko.Observable<string>;
|
||||
public visible: ko.Observable<boolean>;
|
||||
public documentClientUtility: DocumentClientUtilityBase;
|
||||
public isExecuting: ko.Observable<boolean>;
|
||||
|
||||
constructor(options: ViewModels.PaneOptions) {
|
||||
super();
|
||||
this.id = options.id;
|
||||
this.container = options.container;
|
||||
this.documentClientUtility = options.documentClientUtility;
|
||||
this.visible = options.visible || ko.observable(false);
|
||||
this.firstFieldHasFocus = ko.observable<boolean>(false);
|
||||
this.formErrors = ko.observable<string>();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
jest.mock("../../Common/DocumentClientUtilityBase");
|
||||
import * as ko from "knockout";
|
||||
import * as sinon from "sinon";
|
||||
import Q from "q";
|
||||
|
@ -6,7 +7,7 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import DeleteCollectionConfirmationPane from "./DeleteCollectionConfirmationPane";
|
||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import { deleteCollection } from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { TreeNode } from "../../Contracts/ViewModels";
|
||||
|
@ -16,7 +17,7 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be true if 1 database and 1 collection", () => {
|
||||
|
@ -55,15 +56,11 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||
|
||||
describe("shouldRecordFeedback()", () => {
|
||||
it("should return true if last collection and database does not have shared throughput else false", () => {
|
||||
let fakeDocumentClientUtility = sinon.createStubInstance<DocumentClientUtilityBase>(
|
||||
DocumentClientUtilityBase as any
|
||||
);
|
||||
let fakeExplorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
let fakeExplorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
fakeExplorer.refreshAllDatabases = () => Q.resolve();
|
||||
|
||||
let pane = new DeleteCollectionConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
id: "deletecollectionconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
container: fakeExplorer
|
||||
|
@ -96,8 +93,7 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||
|
||||
it("it should log feedback if last collection and database is not shared", () => {
|
||||
let selectedCollectionId = "testCol";
|
||||
let fakeDocumentClientUtility = {} as DocumentClientUtilityBase;
|
||||
fakeDocumentClientUtility.deleteCollection = () => Q(null);
|
||||
(deleteCollection as jest.Mock).mockResolvedValue(null);
|
||||
let fakeExplorer = {} as Explorer;
|
||||
fakeExplorer.findSelectedCollection = () => {
|
||||
return {
|
||||
|
@ -120,14 +116,12 @@ describe("Delete Collection Confirmation Pane", () => {
|
|||
return false;
|
||||
});
|
||||
|
||||
fakeExplorer.documentClientUtility = fakeDocumentClientUtility;
|
||||
fakeExplorer.selectedNode = ko.observable<TreeNode>();
|
||||
fakeExplorer.isLastCollection = () => true;
|
||||
fakeExplorer.isSelectedDatabaseShared = () => false;
|
||||
fakeExplorer.refreshAllDatabases = () => Q.resolve();
|
||||
|
||||
let pane = new DeleteCollectionConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
id: "deletecollectionconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
container: fakeExplorer as any
|
||||
|
|
|
@ -11,6 +11,7 @@ import { DefaultExperienceUtility } from "../../Shared/DefaultExperienceUtility"
|
|||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { deleteCollection } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class DeleteCollectionConfirmationPane extends ContextualPaneBase {
|
||||
public collectionIdConfirmationText: ko.Observable<string>;
|
||||
|
@ -58,7 +59,7 @@ export default class DeleteCollectionConfirmationPane extends ContextualPaneBase
|
|||
this.container
|
||||
);
|
||||
} else {
|
||||
promise = this.container.documentClientUtility.deleteCollection(selectedCollection);
|
||||
promise = deleteCollection(selectedCollection);
|
||||
}
|
||||
return promise.then(
|
||||
() => {
|
||||
|
|
|
@ -1,23 +1,28 @@
|
|||
jest.mock("../../Common/DocumentClientUtilityBase");
|
||||
jest.mock("../../Shared/Telemetry/TelemetryProcessor");
|
||||
import * as ko from "knockout";
|
||||
import * as sinon from "sinon";
|
||||
import Q from "q";
|
||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import DeleteDatabaseConfirmationPane from "./DeleteDatabaseConfirmationPane";
|
||||
import DeleteFeedback from "../../Common/DeleteFeedback";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { TreeNode } from "../../Contracts/ViewModels";
|
||||
import { TabsManager } from "../Tabs/TabsManager";
|
||||
import { deleteDatabase } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
describe("Delete Database Confirmation Pane", () => {
|
||||
describe("Explorer.isLastDatabase() and Explorer.isLastNonEmptyDatabase()", () => {
|
||||
let explorer: Explorer;
|
||||
|
||||
beforeAll(() => {
|
||||
(deleteDatabase as jest.Mock).mockResolvedValue(undefined);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be true if only 1 database", () => {
|
||||
|
@ -49,12 +54,10 @@ describe("Delete Database Confirmation Pane", () => {
|
|||
|
||||
describe("shouldRecordFeedback()", () => {
|
||||
it("should return true if last non empty database or is last database that has shared throughput, else false", () => {
|
||||
let fakeDocumentClientUtility = {} as DocumentClientUtilityBase;
|
||||
let fakeExplorer = {} as Explorer;
|
||||
fakeExplorer.isNotificationConsoleExpanded = ko.observable<boolean>(false);
|
||||
|
||||
let pane = new DeleteDatabaseConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
id: "deletedatabaseconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
container: fakeExplorer as any
|
||||
|
@ -78,20 +81,8 @@ describe("Delete Database Confirmation Pane", () => {
|
|||
});
|
||||
|
||||
describe("submit()", () => {
|
||||
let telemetryProcessorSpy: sinon.SinonSpy;
|
||||
|
||||
beforeEach(() => {
|
||||
telemetryProcessorSpy = sinon.spy(TelemetryProcessor, "trace");
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
telemetryProcessorSpy.restore();
|
||||
});
|
||||
|
||||
it("on submit() it should log feedback if last non empty database or is last database that has shared throughput", () => {
|
||||
let selectedDatabaseId = "testDB";
|
||||
let fakeDocumentClientUtility = {} as DocumentClientUtilityBase;
|
||||
fakeDocumentClientUtility.deleteDatabase = () => Q.resolve(null);
|
||||
let fakeExplorer = {} as Explorer;
|
||||
fakeExplorer.findSelectedDatabase = () => {
|
||||
return {
|
||||
|
@ -114,13 +105,11 @@ describe("Delete Database Confirmation Pane", () => {
|
|||
fakeExplorer.isPreferredApiCassandra = ko.computed(() => {
|
||||
return false;
|
||||
});
|
||||
fakeExplorer.documentClientUtility = fakeDocumentClientUtility;
|
||||
fakeExplorer.selectedNode = ko.observable<TreeNode>();
|
||||
fakeExplorer.tabsManager = new TabsManager();
|
||||
fakeExplorer.isLastNonEmptyDatabase = () => true;
|
||||
|
||||
let pane = new DeleteDatabaseConfirmationPane({
|
||||
documentClientUtility: fakeDocumentClientUtility as any,
|
||||
id: "deletedatabaseconfirmationpane",
|
||||
visible: ko.observable<boolean>(false),
|
||||
container: fakeExplorer as any
|
||||
|
@ -130,15 +119,12 @@ describe("Delete Database Confirmation Pane", () => {
|
|||
pane.databaseDeleteFeedback(Feedback);
|
||||
|
||||
return pane.submit().then(() => {
|
||||
expect(telemetryProcessorSpy.called).toBe(true);
|
||||
let deleteFeedback = new DeleteFeedback(SubscriptionId, AccountName, DataModels.ApiKind.SQL, Feedback);
|
||||
expect(
|
||||
telemetryProcessorSpy.calledWith(
|
||||
Action.DeleteDatabase,
|
||||
ActionModifiers.Mark,
|
||||
JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
)
|
||||
).toBe(true);
|
||||
expect(TelemetryProcessor.trace).toHaveBeenCalledWith(
|
||||
Action.DeleteDatabase,
|
||||
ActionModifiers.Mark,
|
||||
JSON.stringify(deleteFeedback, Object.getOwnPropertyNames(deleteFeedback))
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,6 +12,7 @@ import DeleteFeedback from "../../Common/DeleteFeedback";
|
|||
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import { deleteDatabase } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
||||
public databaseIdConfirmationText: ko.Observable<string>;
|
||||
|
@ -59,7 +60,7 @@ export default class DeleteDatabaseConfirmationPane extends ContextualPaneBase {
|
|||
this.container
|
||||
);
|
||||
} else {
|
||||
promise = this.container.documentClientUtility.deleteDatabase(selectedDatabase);
|
||||
promise = deleteDatabase(selectedDatabase);
|
||||
}
|
||||
return promise.then(
|
||||
() => {
|
||||
|
|
|
@ -7,7 +7,7 @@ describe("Settings Pane", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be true for SQL API", () => {
|
||||
|
|
|
@ -15,8 +15,14 @@ import * as TableEntityProcessor from "./TableEntityProcessor";
|
|||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { MessageTypes } from "../../Contracts/ExplorerContracts";
|
||||
import { sendMessage } from "../../Common/MessageHandler";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
import {
|
||||
queryDocuments,
|
||||
refreshCachedResources,
|
||||
deleteDocument,
|
||||
updateDocument,
|
||||
createDocument
|
||||
} from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export interface CassandraTableKeys {
|
||||
partitionKeys: CassandraTableKey[];
|
||||
|
@ -29,11 +35,7 @@ export interface CassandraTableKey {
|
|||
}
|
||||
|
||||
export abstract class TableDataClient {
|
||||
public documentClientUtility: DocumentClientUtilityBase;
|
||||
|
||||
constructor(documentClientUtility: DocumentClientUtilityBase) {
|
||||
this.documentClientUtility = documentClientUtility;
|
||||
}
|
||||
constructor() {}
|
||||
|
||||
public abstract createDocument(
|
||||
collection: ViewModels.Collection,
|
||||
|
@ -65,20 +67,18 @@ export class TablesAPIDataClient extends TableDataClient {
|
|||
entity: Entities.ITableEntity
|
||||
): Q.Promise<Entities.ITableEntity> {
|
||||
const deferred = Q.defer<Entities.ITableEntity>();
|
||||
this.documentClientUtility
|
||||
.createDocument(
|
||||
collection,
|
||||
TableEntityProcessor.convertEntityToNewDocument(<Entities.ITableEntityForTablesAPI>entity)
|
||||
)
|
||||
.then(
|
||||
(newDocument: any) => {
|
||||
const newEntity = TableEntityProcessor.convertDocumentsToEntities([newDocument])[0];
|
||||
deferred.resolve(newEntity);
|
||||
},
|
||||
reason => {
|
||||
deferred.reject(reason);
|
||||
}
|
||||
);
|
||||
createDocument(
|
||||
collection,
|
||||
TableEntityProcessor.convertEntityToNewDocument(<Entities.ITableEntityForTablesAPI>entity)
|
||||
).then(
|
||||
(newDocument: any) => {
|
||||
const newEntity = TableEntityProcessor.convertDocumentsToEntities([newDocument])[0];
|
||||
deferred.resolve(newEntity);
|
||||
},
|
||||
reason => {
|
||||
deferred.reject(reason);
|
||||
}
|
||||
);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -88,21 +88,20 @@ export class TablesAPIDataClient extends TableDataClient {
|
|||
entity: Entities.ITableEntity
|
||||
): Q.Promise<Entities.ITableEntity> {
|
||||
const deferred = Q.defer<Entities.ITableEntity>();
|
||||
this.documentClientUtility
|
||||
.updateDocument(
|
||||
collection,
|
||||
originalDocument,
|
||||
TableEntityProcessor.convertEntityToNewDocument(<Entities.ITableEntityForTablesAPI>entity)
|
||||
)
|
||||
.then(
|
||||
(newDocument: any) => {
|
||||
const newEntity = TableEntityProcessor.convertDocumentsToEntities([newDocument])[0];
|
||||
deferred.resolve(newEntity);
|
||||
},
|
||||
reason => {
|
||||
deferred.reject(reason);
|
||||
}
|
||||
);
|
||||
|
||||
updateDocument(
|
||||
collection,
|
||||
originalDocument,
|
||||
TableEntityProcessor.convertEntityToNewDocument(<Entities.ITableEntityForTablesAPI>entity)
|
||||
).then(
|
||||
(newDocument: any) => {
|
||||
const newEntity = TableEntityProcessor.convertDocumentsToEntities([newDocument])[0];
|
||||
deferred.resolve(newEntity);
|
||||
},
|
||||
reason => {
|
||||
deferred.reject(reason);
|
||||
}
|
||||
);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
|
@ -114,7 +113,7 @@ export class TablesAPIDataClient extends TableDataClient {
|
|||
|
||||
let options: any = {};
|
||||
options.enableCrossPartitionQuery = HeadersUtility.shouldEnableCrossPartitionKey();
|
||||
this.documentClientUtility.queryDocuments(collection.databaseId, collection.id(), query, options).then(
|
||||
queryDocuments(collection.databaseId, collection.id(), query, options).then(
|
||||
iterator => {
|
||||
iterator
|
||||
.fetchNext()
|
||||
|
@ -150,7 +149,7 @@ export class TablesAPIDataClient extends TableDataClient {
|
|||
documentsToDelete &&
|
||||
documentsToDelete.forEach(document => {
|
||||
document.id = ko.observable<string>(document.id);
|
||||
let promise: Q.Promise<any> = this.documentClientUtility.deleteDocument(collection, document);
|
||||
let promise: Q.Promise<any> = deleteDocument(collection, document);
|
||||
promiseArray.push(promise);
|
||||
});
|
||||
return Q.all(promiseArray);
|
||||
|
@ -425,7 +424,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
|||
ConsoleDataType.Info,
|
||||
`Successfully created a keyspace with query ${createKeyspaceQuery}`
|
||||
);
|
||||
explorer.documentClientUtility.refreshCachedResources().finally(() => deferred.resolve());
|
||||
refreshCachedResources().finally(() => deferred.resolve());
|
||||
},
|
||||
reason => {
|
||||
NotificationConsoleUtils.logConsoleMessage(
|
||||
|
@ -472,7 +471,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
|||
ConsoleDataType.Info,
|
||||
`Successfully created a table with query ${createTableQuery}`
|
||||
);
|
||||
this.documentClientUtility.refreshCachedResources(null).then(
|
||||
refreshCachedResources(null).then(
|
||||
() => {
|
||||
deferred.resolve();
|
||||
},
|
||||
|
@ -521,7 +520,7 @@ export class CassandraAPIDataClient extends TableDataClient {
|
|||
ConsoleDataType.Info,
|
||||
`Successfully deleted resource with query ${deleteQuery}`
|
||||
);
|
||||
this.documentClientUtility.refreshCachedResources(null).then(
|
||||
refreshCachedResources(null).then(
|
||||
() => {
|
||||
deferred.resolve();
|
||||
},
|
||||
|
|
|
@ -21,6 +21,13 @@ import DeleteIcon from "../../../images/delete.svg";
|
|||
import { QueryIterator, ItemDefinition, Resource, ConflictDefinition } from "@azure/cosmos";
|
||||
import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
|
||||
import Explorer from "../Explorer";
|
||||
import {
|
||||
queryConflicts,
|
||||
deleteConflict,
|
||||
deleteDocument,
|
||||
createDocument,
|
||||
updateDocument
|
||||
} from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class ConflictsTab extends TabsBase {
|
||||
public selectedConflictId: ko.Observable<ViewModels.ConflictId>;
|
||||
|
@ -286,7 +293,7 @@ export default class ConflictsTab extends TabsBase {
|
|||
if (selectedConflict.operationType === Constants.ConflictOperationType.Replace) {
|
||||
const documentContent = JSON.parse(this.selectedConflictContent());
|
||||
|
||||
operationPromise = this._container.documentClientUtility.updateDocument(
|
||||
operationPromise = updateDocument(
|
||||
this.collection,
|
||||
selectedConflict.buildDocumentIdFromConflict(documentContent[selectedConflict.partitionKeyProperty]),
|
||||
documentContent
|
||||
|
@ -296,13 +303,13 @@ export default class ConflictsTab extends TabsBase {
|
|||
if (selectedConflict.operationType === Constants.ConflictOperationType.Create) {
|
||||
const documentContent = JSON.parse(this.selectedConflictContent());
|
||||
|
||||
operationPromise = this._container.documentClientUtility.createDocument(this.collection, documentContent);
|
||||
operationPromise = createDocument(this.collection, documentContent);
|
||||
}
|
||||
|
||||
if (selectedConflict.operationType === Constants.ConflictOperationType.Delete && !!this.selectedConflictContent()) {
|
||||
const documentContent = JSON.parse(this.selectedConflictContent());
|
||||
|
||||
operationPromise = this._container.documentClientUtility.deleteDocument(
|
||||
operationPromise = deleteDocument(
|
||||
this.collection,
|
||||
selectedConflict.buildDocumentIdFromConflict(documentContent[selectedConflict.partitionKeyProperty])
|
||||
);
|
||||
|
@ -311,7 +318,7 @@ export default class ConflictsTab extends TabsBase {
|
|||
return operationPromise
|
||||
.then(
|
||||
() => {
|
||||
return this._container.documentClientUtility.deleteConflict(this.collection, selectedConflict).then(() => {
|
||||
return deleteConflict(this.collection, selectedConflict).then(() => {
|
||||
this.conflictIds.remove((conflictId: ViewModels.ConflictId) => conflictId.rid === selectedConflict.rid);
|
||||
this.selectedConflictContent("");
|
||||
this.selectedConflictCurrent("");
|
||||
|
@ -370,8 +377,7 @@ export default class ConflictsTab extends TabsBase {
|
|||
conflictResourceId: selectedConflict.resourceId
|
||||
});
|
||||
|
||||
return this._container.documentClientUtility
|
||||
.deleteConflict(this.collection, selectedConflict)
|
||||
return deleteConflict(this.collection, selectedConflict)
|
||||
.then(
|
||||
() => {
|
||||
this.conflictIds.remove((conflictId: ViewModels.ConflictId) => conflictId.rid === selectedConflict.rid);
|
||||
|
@ -491,7 +497,7 @@ export default class ConflictsTab extends TabsBase {
|
|||
const query: string = undefined;
|
||||
let options: any = {};
|
||||
options.enableCrossPartitionQuery = HeadersUtility.shouldEnableCrossPartitionKey();
|
||||
return this.documentClientUtility.queryConflicts(this.collection.databaseId, this.collection.id(), query, options);
|
||||
return queryConflicts(this.collection.databaseId, this.collection.id(), query, options);
|
||||
}
|
||||
|
||||
public loadNextPage(): Q.Promise<any> {
|
||||
|
|
|
@ -18,6 +18,7 @@ import { CosmosClient } from "../../Common/CosmosClient";
|
|||
import { PlatformType } from "../../PlatformType";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import Explorer from "../Explorer";
|
||||
import { updateOfferThroughputBeyondLimit, updateOffer } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
const updateThroughputBeyondLimitWarningMessage: string = `
|
||||
You are about to request an increase in throughput beyond the pre-allocated capacity.
|
||||
|
@ -499,13 +500,13 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
|||
delete newOffer.content.offerAutopilotSettings;
|
||||
}
|
||||
|
||||
const updateOfferPromise = this.container.documentClientUtility
|
||||
.updateOffer(this.database.offer(), newOffer, headerOptions)
|
||||
.then((updatedOffer: DataModels.Offer) => {
|
||||
const updateOfferPromise = updateOffer(this.database.offer(), newOffer, headerOptions).then(
|
||||
(updatedOffer: DataModels.Offer) => {
|
||||
this.database.offer(updatedOffer);
|
||||
this.database.offer.valueHasMutated();
|
||||
this._wasAutopilotOriginallySet(this.isAutoPilotSelected());
|
||||
});
|
||||
}
|
||||
);
|
||||
promises.push(updateOfferPromise);
|
||||
} else {
|
||||
if (this.throughput.editableIsDirty() || this.isAutoPilotSelected.editableIsDirty()) {
|
||||
|
@ -527,32 +528,30 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
|||
throughput: newThroughput,
|
||||
offerIsRUPerMinuteThroughputEnabled: false
|
||||
};
|
||||
const updateOfferBeyondLimitPromise: Q.Promise<void> = this.documentClientUtility
|
||||
.updateOfferThroughputBeyondLimit(requestPayload)
|
||||
.then(
|
||||
() => {
|
||||
this.database.offer().content.offerThroughput = originalThroughputValue;
|
||||
this.throughput(originalThroughputValue);
|
||||
this.notificationStatusInfo(
|
||||
throughputApplyDelayedMessage(this.isAutoPilotSelected(), newThroughput, this.database.id())
|
||||
);
|
||||
this.throughput.valueHasMutated(); // force component re-render
|
||||
},
|
||||
(error: any) => {
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.UpdateSettings,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
databaseName: this.database && this.database.id(),
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Tab,
|
||||
tabTitle: this.tabTitle(),
|
||||
error: error
|
||||
},
|
||||
startKey
|
||||
);
|
||||
}
|
||||
);
|
||||
const updateOfferBeyondLimitPromise: Q.Promise<void> = updateOfferThroughputBeyondLimit(requestPayload).then(
|
||||
() => {
|
||||
this.database.offer().content.offerThroughput = originalThroughputValue;
|
||||
this.throughput(originalThroughputValue);
|
||||
this.notificationStatusInfo(
|
||||
throughputApplyDelayedMessage(this.isAutoPilotSelected(), newThroughput, this.database.id())
|
||||
);
|
||||
this.throughput.valueHasMutated(); // force component re-render
|
||||
},
|
||||
(error: any) => {
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.UpdateSettings,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
databaseName: this.database && this.database.id(),
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Tab,
|
||||
tabTitle: this.tabTitle(),
|
||||
error: error
|
||||
},
|
||||
startKey
|
||||
);
|
||||
}
|
||||
);
|
||||
promises.push(updateOfferBeyondLimitPromise);
|
||||
} else {
|
||||
const newOffer: DataModels.Offer = {
|
||||
|
@ -577,13 +576,13 @@ export default class DatabaseSettingsTab extends TabsBase implements ViewModels.
|
|||
newOffer.content.offerAutopilotSettings = { maxThroughput: 0 };
|
||||
}
|
||||
|
||||
const updateOfferPromise = this.container.documentClientUtility
|
||||
.updateOffer(this.database.offer(), newOffer, headerOptions)
|
||||
.then((updatedOffer: DataModels.Offer) => {
|
||||
const updateOfferPromise = updateOffer(this.database.offer(), newOffer, headerOptions).then(
|
||||
(updatedOffer: DataModels.Offer) => {
|
||||
this._wasAutopilotOriginallySet(this.isAutoPilotSelected());
|
||||
this.database.offer(updatedOffer);
|
||||
this.database.offer.valueHasMutated();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
promises.push(updateOfferPromise);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ import * as ViewModels from "../../Contracts/ViewModels";
|
|||
import * as Constants from "../../Common/Constants";
|
||||
import DocumentsTab from "./DocumentsTab";
|
||||
import Explorer from "../Explorer";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
describe("Documents tab", () => {
|
||||
describe("buildQuery", () => {
|
||||
|
@ -14,7 +13,6 @@ describe("Documents tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -28,13 +26,11 @@ describe("Documents tab", () => {
|
|||
|
||||
describe("showPartitionKey", () => {
|
||||
const explorer = new Explorer({
|
||||
documentClientUtility: null,
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
});
|
||||
|
||||
const mongoExplorer = new Explorer({
|
||||
documentClientUtility: null,
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
});
|
||||
|
@ -97,7 +93,6 @@ describe("Documents tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -116,7 +111,6 @@ describe("Documents tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -135,7 +129,6 @@ describe("Documents tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -154,7 +147,6 @@ describe("Documents tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -173,7 +165,6 @@ describe("Documents tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
|
|
@ -26,6 +26,13 @@ import { extractPartitionKey, PartitionKeyDefinition, QueryIterator, ItemDefinit
|
|||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
||||
import Explorer from "../Explorer";
|
||||
import {
|
||||
readDocument,
|
||||
queryDocuments,
|
||||
deleteDocument,
|
||||
updateDocument,
|
||||
createDocument
|
||||
} from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class DocumentsTab extends TabsBase implements ViewModels.DocumentsTab {
|
||||
public selectedDocumentId: ko.Observable<ViewModels.DocumentId>;
|
||||
|
@ -442,8 +449,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
|
|||
});
|
||||
const document = JSON.parse(this.selectedDocumentContent());
|
||||
this.isExecuting(true);
|
||||
return this.documentClientUtility
|
||||
.createDocument(this.collection, document)
|
||||
return createDocument(this.collection, document)
|
||||
.then(
|
||||
(savedDocument: any) => {
|
||||
const value: string = this.renderObjectForEditor(savedDocument || {}, null, 4);
|
||||
|
@ -516,8 +522,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
|
|||
tabTitle: this.tabTitle()
|
||||
});
|
||||
this.isExecuting(true);
|
||||
return this.documentClientUtility
|
||||
.updateDocument(this.collection, selectedDocumentId, documentContent)
|
||||
return updateDocument(this.collection, selectedDocumentId, documentContent)
|
||||
.then(
|
||||
(updatedDocument: any) => {
|
||||
const value: string = this.renderObjectForEditor(updatedDocument || {}, null, 4);
|
||||
|
@ -665,7 +670,7 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
|
|||
};
|
||||
|
||||
protected __deleteDocument(documentId: ViewModels.DocumentId): Q.Promise<any> {
|
||||
return this.documentClientUtility.deleteDocument(this.collection, documentId);
|
||||
return deleteDocument(this.collection, documentId);
|
||||
}
|
||||
|
||||
private _deleteDocument(selectedDocumentId: ViewModels.DocumentId): Q.Promise<any> {
|
||||
|
@ -724,12 +729,12 @@ export default class DocumentsTab extends TabsBase implements ViewModels.Documen
|
|||
options.partitionKey = this._resourceTokenPartitionKey;
|
||||
}
|
||||
|
||||
return this.documentClientUtility.queryDocuments(this.collection.databaseId, this.collection.id(), query, options);
|
||||
return queryDocuments(this.collection.databaseId, this.collection.id(), query, options);
|
||||
}
|
||||
|
||||
public selectDocument(documentId: ViewModels.DocumentId): Q.Promise<any> {
|
||||
this.selectedDocumentId(documentId);
|
||||
return this.documentClientUtility.readDocument(this.collection, documentId).then((content: any) => {
|
||||
return readDocument(this.collection, documentId).then((content: any) => {
|
||||
this.initDocumentEditor(documentId, content);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -83,7 +83,6 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
|
|||
onIsFilterQueryLoading: (isFilterQueryLoading: boolean): void => this.isFilterQueryLoading(isFilterQueryLoading),
|
||||
onIsValidQuery: (isValidQuery: boolean): void => this.isValidQuery(isValidQuery),
|
||||
collectionPartitionKeyProperty: options.collectionPartitionKeyProperty,
|
||||
documentClientUtility: this.documentClientUtility,
|
||||
collectionRid: this.rid,
|
||||
collectionSelfLink: options.selfLink,
|
||||
graphBackendEndpoint: GraphTab.getGremlinEndpoint(options.account),
|
||||
|
@ -101,7 +100,6 @@ export default class GraphTab extends TabsBase implements ViewModels.Tab {
|
|||
|
||||
this.isFilterQueryLoading = ko.observable(false);
|
||||
this.isValidQuery = ko.observable(true);
|
||||
this.documentClientUtility = options.documentClientUtility;
|
||||
this.toolbarViewModel = ko.observable<Toolbar>();
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ describe("Query Tab", () => {
|
|||
database: database,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: container.documentClientUtility,
|
||||
selfLink: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
hashLocation: "",
|
||||
|
@ -51,7 +50,7 @@ describe("Query Tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be true for accounts using SQL API", () => {
|
||||
|
@ -71,7 +70,7 @@ describe("Query Tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
});
|
||||
|
||||
it("should be visible when using a supported API", () => {
|
||||
|
|
|
@ -16,6 +16,7 @@ import { QueryUtils } from "../../Utils/QueryUtils";
|
|||
import SaveQueryIcon from "../../../images/save-cosmos.svg";
|
||||
|
||||
import { MinimalQueryIterator } from "../../Common/IteratorUtilities";
|
||||
import { queryDocuments, queryDocumentsPage } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
enum ToggleState {
|
||||
Result,
|
||||
|
@ -290,12 +291,7 @@ export default class QueryTab extends TabsBase implements ViewModels.QueryTab, V
|
|||
options.enableCrossPartitionQuery = HeadersUtility.shouldEnableCrossPartitionKey();
|
||||
|
||||
const queryDocuments = (firstItemIndex: number) =>
|
||||
this.documentClientUtility.queryDocumentsPage(
|
||||
this.collection && this.collection.id(),
|
||||
this._iterator,
|
||||
firstItemIndex,
|
||||
options
|
||||
);
|
||||
queryDocumentsPage(this.collection && this.collection.id(), this._iterator, firstItemIndex, options);
|
||||
this.isExecuting(true);
|
||||
return QueryUtils.queryPagesUntilContentPresent(firstItemIndex, queryDocuments)
|
||||
.then(
|
||||
|
@ -497,9 +493,9 @@ export default class QueryTab extends TabsBase implements ViewModels.QueryTab, V
|
|||
}
|
||||
|
||||
return Q(
|
||||
this.documentClientUtility
|
||||
.queryDocuments(this.collection.databaseId, this.collection.id(), this.sqlStatementToExecute(), options)
|
||||
.then(iterator => (this._iterator = iterator))
|
||||
queryDocuments(this.collection.databaseId, this.collection.id(), this.sqlStatementToExecute(), options).then(
|
||||
iterator => (this._iterator = iterator)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import * as ko from "knockout";
|
|||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import Collection from "../Tree/Collection";
|
||||
import Database from "../Tree/Database";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
import SettingsTab from "../Tabs/SettingsTab";
|
||||
|
||||
|
@ -63,8 +62,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: undefined,
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable(false),
|
||||
|
@ -80,7 +77,7 @@ describe("Settings tab", () => {
|
|||
};
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
@ -179,7 +176,7 @@ describe("Settings tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
@ -188,8 +185,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable(false),
|
||||
|
@ -212,7 +207,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
@ -231,7 +225,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
@ -261,7 +254,7 @@ describe("Settings tab", () => {
|
|||
let explorer: Explorer;
|
||||
|
||||
beforeEach(() => {
|
||||
explorer = new Explorer({ documentClientUtility: null, notificationsClient: null, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: null, isEmulator: false });
|
||||
explorer.hasAutoPilotV2FeatureFlag = ko.computed<boolean>(() => true);
|
||||
});
|
||||
|
||||
|
@ -270,7 +263,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
@ -287,7 +279,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
@ -313,7 +304,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
@ -346,7 +336,6 @@ describe("Settings tab", () => {
|
|||
|
||||
function getCollection(defaultApi: string, partitionKeyOption: PartitionKeyOption) {
|
||||
const explorer = new Explorer({
|
||||
documentClientUtility: null,
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
});
|
||||
|
@ -394,7 +383,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
@ -483,7 +471,6 @@ describe("Settings tab", () => {
|
|||
describe("AutoPilot", () => {
|
||||
function getCollection(autoPilotTier: DataModels.AutopilotTier) {
|
||||
const explorer = new Explorer({
|
||||
documentClientUtility: null,
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
});
|
||||
|
@ -540,7 +527,6 @@ describe("Settings tab", () => {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
|
|
|
@ -18,6 +18,11 @@ import { CosmosClient } from "../../Common/CosmosClient";
|
|||
import { PlatformType } from "../../PlatformType";
|
||||
import { RequestOptions } from "@azure/cosmos/dist-esm";
|
||||
import Explorer from "../Explorer";
|
||||
import {
|
||||
updateOfferThroughputBeyondLimit,
|
||||
updateOffer,
|
||||
updateCollection
|
||||
} from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
const ttlWarning: string = `
|
||||
The system will automatically delete items based on the TTL value (in seconds) you provide, without needing a delete operation explicitly issued by a client application.
|
||||
|
@ -1062,9 +1067,8 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
}
|
||||
|
||||
const newCollection: DataModels.Collection = _.extend({}, this.collection.rawDataModel, newCollectionAttributes);
|
||||
const updateCollectionPromise = this.container.documentClientUtility
|
||||
.updateCollection(this.collection.databaseId, this.collection, newCollection)
|
||||
.then((updatedCollection: DataModels.Collection) => {
|
||||
const updateCollectionPromise = updateCollection(this.collection.databaseId, this.collection, newCollection).then(
|
||||
(updatedCollection: DataModels.Collection) => {
|
||||
this.collection.rawDataModel = updatedCollection;
|
||||
this.collection.defaultTtl(updatedCollection.defaultTtl);
|
||||
this.collection.analyticalStorageTtl(updatedCollection.analyticalStorageTtl);
|
||||
|
@ -1073,7 +1077,8 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
this.collection.conflictResolutionPolicy(updatedCollection.conflictResolutionPolicy);
|
||||
this.collection.changeFeedPolicy(updatedCollection.changeFeedPolicy);
|
||||
this.collection.geospatialConfig(updatedCollection.geospatialConfig);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
promises.push(updateCollectionPromise);
|
||||
}
|
||||
|
@ -1147,48 +1152,46 @@ export default class SettingsTab extends TabsBase implements ViewModels.WaitsFor
|
|||
throughput: newThroughput,
|
||||
offerIsRUPerMinuteThroughputEnabled: isRUPerMinuteThroughputEnabled
|
||||
};
|
||||
const updateOfferBeyondLimitPromise: Q.Promise<void> = this.documentClientUtility
|
||||
.updateOfferThroughputBeyondLimit(requestPayload)
|
||||
.then(
|
||||
() => {
|
||||
this.collection.offer().content.offerThroughput = originalThroughputValue;
|
||||
this.throughput(originalThroughputValue);
|
||||
this.notificationStatusInfo(
|
||||
throughputApplyDelayedMessage(
|
||||
this.isAutoPilotSelected(),
|
||||
originalThroughputValue,
|
||||
this._getThroughputUnit(),
|
||||
this.collection.databaseId,
|
||||
this.collection.id(),
|
||||
newThroughput
|
||||
)
|
||||
);
|
||||
this.throughput.valueHasMutated(); // force component re-render
|
||||
},
|
||||
(error: any) => {
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.UpdateSettings,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
databaseName: this.collection && this.collection.databaseId,
|
||||
collectionName: this.collection && this.collection.id(),
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Tab,
|
||||
tabTitle: this.tabTitle(),
|
||||
error: error
|
||||
},
|
||||
startKey
|
||||
);
|
||||
}
|
||||
);
|
||||
const updateOfferBeyondLimitPromise: Q.Promise<void> = updateOfferThroughputBeyondLimit(requestPayload).then(
|
||||
() => {
|
||||
this.collection.offer().content.offerThroughput = originalThroughputValue;
|
||||
this.throughput(originalThroughputValue);
|
||||
this.notificationStatusInfo(
|
||||
throughputApplyDelayedMessage(
|
||||
this.isAutoPilotSelected(),
|
||||
originalThroughputValue,
|
||||
this._getThroughputUnit(),
|
||||
this.collection.databaseId,
|
||||
this.collection.id(),
|
||||
newThroughput
|
||||
)
|
||||
);
|
||||
this.throughput.valueHasMutated(); // force component re-render
|
||||
},
|
||||
(error: any) => {
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.UpdateSettings,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
databaseName: this.collection && this.collection.databaseId,
|
||||
collectionName: this.collection && this.collection.id(),
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
dataExplorerArea: Constants.Areas.Tab,
|
||||
tabTitle: this.tabTitle(),
|
||||
error: error
|
||||
},
|
||||
startKey
|
||||
);
|
||||
}
|
||||
);
|
||||
promises.push(updateOfferBeyondLimitPromise);
|
||||
} else {
|
||||
const updateOfferPromise = this.documentClientUtility
|
||||
.updateOffer(this.collection.offer(), newOffer, headerOptions)
|
||||
.then((updatedOffer: DataModels.Offer) => {
|
||||
const updateOfferPromise = updateOffer(this.collection.offer(), newOffer, headerOptions).then(
|
||||
(updatedOffer: DataModels.Offer) => {
|
||||
this.collection.offer(updatedOffer);
|
||||
this.collection.offer.valueHasMutated();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
promises.push(updateOfferPromise);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import ScriptTabBase from "./ScriptTabBase";
|
|||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import ExecuteQueryIcon from "../../../images/ExecuteQuery.svg";
|
||||
import StoredProcedure from "../Tree/StoredProcedure";
|
||||
import { createStoredProcedure, updateStoredProcedure } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
enum ToggleState {
|
||||
Result = "result",
|
||||
|
@ -81,8 +82,7 @@ export default class StoredProcedureTab extends ScriptTabBase implements ViewMod
|
|||
dataExplorerArea: Constants.Areas.Tab,
|
||||
tabTitle: this.tabTitle()
|
||||
});
|
||||
return this.documentClientUtility
|
||||
.updateStoredProcedure(this.collection, data)
|
||||
return updateStoredProcedure(this.collection, data)
|
||||
.then(
|
||||
(updatedResource: DataModels.StoredProcedure) => {
|
||||
this.resource(updatedResource);
|
||||
|
@ -240,8 +240,7 @@ export default class StoredProcedureTab extends ScriptTabBase implements ViewMod
|
|||
tabTitle: this.tabTitle()
|
||||
});
|
||||
|
||||
return this.documentClientUtility
|
||||
.createStoredProcedure(this.collection, resource)
|
||||
return createStoredProcedure(this.collection, resource)
|
||||
.then(
|
||||
createdResource => {
|
||||
this.tabTitle(createdResource.id);
|
||||
|
|
|
@ -7,13 +7,11 @@ import { RouteHandler } from "../../RouteHandlers/RouteHandler";
|
|||
import { WaitsForTemplateViewModel } from "../WaitsForTemplateViewModel";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import ThemeUtility from "../../Common/ThemeUtility";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import Explorer from "../Explorer";
|
||||
|
||||
// TODO: Use specific actions for logging telemetry data
|
||||
export default class TabsBase extends WaitsForTemplateViewModel implements ViewModels.Tab {
|
||||
public closeTabButton: ViewModels.Button;
|
||||
public documentClientUtility: DocumentClientUtilityBase;
|
||||
public node: ViewModels.TreeNode;
|
||||
public collection: ViewModels.CollectionBase;
|
||||
public database: ViewModels.Database;
|
||||
|
@ -39,7 +37,6 @@ export default class TabsBase extends WaitsForTemplateViewModel implements ViewM
|
|||
const id = new Date().getTime().toString();
|
||||
|
||||
this._theme = ThemeUtility.getMonacoTheme(options.theme);
|
||||
this.documentClientUtility = options.documentClientUtility;
|
||||
this.node = options.node;
|
||||
this.collection = options.collection;
|
||||
this.database = options.database;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import * as ko from "knockout";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { TabsManager } from "./TabsManager";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
import DocumentsTab from "./DocumentsTab";
|
||||
import Explorer from "../Explorer";
|
||||
import QueryTab from "./QueryTab";
|
||||
|
@ -15,7 +14,7 @@ describe("Tabs manager tests", () => {
|
|||
let documentsTab: DocumentsTab;
|
||||
|
||||
beforeAll(() => {
|
||||
explorer = new Explorer({ documentClientUtility: undefined, notificationsClient: undefined, isEmulator: false });
|
||||
explorer = new Explorer({ notificationsClient: undefined, isEmulator: false });
|
||||
explorer.databaseAccount = ko.observable<ViewModels.DatabaseAccount>({
|
||||
id: "test",
|
||||
name: "test",
|
||||
|
@ -49,7 +48,6 @@ describe("Tabs manager tests", () => {
|
|||
database,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: explorer.documentClientUtility,
|
||||
selfLink: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
hashLocation: "",
|
||||
|
@ -63,7 +61,6 @@ describe("Tabs manager tests", () => {
|
|||
collection,
|
||||
title: "",
|
||||
tabPath: "",
|
||||
documentClientUtility: new DocumentClientUtilityBase(),
|
||||
selfLink: "",
|
||||
hashLocation: "",
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
|
|
@ -7,6 +7,7 @@ import ScriptTabBase from "./ScriptTabBase";
|
|||
import editable from "../../Common/EditableUtility";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import Trigger from "../Tree/Trigger";
|
||||
import { createTrigger, updateTrigger } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class TriggerTab extends ScriptTabBase implements ViewModels.TriggerTab {
|
||||
public collection: ViewModels.Collection;
|
||||
|
@ -41,8 +42,7 @@ export default class TriggerTab extends ScriptTabBase implements ViewModels.Trig
|
|||
tabTitle: this.tabTitle()
|
||||
});
|
||||
|
||||
return this.documentClientUtility
|
||||
.updateTrigger(this.collection, data)
|
||||
return updateTrigger(this.collection, data)
|
||||
.then(
|
||||
(createdResource: DataModels.Trigger) => {
|
||||
this.resource(createdResource);
|
||||
|
@ -119,8 +119,7 @@ export default class TriggerTab extends ScriptTabBase implements ViewModels.Trig
|
|||
tabTitle: this.tabTitle()
|
||||
});
|
||||
|
||||
return this.documentClientUtility
|
||||
.createTrigger(this.collection, resource)
|
||||
return createTrigger(this.collection, resource)
|
||||
.then(
|
||||
(createdResource: DataModels.Trigger) => {
|
||||
this.tabTitle(createdResource.id);
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Action } from "../../Shared/Telemetry/TelemetryConstants";
|
|||
import ScriptTabBase from "./ScriptTabBase";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import UserDefinedFunction from "../Tree/UserDefinedFunction";
|
||||
import { createUserDefinedFunction, updateUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class UserDefinedFunctionTab extends ScriptTabBase implements ViewModels.UserDefinedFunctionTab {
|
||||
public collection: ViewModels.Collection;
|
||||
|
@ -34,8 +35,7 @@ export default class UserDefinedFunctionTab extends ScriptTabBase implements Vie
|
|||
tabTitle: this.tabTitle()
|
||||
});
|
||||
|
||||
return this.documentClientUtility
|
||||
.updateUserDefinedFunction(this.collection, data)
|
||||
return updateUserDefinedFunction(this.collection, data)
|
||||
.then(
|
||||
(createdResource: DataModels.UserDefinedFunction) => {
|
||||
this.resource(createdResource);
|
||||
|
@ -104,8 +104,7 @@ export default class UserDefinedFunctionTab extends ScriptTabBase implements Vie
|
|||
tabTitle: this.tabTitle()
|
||||
});
|
||||
|
||||
return this.documentClientUtility
|
||||
.createUserDefinedFunction(this.collection, resource)
|
||||
return createUserDefinedFunction(this.collection, resource)
|
||||
.then(
|
||||
(createdResource: DataModels.UserDefinedFunction) => {
|
||||
this.tabTitle(createdResource.id);
|
||||
|
|
|
@ -33,6 +33,15 @@ import Trigger from "./Trigger";
|
|||
import UserDefinedFunction from "./UserDefinedFunction";
|
||||
import { config } from "../../Config";
|
||||
import Explorer from "../Explorer";
|
||||
import {
|
||||
createDocument,
|
||||
readTriggers,
|
||||
readUserDefinedFunctions,
|
||||
readStoredProcedures,
|
||||
readCollectionQuotaInfo,
|
||||
readOffer,
|
||||
readOffers
|
||||
} from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class Collection implements ViewModels.Collection {
|
||||
public nodeKind: string;
|
||||
|
@ -306,7 +315,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
documentIds: ko.observableArray<DocumentId>([]),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "Items",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
selfLink: this.self,
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -358,7 +366,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
conflictIds: ko.observableArray<ConflictId>([]),
|
||||
tabKind: ViewModels.CollectionTabKind.Conflicts,
|
||||
title: "Conflicts",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
selfLink: this.self,
|
||||
isActive: ko.observable<boolean>(false),
|
||||
|
@ -419,7 +426,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
tabKind: ViewModels.CollectionTabKind.QueryTables,
|
||||
title: title,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
collection: this,
|
||||
|
||||
node: this,
|
||||
|
@ -472,7 +479,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
node: this,
|
||||
title: title,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
collection: this,
|
||||
selfLink: this.self,
|
||||
masterKey: CosmosClient.masterKey() || "",
|
||||
|
@ -527,7 +534,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "Documents",
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
collection: this,
|
||||
|
||||
node: this,
|
||||
|
@ -580,7 +587,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
tabKind: ViewModels.CollectionTabKind.Settings,
|
||||
title: !this.offer() ? "Settings" : "Scale & Settings",
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
collection: this,
|
||||
node: this,
|
||||
selfLink: this.self,
|
||||
|
@ -645,10 +652,8 @@ export default class Collection implements ViewModels.Collection {
|
|||
defaultExperience: this.container.defaultExperience()
|
||||
});
|
||||
// TODO: Use the collection entity cache to get quota info
|
||||
const quotaInfoPromise: Q.Promise<DataModels.CollectionQuotaInfo> = this.container.documentClientUtility.readCollectionQuotaInfo(
|
||||
this
|
||||
);
|
||||
const offerInfoPromise: Q.Promise<DataModels.Offer[]> = this.container.documentClientUtility.readOffers();
|
||||
const quotaInfoPromise: Q.Promise<DataModels.CollectionQuotaInfo> = readCollectionQuotaInfo(this);
|
||||
const offerInfoPromise: Q.Promise<DataModels.Offer[]> = readOffers();
|
||||
Q.all([quotaInfoPromise, offerInfoPromise]).then(
|
||||
() => {
|
||||
this.container.isRefreshingExplorer(false);
|
||||
|
@ -675,41 +680,39 @@ export default class Collection implements ViewModels.Collection {
|
|||
return;
|
||||
}
|
||||
|
||||
this.container.documentClientUtility
|
||||
.readOffer(collectionOffer)
|
||||
.then((offerDetail: DataModels.OfferWithHeaders) => {
|
||||
if (OfferUtils.isNotOfferV1(collectionOffer)) {
|
||||
const offerThroughputInfo: DataModels.OfferThroughputInfo = {
|
||||
minimumRUForCollection:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.minimumRUForCollection,
|
||||
numPhysicalPartitions:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.numPhysicalPartitions
|
||||
};
|
||||
readOffer(collectionOffer).then((offerDetail: DataModels.OfferWithHeaders) => {
|
||||
if (OfferUtils.isNotOfferV1(collectionOffer)) {
|
||||
const offerThroughputInfo: DataModels.OfferThroughputInfo = {
|
||||
minimumRUForCollection:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.minimumRUForCollection,
|
||||
numPhysicalPartitions:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.numPhysicalPartitions
|
||||
};
|
||||
|
||||
collectionOffer.content.collectionThroughputInfo = offerThroughputInfo;
|
||||
}
|
||||
collectionOffer.content.collectionThroughputInfo = offerThroughputInfo;
|
||||
}
|
||||
|
||||
(collectionOffer as DataModels.OfferWithHeaders).headers = offerDetail.headers;
|
||||
this.offer(collectionOffer);
|
||||
this.offer.valueHasMutated();
|
||||
this.quotaInfo(quotaInfo);
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadOffers,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
databaseName: this.databaseId,
|
||||
collectionName: this.id(),
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
offerVersion: collectionOffer && collectionOffer.offerVersion
|
||||
},
|
||||
startKey
|
||||
);
|
||||
deferred.resolve();
|
||||
});
|
||||
(collectionOffer as DataModels.OfferWithHeaders).headers = offerDetail.headers;
|
||||
this.offer(collectionOffer);
|
||||
this.offer.valueHasMutated();
|
||||
this.quotaInfo(quotaInfo);
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadOffers,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
databaseName: this.databaseId,
|
||||
collectionName: this.id(),
|
||||
defaultExperience: this.container.defaultExperience(),
|
||||
offerVersion: collectionOffer && collectionOffer.offerVersion
|
||||
},
|
||||
startKey
|
||||
);
|
||||
deferred.resolve();
|
||||
});
|
||||
},
|
||||
(error: any) => {
|
||||
this.container.isRefreshingExplorer(false);
|
||||
|
@ -747,7 +750,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
tabKind: ViewModels.CollectionTabKind.Query,
|
||||
title: title,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this,
|
||||
node: this,
|
||||
selfLink: this.self,
|
||||
|
@ -780,7 +782,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
tabKind: ViewModels.CollectionTabKind.Query,
|
||||
title: title,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this,
|
||||
node: this,
|
||||
selfLink: this.self,
|
||||
|
@ -813,7 +814,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
node: this,
|
||||
title: title,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this,
|
||||
selfLink: this.self,
|
||||
masterKey: CosmosClient.masterKey() || "",
|
||||
|
@ -836,7 +836,6 @@ export default class Collection implements ViewModels.Collection {
|
|||
tabKind: ViewModels.CollectionTabKind.MongoShell,
|
||||
title: "Shell " + id,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this,
|
||||
node: this,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(this.databaseId, this.id())}/mongoShell`,
|
||||
|
@ -1075,40 +1074,34 @@ export default class Collection implements ViewModels.Collection {
|
|||
}
|
||||
|
||||
public loadStoredProcedures(): Q.Promise<any> {
|
||||
return this.container.documentClientUtility
|
||||
.readStoredProcedures(this)
|
||||
.then((storedProcedures: DataModels.StoredProcedure[]) => {
|
||||
const storedProceduresNodes: ViewModels.TreeNode[] = storedProcedures.map(
|
||||
storedProcedure => new StoredProcedure(this.container, this, storedProcedure)
|
||||
);
|
||||
const otherNodes = this.children().filter(node => node.nodeKind !== "StoredProcedure");
|
||||
const allNodes = otherNodes.concat(storedProceduresNodes);
|
||||
this.children(allNodes);
|
||||
});
|
||||
return readStoredProcedures(this).then((storedProcedures: DataModels.StoredProcedure[]) => {
|
||||
const storedProceduresNodes: ViewModels.TreeNode[] = storedProcedures.map(
|
||||
storedProcedure => new StoredProcedure(this.container, this, storedProcedure)
|
||||
);
|
||||
const otherNodes = this.children().filter(node => node.nodeKind !== "StoredProcedure");
|
||||
const allNodes = otherNodes.concat(storedProceduresNodes);
|
||||
this.children(allNodes);
|
||||
});
|
||||
}
|
||||
|
||||
public loadUserDefinedFunctions(): Q.Promise<any> {
|
||||
return this.container.documentClientUtility
|
||||
.readUserDefinedFunctions(this)
|
||||
.then((userDefinedFunctions: DataModels.UserDefinedFunction[]) => {
|
||||
const userDefinedFunctionsNodes: ViewModels.TreeNode[] = userDefinedFunctions.map(
|
||||
udf => new UserDefinedFunction(this.container, this, udf)
|
||||
);
|
||||
const otherNodes = this.children().filter(node => node.nodeKind !== "UserDefinedFunction");
|
||||
const allNodes = otherNodes.concat(userDefinedFunctionsNodes);
|
||||
this.children(allNodes);
|
||||
});
|
||||
return readUserDefinedFunctions(this).then((userDefinedFunctions: DataModels.UserDefinedFunction[]) => {
|
||||
const userDefinedFunctionsNodes: ViewModels.TreeNode[] = userDefinedFunctions.map(
|
||||
udf => new UserDefinedFunction(this.container, this, udf)
|
||||
);
|
||||
const otherNodes = this.children().filter(node => node.nodeKind !== "UserDefinedFunction");
|
||||
const allNodes = otherNodes.concat(userDefinedFunctionsNodes);
|
||||
this.children(allNodes);
|
||||
});
|
||||
}
|
||||
|
||||
public loadTriggers(): Q.Promise<any> {
|
||||
return this.container.documentClientUtility
|
||||
.readTriggers(this, null /*options*/)
|
||||
.then((triggers: DataModels.Trigger[]) => {
|
||||
const triggerNodes: ViewModels.TreeNode[] = triggers.map(trigger => new Trigger(this.container, this, trigger));
|
||||
const otherNodes = this.children().filter(node => node.nodeKind !== "Trigger");
|
||||
const allNodes = otherNodes.concat(triggerNodes);
|
||||
this.children(allNodes);
|
||||
});
|
||||
return readTriggers(this, null /*options*/).then((triggers: DataModels.Trigger[]) => {
|
||||
const triggerNodes: ViewModels.TreeNode[] = triggers.map(trigger => new Trigger(this.container, this, trigger));
|
||||
const otherNodes = this.children().filter(node => node.nodeKind !== "Trigger");
|
||||
const allNodes = otherNodes.concat(triggerNodes);
|
||||
this.children(allNodes);
|
||||
});
|
||||
}
|
||||
|
||||
public onDragOver(source: Collection, event: { originalEvent: DragEvent }) {
|
||||
|
@ -1269,7 +1262,7 @@ export default class Collection implements ViewModels.Collection {
|
|||
const promises: Array<Q.Promise<any>> = [];
|
||||
|
||||
const triggerCreateDocument: (documentContent: any) => Q.Promise<any> = (documentContent: any) => {
|
||||
return this.container.documentClientUtility.createDocument(this, documentContent).then(
|
||||
return createDocument(this, documentContent).then(
|
||||
doc => {
|
||||
record.numSucceeded++;
|
||||
return Q.resolve();
|
||||
|
|
|
@ -6,6 +6,7 @@ import * as DataModels from "../../Contracts/DataModels";
|
|||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { extractPartitionKey } from "@azure/cosmos";
|
||||
import ConflictsTab from "../Tabs/ConflictsTab";
|
||||
import { readDocument } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class ConflictId implements ViewModels.ConflictId {
|
||||
public container: ConflictsTab;
|
||||
|
@ -68,33 +69,31 @@ export default class ConflictId implements ViewModels.ConflictId {
|
|||
}
|
||||
|
||||
this.container.loadingConflictData(true);
|
||||
return conflictsTab.documentClientUtility
|
||||
.readDocument(this.container.collection, this.buildDocumentIdFromConflict(this.partitionKeyValue))
|
||||
.then(
|
||||
(currentDocumentContent: any) => {
|
||||
this.container.loadingConflictData(false);
|
||||
if (this.operationType === Constants.ConflictOperationType.Replace) {
|
||||
this.container.initDocumentEditorForReplace(this, this.content, currentDocumentContent);
|
||||
} else {
|
||||
this.container.initDocumentEditorForDelete(this, currentDocumentContent);
|
||||
}
|
||||
},
|
||||
(reason: any) => {
|
||||
this.container.loadingConflictData(false);
|
||||
|
||||
// Document could be deleted
|
||||
if (
|
||||
reason &&
|
||||
reason.code === Constants.HttpStatusCodes.NotFound &&
|
||||
this.operationType === Constants.ConflictOperationType.Delete
|
||||
) {
|
||||
this.container.initDocumentEditorForNoOp(this);
|
||||
return Q();
|
||||
}
|
||||
|
||||
return Q.reject(reason);
|
||||
return readDocument(this.container.collection, this.buildDocumentIdFromConflict(this.partitionKeyValue)).then(
|
||||
(currentDocumentContent: any) => {
|
||||
this.container.loadingConflictData(false);
|
||||
if (this.operationType === Constants.ConflictOperationType.Replace) {
|
||||
this.container.initDocumentEditorForReplace(this, this.content, currentDocumentContent);
|
||||
} else {
|
||||
this.container.initDocumentEditorForDelete(this, currentDocumentContent);
|
||||
}
|
||||
);
|
||||
},
|
||||
(reason: any) => {
|
||||
this.container.loadingConflictData(false);
|
||||
|
||||
// Document could be deleted
|
||||
if (
|
||||
reason &&
|
||||
reason.code === Constants.HttpStatusCodes.NotFound &&
|
||||
this.operationType === Constants.ConflictOperationType.Delete
|
||||
) {
|
||||
this.container.initDocumentEditorForNoOp(this);
|
||||
return Q();
|
||||
}
|
||||
|
||||
return Q.reject(reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public getPartitionKeyValueAsString(): string {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { NotificationConsoleUtils } from "../../Utils/NotificationConsoleUtils";
|
|||
import { ConsoleDataType } from "../Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import Explorer from "../Explorer";
|
||||
import { readCollections, readOffers, readOffer } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class Database implements ViewModels.Database {
|
||||
public nodeKind: string;
|
||||
|
@ -71,7 +72,6 @@ export default class Database implements ViewModels.Database {
|
|||
tabKind: ViewModels.CollectionTabKind.DatabaseSettings,
|
||||
title: "Scale",
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
node: this,
|
||||
rid: this.rid,
|
||||
database: this,
|
||||
|
@ -137,7 +137,7 @@ export default class Database implements ViewModels.Database {
|
|||
defaultExperience: this.container.defaultExperience()
|
||||
});
|
||||
|
||||
const offerInfoPromise: Q.Promise<DataModels.Offer[]> = this.container.documentClientUtility.readOffers();
|
||||
const offerInfoPromise: Q.Promise<DataModels.Offer[]> = readOffers();
|
||||
Q.all([offerInfoPromise]).then(
|
||||
() => {
|
||||
this.container.isRefreshingExplorer(false);
|
||||
|
@ -146,35 +146,33 @@ export default class Database implements ViewModels.Database {
|
|||
offerInfoPromise.valueOf(),
|
||||
databaseDataModel
|
||||
);
|
||||
this.container.documentClientUtility
|
||||
.readOffer(databaseOffer)
|
||||
.then((offerDetail: DataModels.OfferWithHeaders) => {
|
||||
const offerThroughputInfo: DataModels.OfferThroughputInfo = {
|
||||
minimumRUForCollection:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.minimumRUForCollection,
|
||||
numPhysicalPartitions:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.numPhysicalPartitions
|
||||
};
|
||||
readOffer(databaseOffer).then((offerDetail: DataModels.OfferWithHeaders) => {
|
||||
const offerThroughputInfo: DataModels.OfferThroughputInfo = {
|
||||
minimumRUForCollection:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.minimumRUForCollection,
|
||||
numPhysicalPartitions:
|
||||
offerDetail.content &&
|
||||
offerDetail.content.collectionThroughputInfo &&
|
||||
offerDetail.content.collectionThroughputInfo.numPhysicalPartitions
|
||||
};
|
||||
|
||||
databaseOffer.content.collectionThroughputInfo = offerThroughputInfo;
|
||||
(databaseOffer as DataModels.OfferWithHeaders).headers = offerDetail.headers;
|
||||
this.offer(databaseOffer);
|
||||
this.offer.valueHasMutated();
|
||||
databaseOffer.content.collectionThroughputInfo = offerThroughputInfo;
|
||||
(databaseOffer as DataModels.OfferWithHeaders).headers = offerDetail.headers;
|
||||
this.offer(databaseOffer);
|
||||
this.offer.valueHasMutated();
|
||||
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadOffers,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
defaultExperience: this.container.defaultExperience()
|
||||
},
|
||||
startKey
|
||||
);
|
||||
deferred.resolve();
|
||||
});
|
||||
TelemetryProcessor.traceSuccess(
|
||||
Action.LoadOffers,
|
||||
{
|
||||
databaseAccountName: this.container.databaseAccount().name,
|
||||
defaultExperience: this.container.defaultExperience()
|
||||
},
|
||||
startKey
|
||||
);
|
||||
deferred.resolve();
|
||||
});
|
||||
},
|
||||
(error: any) => {
|
||||
this.container.isRefreshingExplorer(false);
|
||||
|
@ -263,7 +261,7 @@ export default class Database implements ViewModels.Database {
|
|||
let collectionVMs: Collection[] = [];
|
||||
let deferred: Q.Deferred<void> = Q.defer<void>();
|
||||
|
||||
this.container.documentClientUtility.readCollections(this).then(
|
||||
readCollections(this).then(
|
||||
(collections: DataModels.Collection[]) => {
|
||||
let collectionsToAddVMPromises: Q.Promise<any>[] = [];
|
||||
let deltaCollections = this.getDeltaCollections(collections);
|
||||
|
|
|
@ -91,7 +91,6 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
|||
tabKind: ViewModels.CollectionTabKind.Query,
|
||||
title: title,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this,
|
||||
node: this,
|
||||
selfLink: this.self,
|
||||
|
@ -143,8 +142,6 @@ export default class ResourceTokenCollection implements ViewModels.CollectionBas
|
|||
documentIds: ko.observableArray<DocumentId>([]),
|
||||
tabKind: ViewModels.CollectionTabKind.Documents,
|
||||
title: "Items",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
|
||||
selfLink: this.self,
|
||||
isActive: ko.observable<boolean>(false),
|
||||
collection: this,
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||
import StoredProcedureTab from "../Tabs/StoredProcedureTab";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import Explorer from "../Explorer";
|
||||
import { deleteStoredProcedure, executeStoredProcedure } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
const sampleStoredProcedureBody: string = `// SAMPLE STORED PROCEDURE
|
||||
function sample(prefix) {
|
||||
|
@ -69,7 +70,6 @@ export default class StoredProcedure {
|
|||
tabKind: ViewModels.CollectionTabKind.StoredProcedures,
|
||||
title: `New Stored Procedure ${id}`,
|
||||
tabPath: `${source.databaseId}>${source.id()}>New Stored Procedure ${id}`,
|
||||
documentClientUtility: source.container.documentClientUtility,
|
||||
collection: source,
|
||||
node: source,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(source.databaseId, source.id())}/sproc`,
|
||||
|
@ -116,7 +116,6 @@ export default class StoredProcedure {
|
|||
tabKind: ViewModels.CollectionTabKind.StoredProcedures,
|
||||
title: storedProcedureData.id,
|
||||
tabPath: `${this.collection.databaseId}>${this.collection.id()}>${storedProcedureData.id}`,
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this.collection,
|
||||
node: this,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(
|
||||
|
@ -144,7 +143,7 @@ export default class StoredProcedure {
|
|||
body: this.body()
|
||||
};
|
||||
|
||||
this.container.documentClientUtility.deleteStoredProcedure(this.collection, storedProcedureData).then(
|
||||
deleteStoredProcedure(this.collection, storedProcedureData).then(
|
||||
() => {
|
||||
this.container.tabsManager.removeTabByComparator(
|
||||
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid
|
||||
|
@ -163,8 +162,7 @@ export default class StoredProcedure {
|
|||
const sprocTab: ViewModels.StoredProcedureTab = sprocTabs && sprocTabs.length > 0 && sprocTabs[0];
|
||||
sprocTab.isExecuting(true);
|
||||
this.container &&
|
||||
this.container.documentClientUtility
|
||||
.executeStoredProcedure(this.collection, this, partitionKeyValue, params)
|
||||
executeStoredProcedure(this.collection, this, partitionKeyValue, params)
|
||||
.then(
|
||||
(result: any) => {
|
||||
sprocTab.onExecuteSprocsResult(result, result.scriptLogs);
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||
import TriggerTab from "../Tabs/TriggerTab";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import Explorer from "../Explorer";
|
||||
import { deleteTrigger } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class Trigger {
|
||||
public nodeKind: string;
|
||||
|
@ -55,7 +56,6 @@ export default class Trigger {
|
|||
tabKind: ViewModels.CollectionTabKind.Triggers,
|
||||
title: `New Trigger ${id}`,
|
||||
tabPath: "",
|
||||
documentClientUtility: source.container.documentClientUtility,
|
||||
collection: source,
|
||||
node: source,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(source.databaseId, source.id())}/trigger`,
|
||||
|
@ -94,7 +94,6 @@ export default class Trigger {
|
|||
tabKind: ViewModels.CollectionTabKind.Triggers,
|
||||
title: triggerData.id,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this.collection,
|
||||
node: this,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(
|
||||
|
@ -124,7 +123,7 @@ export default class Trigger {
|
|||
triggerType: this.triggerType()
|
||||
};
|
||||
|
||||
this.container.documentClientUtility.deleteTrigger(this.collection, triggerData).then(
|
||||
deleteTrigger(this.collection, triggerData).then(
|
||||
() => {
|
||||
this.container.tabsManager.removeTabByComparator(
|
||||
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid
|
||||
|
|
|
@ -6,6 +6,7 @@ import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstan
|
|||
import UserDefinedFunctionTab from "../Tabs/UserDefinedFunctionTab";
|
||||
import TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
|
||||
import Explorer from "../Explorer";
|
||||
import { deleteUserDefinedFunction } from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class UserDefinedFunction {
|
||||
public nodeKind: string;
|
||||
|
@ -40,7 +41,6 @@ export default class UserDefinedFunction {
|
|||
tabKind: ViewModels.CollectionTabKind.UserDefinedFunctions,
|
||||
title: `New UDF ${id}`,
|
||||
tabPath: "",
|
||||
documentClientUtility: source.container.documentClientUtility,
|
||||
collection: source,
|
||||
node: source,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(source.databaseId, source.id())}/udf`,
|
||||
|
@ -77,7 +77,6 @@ export default class UserDefinedFunction {
|
|||
tabKind: ViewModels.CollectionTabKind.UserDefinedFunctions,
|
||||
title: userDefinedFunctionData.id,
|
||||
tabPath: "",
|
||||
documentClientUtility: this.container.documentClientUtility,
|
||||
collection: this.collection,
|
||||
node: this,
|
||||
hashLocation: `${Constants.HashRoutePrefixes.collectionsWithIds(
|
||||
|
@ -114,7 +113,7 @@ export default class UserDefinedFunction {
|
|||
id: this.id(),
|
||||
body: this.body()
|
||||
};
|
||||
this.container.documentClientUtility.deleteUserDefinedFunction(this.collection, userDefinedFunctionData).then(
|
||||
deleteUserDefinedFunction(this.collection, userDefinedFunctionData).then(
|
||||
() => {
|
||||
this.container.tabsManager.removeTabByComparator(
|
||||
(tab: ViewModels.Tab) => tab.node && tab.node.rid === this.rid
|
||||
|
|
|
@ -3,15 +3,10 @@ import { AccountKind, TagNames, DefaultAccountExperience } from "../../Common/Co
|
|||
import Explorer from "../../Explorer/Explorer";
|
||||
|
||||
import { NotificationsClient } from "./NotificationsClient";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class EmulatorExplorerFactory {
|
||||
public static createExplorer(): Explorer {
|
||||
DocumentClientUtilityBase;
|
||||
const documentClientUtility: DocumentClientUtilityBase = new DocumentClientUtilityBase();
|
||||
|
||||
const explorer: Explorer = new Explorer({
|
||||
documentClientUtility: documentClientUtility,
|
||||
notificationsClient: new NotificationsClient(),
|
||||
isEmulator: true
|
||||
});
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
import Explorer from "../../Explorer/Explorer";
|
||||
import { NotificationsClient } from "./NotificationsClient";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class HostedExplorerFactory {
|
||||
public createExplorer(): Explorer {
|
||||
var documentClientUtility = new DocumentClientUtilityBase();
|
||||
|
||||
const explorer = new Explorer({
|
||||
documentClientUtility: documentClientUtility,
|
||||
notificationsClient: new NotificationsClient(),
|
||||
isEmulator: false
|
||||
});
|
||||
|
@ -17,8 +13,6 @@ export default class HostedExplorerFactory {
|
|||
|
||||
public static reInitializeDocumentClientUtilityForExplorer(explorer: Explorer): void {
|
||||
if (!!explorer) {
|
||||
const documentClientUtility = new DocumentClientUtilityBase();
|
||||
explorer.rebindDocumentClientUtility(documentClientUtility);
|
||||
explorer.notificationConsoleData([]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,9 @@
|
|||
import Explorer from "../../Explorer/Explorer";
|
||||
|
||||
import { NotificationsClient } from "./NotificationsClient";
|
||||
import DocumentClientUtilityBase from "../../Common/DocumentClientUtilityBase";
|
||||
|
||||
export default class PortalExplorerFactory {
|
||||
public createExplorer(): Explorer {
|
||||
var documentClientUtility = new DocumentClientUtilityBase();
|
||||
|
||||
var explorer = new Explorer({
|
||||
documentClientUtility: documentClientUtility,
|
||||
notificationsClient: new NotificationsClient(),
|
||||
isEmulator: false
|
||||
});
|
||||
|
|
|
@ -10,7 +10,6 @@ describe("TabRouteHandler", () => {
|
|||
|
||||
beforeAll(() => {
|
||||
(<any>window).dataExplorer = new Explorer({
|
||||
documentClientUtility: null,
|
||||
notificationsClient: null,
|
||||
isEmulator: false
|
||||
}); // create a mock to avoid null refs
|
||||
|
|
Loading…
Reference in New Issue