diff --git a/packages/compass-aggregations/electron/renderer/index.jsx b/packages/compass-aggregations/electron/renderer/index.jsx index e9290daf4a3..09c54e441dd 100644 --- a/packages/compass-aggregations/electron/renderer/index.jsx +++ b/packages/compass-aggregations/electron/renderer/index.jsx @@ -32,7 +32,7 @@ document.body.appendChild(root); // // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const localAppRegistry = new AppRegistry(); const store = configureStore({ @@ -71,7 +71,7 @@ const connection = new Connection({ port: 27017, ns: 'admin' }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); dataService.connect((error, ds) => { appRegistry.emit('data-service-connected', error, ds); diff --git a/packages/compass-app-stores/electron/renderer/index.js b/packages/compass-app-stores/electron/renderer/index.js index 1cd0a1727d1..07967bfc7ef 100644 --- a/packages/compass-app-stores/electron/renderer/index.js +++ b/packages/compass-app-stores/electron/renderer/index.js @@ -50,13 +50,13 @@ render(ComponentPlugin); // // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', port: 27017 }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); appRegistry.emit('data-service-initialized', dataService); dataService.connect((error, ds) => { diff --git a/packages/compass-auto-updates/electron/renderer/index.js b/packages/compass-auto-updates/electron/renderer/index.js index 99a0eb5280b..955742c8fa6 100644 --- a/packages/compass-auto-updates/electron/renderer/index.js +++ b/packages/compass-auto-updates/electron/renderer/index.js @@ -55,7 +55,7 @@ remote.getCurrentWebContents().send('app:update-available', { // // Data service initialization and connection. // import Connection from 'mongodb-connection-model'; -// import { DataService } from 'mongodb-data-service'; +// import { DataServiceImpl } from 'mongodb-data-service'; // // const connection = new Connection({ // hostname: '127.0.0.1', @@ -65,7 +65,7 @@ remote.getCurrentWebContents().send('app:update-available', { // mongodb_username: '', // mongodb_password: '' // }); -// const dataService = new DataService(connection); +// const dataService = new DataServiceImpl(connection); // // appRegistry.emit('data-service-initialized', dataService); // dataService.connect((error, ds) => { diff --git a/packages/compass-crud/electron/renderer/index.js b/packages/compass-crud/electron/renderer/index.js index 73cfe8f4dcd..2135467469c 100644 --- a/packages/compass-crud/electron/renderer/index.js +++ b/packages/compass-crud/electron/renderer/index.js @@ -86,7 +86,7 @@ render(ConnectedDocumentList); // // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', @@ -94,7 +94,7 @@ const connection = new Connection({ ns: DB, mongodb_database_name: 'admin' }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); appRegistry.emit('data-service-initialized', dataService); diff --git a/packages/compass-database/electron/renderer/index.js b/packages/compass-database/electron/renderer/index.js index 145a2d32692..94e2adeb3df 100644 --- a/packages/compass-database/electron/renderer/index.js +++ b/packages/compass-database/electron/renderer/index.js @@ -58,7 +58,7 @@ render(DatabasePlugin); // // Data service initialization and connection. // import Connection from 'mongodb-connection-model'; -// import { DataService } from 'mongodb-data-service'; +// import { DataServiceImpl } from 'mongodb-data-service'; // // const connection = new Connection({ // hostname: '127.0.0.1', @@ -68,7 +68,7 @@ render(DatabasePlugin); // mongodb_username: '', // mongodb_password: '' // }); -// const dataService = new DataService(connection); +// const dataService = new DataServiceImpl(connection); // // appRegistry.emit('data-service-initialized', dataService); // dataService.connect((error, ds) => { diff --git a/packages/compass-deployment-awareness/electron/renderer/index.js b/packages/compass-deployment-awareness/electron/renderer/index.js index 23c6d08d638..674d6aa01d4 100644 --- a/packages/compass-deployment-awareness/electron/renderer/index.js +++ b/packages/compass-deployment-awareness/electron/renderer/index.js @@ -10,7 +10,7 @@ import app from 'hadron-app'; import AppRegistry from 'hadron-app-registry'; import { AppContainer } from 'react-hot-loader'; import DeploymentAwarenessPlugin, { activate } from '../../src/index.js'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; import Connection from 'mongodb-connection-model'; const appRegistry = new AppRegistry(); @@ -50,7 +50,7 @@ const render = Component => { // Render our plugin - don't remove the following line. render(DeploymentAwarenessPlugin); -const dataService = new DataService(CONNECTION); +const dataService = new DataServiceImpl(CONNECTION); dataService.connect((error, ds) => { global.hadronApp.dataService = ds; diff --git a/packages/compass-explain-plan/electron/renderer/index.js b/packages/compass-explain-plan/electron/renderer/index.js index 15c47fea1cb..fe232e8e88f 100644 --- a/packages/compass-explain-plan/electron/renderer/index.js +++ b/packages/compass-explain-plan/electron/renderer/index.js @@ -79,14 +79,14 @@ render(ExplainPlanPlugin); // Data service initialization and connection import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', port: 27017, ns: 'admin' }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); appRegistry.emit('data-service-initialized', dataService); diff --git a/packages/compass-export-to-language/electron/renderer/index.js b/packages/compass-export-to-language/electron/renderer/index.js index 04e5c9ee1b0..60fb906ca8c 100644 --- a/packages/compass-export-to-language/electron/renderer/index.js +++ b/packages/compass-export-to-language/electron/renderer/index.js @@ -53,13 +53,13 @@ render(ExportToLanguageStandalone); // // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', port: 27017 }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); dataService.connect((error, ds) => { appRegistry.emit('data-service-connected', error, ds); diff --git a/packages/compass-field-store/electron/renderer/index.js b/packages/compass-field-store/electron/renderer/index.js index 8f316966da3..c5211795148 100644 --- a/packages/compass-field-store/electron/renderer/index.js +++ b/packages/compass-field-store/electron/renderer/index.js @@ -48,7 +48,7 @@ render(ComponentPlugin); // // Data service initialization and connection. // import Connection from 'mongodb-connection-model'; -// import { DataService } from 'mongodb-data-service'; +// import { DataServiceImpl } from 'mongodb-data-service'; // // const connection = new Connection({ // hostname: '127.0.0.1', @@ -58,7 +58,7 @@ render(ComponentPlugin); // mongodb_username: '', // mongodb_password: '' // }); -// const dataService = new DataService(connection); +// const dataService = new DataServiceImpl(connection); // // appRegistry.emit('data-service-initialized', dataService); // dataService.connect((error, ds) => { diff --git a/packages/compass-import-export/src/modules/export.spec.js b/packages/compass-import-export/src/modules/export.spec.js index f1bca66252d..1476e2b2b46 100644 --- a/packages/compass-import-export/src/modules/export.spec.js +++ b/packages/compass-import-export/src/modules/export.spec.js @@ -9,7 +9,7 @@ import AppRegistry from 'hadron-app-registry'; import FILE_TYPES from '../constants/file-types'; import reducer, * as actions from './export'; import store from '../stores/export-store'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; import { promisify } from 'util'; import { once } from 'events'; import { dataServiceConnected, globalAppRegistryActivated } from './compass'; @@ -21,7 +21,7 @@ describe('export [module]', function () { describe('#reducer', function () { context('#startExport', function () { const globalAppRegistry = new AppRegistry(); - const dataService = new DataService({ + const dataService = new DataServiceImpl({ connectionString: 'mongodb://localhost:27018/local', }); const createCollection = promisify(dataService.createCollection).bind( diff --git a/packages/compass-instance/electron/renderer/index.js b/packages/compass-instance/electron/renderer/index.js index a38a2bc106a..a38b1c0c744 100644 --- a/packages/compass-instance/electron/renderer/index.js +++ b/packages/compass-instance/electron/renderer/index.js @@ -50,7 +50,7 @@ render(InstancePlugin); // // Data service initialization and connection. // import Connection from 'mongodb-connection-model'; -// import { DataService } from 'mongodb-data-service'; +// import { DataServiceImpl } from 'mongodb-data-service'; // // const connection = new Connection({ // hostname: '127.0.0.1', @@ -60,7 +60,7 @@ render(InstancePlugin); // mongodb_username: '', // mongodb_password: '' // }); -// const dataService = new DataService(connection); +// const dataService = new DataServiceImpl(connection); // // appRegistry.emit('data-service-initialized', dataService); // dataService.connect((error, ds) => { diff --git a/packages/compass-schema-validation/electron/renderer/index.js b/packages/compass-schema-validation/electron/renderer/index.js index b4e0222dd62..33bd60a5f24 100644 --- a/packages/compass-schema-validation/electron/renderer/index.js +++ b/packages/compass-schema-validation/electron/renderer/index.js @@ -61,14 +61,14 @@ render(CompassSchemaValidationPlugin); // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', port: 27017, ns: 'admin' }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); dataService.connect((error, ds) => { setDataProvider(store, error, ds); diff --git a/packages/compass-server-version/electron/renderer/index.js b/packages/compass-server-version/electron/renderer/index.js index dd0e555b46f..0a50f10432a 100644 --- a/packages/compass-server-version/electron/renderer/index.js +++ b/packages/compass-server-version/electron/renderer/index.js @@ -59,7 +59,7 @@ render(ServerVersionPlugin); // // Data service initialization and connection. // import Connection from 'mongodb-connection-model'; -// import { DataService } from 'mongodb-data-service'; +// import { DataServiceImpl } from 'mongodb-data-service'; // // const connection = new Connection({ // hostname: '127.0.0.1', @@ -69,7 +69,7 @@ render(ServerVersionPlugin); // mongodb_username: '', // mongodb_password: '' // }); -// const dataService = new DataService(connection); +// const dataService = new DataServiceImpl(connection); // // appRegistry.emit('data-service-initialized', dataService); // dataService.connect((error, ds) => { diff --git a/packages/compass-serverstats/electron/renderer/index.js b/packages/compass-serverstats/electron/renderer/index.js index aa1a0c47277..93a776f05a5 100644 --- a/packages/compass-serverstats/electron/renderer/index.js +++ b/packages/compass-serverstats/electron/renderer/index.js @@ -5,7 +5,7 @@ import 'mongodb-compass/src/app/styles/index.less'; const React = require('react'); const ReactDOM = require('react-dom'); -const { DataService } = require('mongodb-data-service'); +const { DataServiceImpl } = require('mongodb-data-service'); const Connection = require('mongodb-connection-model'); const app = require('hadron-app'); const { AppRegistry } = require('hadron-app-registry'); @@ -38,7 +38,7 @@ global.hadronApp.appRegistry.registerStore( global.hadronApp.appRegistry.registerStore('RTSS.TopStore', TopStore); global.hadronApp.instance = { host: { cpu_cores: 4 } }; -const dataService = new DataService(CONNECTION); +const dataService = new DataServiceImpl(CONNECTION); dataService.connect((error, ds) => { global.hadronApp.appRegistry.onActivated(); global.hadronApp.appRegistry.emit('data-service-connected', error, ds); diff --git a/packages/compass-sidebar/electron/renderer/index.js b/packages/compass-sidebar/electron/renderer/index.js index 01bc5da86b6..a624ffa4dbc 100644 --- a/packages/compass-sidebar/electron/renderer/index.js +++ b/packages/compass-sidebar/electron/renderer/index.js @@ -58,7 +58,7 @@ render(SidebarPlugin); // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', @@ -70,7 +70,7 @@ const connection = new Connection({ readPreference: 'primaryPreferred', attributes: { hostanme: 'localhost' } }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); global.hadronApp.instance.genuineMongoDB = { isGenuine: false, dbType: 'cosmos' }; diff --git a/packages/compass-ssh-tunnel-status/electron/renderer/index.js b/packages/compass-ssh-tunnel-status/electron/renderer/index.js index 297434a1295..dd6af0c092e 100644 --- a/packages/compass-ssh-tunnel-status/electron/renderer/index.js +++ b/packages/compass-ssh-tunnel-status/electron/renderer/index.js @@ -46,7 +46,7 @@ render(SshTunnelStatusPlugin); // // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: '127.0.0.1', @@ -54,7 +54,7 @@ const connection = new Connection({ ns: 'databaseName', mongodb_database_name: 'admin' }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); appRegistry.emit('data-service-initialized', dataService); dataService.connect((error, ds) => { diff --git a/packages/compass/test/unit/support/mock-data-service.js b/packages/compass/test/unit/support/mock-data-service.js index d475c08eb40..25256616081 100644 --- a/packages/compass/test/unit/support/mock-data-service.js +++ b/packages/compass/test/unit/support/mock-data-service.js @@ -1,7 +1,7 @@ const sinon = require('sinon'); const app = require('hadron-app'); const _ = require('lodash'); -const { DataService } = require('mongodb-data-service'); +const { DataServiceImpl } = require('mongodb-data-service'); /** * wraps the mocked callbacks and returns either cb(err) or cb(null, res) @@ -65,7 +65,7 @@ function callbackWrapper(cb, err, res) { const mockDataService = function(errors, results) { errors = errors || {}; results = results || {}; - const dataService = new DataService({}); + const dataService = new DataServiceImpl({}); // extract all method names from real data-service const methodNames = Object.getOwnPropertyNames(Object.getPrototypeOf(dataService)); // create new object with all methods, but mock spy functions that return diff --git a/packages/data-service/src/connect.ts b/packages/data-service/src/connect.ts index 51d9b20597d..18a5d09804c 100644 --- a/packages/data-service/src/connect.ts +++ b/packages/data-service/src/connect.ts @@ -1,10 +1,11 @@ import type { ConnectionOptions } from './connection-options'; -import DataService from './data-service'; +import type { DataService } from './data-service'; +import { DataServiceImpl } from './data-service'; export default async function connect( connectionOptions: ConnectionOptions ): Promise { - const dataService = new DataService(connectionOptions); + const dataService = new DataServiceImpl(connectionOptions); await dataService.connect(); return dataService; } diff --git a/packages/data-service/src/data-service.spec.ts b/packages/data-service/src/data-service.spec.ts index 649222c0847..4b6e56d6ff3 100644 --- a/packages/data-service/src/data-service.spec.ts +++ b/packages/data-service/src/data-service.spec.ts @@ -6,7 +6,8 @@ import { MongoClient } from 'mongodb'; import sinon from 'sinon'; import { v4 as uuid } from 'uuid'; -import DataService from './data-service'; +import type { DataService } from './data-service'; +import { DataServiceImpl } from './data-service'; import type { ConnectionFleOptions, ConnectionOptions, @@ -47,7 +48,7 @@ describe('DataService', function () { mongoClient = new MongoClient(connectionOptions.connectionString); await mongoClient.connect(); - dataService = new DataService(connectionOptions); + dataService = new DataServiceImpl(connectionOptions); await dataService.connect(); }); @@ -85,18 +86,18 @@ describe('DataService', function () { }); it('returns false when not connected initially', function () { - dataServiceIsConnected = new DataService(connectionOptions); + dataServiceIsConnected = new DataServiceImpl(connectionOptions); expect(dataServiceIsConnected.isConnected()).to.equal(false); }); it('returns true if client is connected', async function () { - dataServiceIsConnected = new DataService(connectionOptions); + dataServiceIsConnected = new DataServiceImpl(connectionOptions); await dataServiceIsConnected.connect(); expect(dataServiceIsConnected.isConnected()).to.equal(true); }); it('returns false if client is disconnected', async function () { - dataServiceIsConnected = new DataService(connectionOptions); + dataServiceIsConnected = new DataServiceImpl(connectionOptions); await dataServiceIsConnected.connect(); await dataServiceIsConnected.disconnect(); @@ -107,7 +108,7 @@ describe('DataService', function () { describe('#setupListeners', function () { it('emits log events for MongoClient heartbeat events', function () { - const dataService: any = new DataService(null as any); + const dataService: any = new DataServiceImpl(null as any); const client: Pick = new EventEmitter() as any; const logEntries: any[] = []; @@ -1017,7 +1018,7 @@ describe('DataService', function () { }); it("it returns null when a topology description event hasn't yet occured", function () { - const testService = new DataService(connectionOptions); + const testService = new DataServiceImpl(connectionOptions); expect(testService.getLastSeenTopology()).to.equal(null); }); }); @@ -1364,7 +1365,9 @@ describe('DataService', function () { }, }, }; - expect(dataService._csfleLogInformation(fleOptions)).to.deep.equal({ + expect( + (dataService as DataServiceImpl)._csfleLogInformation(fleOptions) + ).to.deep.equal({ storeCredentials: false, keyVaultNamespace: 'abc.def', schemaMapNamespaces: ['a.b'], @@ -1376,7 +1379,7 @@ describe('DataService', function () { context('with mocked client', function () { function createDataServiceWithMockedClient(clientConfig) { - const dataService = new DataService({ + const dataService = new DataServiceImpl({ connectionString: 'mongodb://localhost:27020', }); const client = createMongoClientMock(clientConfig); diff --git a/packages/data-service/src/data-service.ts b/packages/data-service/src/data-service.ts index 70d761786e1..e2d40cf4bfd 100644 --- a/packages/data-service/src/data-service.ts +++ b/packages/data-service/src/data-service.ts @@ -100,7 +100,594 @@ interface CompassClientSession extends ClientSession { [kSessionClientType]: ClientType; } -class DataService extends EventEmitter { +export interface DataServiceEventMap { + serverDescriptionChanged: (evt: ServerDescriptionChangedEvent) => void; + serverOpening: (evt: ServerOpeningEvent) => void; + serverClosed: (evt: ServerClosedEvent) => void; + topologyOpening: (evt: TopologyOpeningEvent) => void; + topologyClosed: (evt: TopologyClosedEvent) => void; + topologyDescriptionChanged: (evt: TopologyDescriptionChangedEvent) => void; + serverHeartbeatSucceeded: (evt: ServerHeartbeatSucceededEvent) => void; + serverHeartbeatFailedEvent: (evt: ServerHeartbeatFailedEvent) => void; +} +export interface DataService { + // TypeScript uses something like this itself for its EventTarget definitions. + on( + event: K, + listener: DataServiceEventMap[K] + ): this; + once( + event: K, + listener: DataServiceEventMap[K] + ): this; + emit( + event: K, + ...args: DataServiceEventMap[K] extends (...args: infer P) => any + ? P + : never + ): unknown; + + getMongoClientConnectionOptions(): + | { url: string; options: MongoClientOptions } + | undefined; + getConnectionOptions(): Readonly; + getConnectionString(): ConnectionStringUrl; + getReadPreference(): ReadPreferenceLike; + setCSFLEEnabled(enabled: boolean): void; + + /** + * Get the kitchen sink information about a collection. + * + * @param ns - The namespace. + * @param options - The options. + * @param callback - The callback. + */ + collection(ns: string, options: unknown, callback: Callback): void; + + /** + * Get the stats for all collections in the database. + * + * @param databaseName - The database name. + * @param callback - The callback. + */ + collections( + databaseName: string, + callback: Callback + ): void; + + /** + * Get the stats for a collection. + * + * @param databaseName - The database name. + * @param collectionName - The collection name. + * @param callback - The callback. + */ + collectionStats( + databaseName: string, + collectionName: string, + callback: Callback + ): void; + + /** + * Returns normalized collection info provided by listCollection command for a + * specific collection + * + * @param dbName database name + * @param collName collection name + */ + collectionInfo( + dbName: string, + collName: string + ): Promise | null>; + + /** + * Execute a command. + * + * @param databaseName - The db name. + * @param comm - The command. + * @param callback - The callback. + */ + command( + databaseName: string, + comm: Document, + callback: Callback + ): void; + + /** + * Is the data service allowed to perform write operations. + * + * @returns If the data service is writable. + */ + isWritable(): boolean; + + /** + * Is the data service connected to a mongos. + * + * @returns If the data service is connected to a mongos. + */ + isMongos(): boolean; + + /** + * Return the current topology type, as reported by the driver's topology + * update events. + * + * @returns The current topology type. + */ + currentTopologyType(): TopologyType; + + connectionStatus(): Promise; + + /** + * List all collections for a database. + */ + listCollections( + databaseName: string, + filter?: Document, + options?: { + nameOnly?: true; + privileges?: + | ConnectionStatusWithPrivileges['authInfo']['authenticatedUserPrivileges'] + | null; + } + ): Promise[]>; + + /** + * List all databases on the currently connected instance. + */ + listDatabases(options?: { + nameOnly?: true; + privileges?: + | ConnectionStatusWithPrivileges['authInfo']['authenticatedUserPrivileges'] + | null; + roles?: + | ConnectionStatusWithPrivileges['authInfo']['authenticatedUserRoles'] + | null; + }): Promise<{ _id: string; name: string }[]>; + + connect(): Promise; + + /** + * Count the number of documents in the collection. + * + * @param ns - The namespace to search on. + * @param options - The query options. + * @param callback - The callback function. + */ + estimatedCount( + ns: string, + options: EstimatedDocumentCountOptions, + callback: Callback + ): void; + + /** + * Count the number of documents in the collection for the provided filter + * and options. + * + * @param ns - The namespace to search on. + * @param options - The query options. + * @param callback - The callback function. + */ + count( + ns: string, + filter: Filter, + options: CountDocumentsOptions, + callback: Callback + ): void; + + /** + * Creates a collection + * + * @param ns - The namespace. + * @param options - The options. + * @param callback - The callback. + */ + createCollection( + ns: string, + options: CreateCollectionOptions, + callback: Callback> + ): void; + + /** + * Creates an index + * + * @param ns - The namespace. + * @param spec - The index specification. + * @param options - The options. + * @param callback - The callback. + */ + createIndex( + ns: string, + spec: IndexSpecification, + options: CreateIndexesOptions, + callback: Callback + ): void; + + /** + * Get the kitchen sink information about a database and all its collections. + * + * @param name - The database name. + * @param options - The query options. + * @param callback - The callback. + */ + database(name: string, options: unknown, callback: Callback): void; + + /** + * Delete a single document from the collection. + * + * @param ns - The namespace. + * @param filter - The filter. + * @param options - The options. + * @param callback - The callback. + */ + deleteOne( + ns: string, + filter: Filter, + options: DeleteOptions, + callback: Callback + ): void; + + /** + * Deletes multiple documents from a collection. + * + * @param ns - The namespace. + * @param filter - The filter. + * @param options - The options. + * @param callback - The callback. + */ + deleteMany( + ns: string, + filter: Filter, + options: DeleteOptions, + callback: Callback + ): void; + + /** + * Disconnect the service. + * @param callback - The callback. + */ + disconnect(): Promise; + + /** + * Drops a collection from a database + * + * @param ns - The namespace. + * @param callback - The callback. + */ + dropCollection(ns: string, callback: Callback): void; + + /** + * Drops a database + * + * @param name - The database name. + * @param callback - The callback. + */ + dropDatabase(name: string, callback: Callback): void; + + /** + * Drops an index from a collection + * + * @param ns - The namespace. + * @param name - The index name. + * @param callback - The callback. + */ + dropIndex(ns: string, name: string, callback: Callback): void; + + /** + * Execute an aggregation framework pipeline with the provided options on the + * collection. + * + * + * @param ns - The namespace to search on. + * @param pipeline - The aggregation pipeline. + * @param options - The aggregation options. + * @param callback - The callback function. + */ + aggregate( + ns: string, + pipeline: Document[], + options?: AggregateOptions + ): AggregationCursor; + aggregate( + ns: string, + pipeline: Document[], + callback: Callback + ): void; + aggregate( + ns: string, + pipeline: Document[], + options: AggregateOptions | undefined, + callback: Callback + ): void; + + /** + * Find documents for the provided filter and options on the collection. + * + * @param ns - The namespace to search on. + * @param filter - The query filter. + * @param options - The query options. + * @param callback - The callback function. + */ + find( + ns: string, + filter: Filter, + options: FindOptions, + callback: Callback + ): void; + + /** + * Fetch documents for the provided filter and options on the collection. + * + * @param ns - The namespace to search on. + * @param filter - The query filter. + * @param options - The query options. + */ + fetch(ns: string, filter: Filter, options: FindOptions): FindCursor; + + /** + * Find one document and replace it with the replacement. + * + * @param ns - The namespace to search on. + * @param filter - The filter. + * @param replacement - The replacement doc. + * @param options - The query options. + * @param callback - The callback. + */ + findOneAndReplace( + ns: string, + filter: Filter, + replacement: Document, + options: FindOneAndReplaceOptions, + callback: Callback + ): void; + + /** + * Find one document and update it with the update operations. + * + * @param ns - The namespace to search on. + * @param filter - The filter. + * @param update - The update operations doc. + * @param options - The query options. + * @param callback - The callback. + */ + findOneAndUpdate( + ns: string, + filter: Filter, + update: Document, + options: FindOneAndUpdateOptions, + callback: Callback + ): void; + + /** + * Returns explain plan for the provided filter and options on the collection. + * + * @param ns - The namespace to search on. + * @param filter - The query filter. + * @param options - The query options. + * @param callback - The callback function. + */ + explain( + ns: string, + filter: Filter, + options: FindOptions, + callback: Callback + ): void; + + /** + * Get the indexes for the collection. + * + * @param ns - The collection namespace. + * @param options - The options (unused). + * @param callback - The callback. + */ + indexes(ns: string, options: unknown, callback: Callback): void; + + /** + * Get the current instance details. + */ + instance(): Promise; + + /** + * Insert a single document into the database. + * + * @param ns - The namespace. + * @param doc - The document to insert. + * @param options - The options. + * @param callback - The callback. + */ + insertOne( + ns: string, + doc: Document, + options: InsertOneOptions, + callback: Callback> + ): void; + + /** + * Inserts multiple documents into the collection. + * + * @param ns - The namespace. + * @param docs - The documents to insert. + * @param options - The options. + * @param callback - The callback. + */ + insertMany( + ns: string, + docs: Document[], + options: BulkWriteOptions, + callback: Callback> + ): void; + + /** + * Inserts multiple documents into the collection. + * + * @param ns - The namespace. + * @param docs - The documents to insert. + * @param options - The options. + * @deprecated + */ + putMany( + ns: string, + docs: Document[], + options: BulkWriteOptions + ): Promise>; + + /** + * Update a collection. + * + * @param ns - The namespace. + * @param flags - The flags. + * @param callback - The callback. + */ + updateCollection( + ns: string, + // Collection name to update that will be passed to the collMod command will + // be derived from the provided namespace, this is why we are explicitly + // prohibiting to pass collMod flag here + flags: Document & { collMod?: never }, + callback: Callback + ): void; + + /** + * Update a single document in the collection. + * + * @param ns - The namespace. + * @param filter - The filter. + * @param update - The update. + * @param options - The options. + * @param callback - The callback. + */ + updateOne( + ns: string, + filter: Filter, + update: Document | UpdateFilter, + options: UpdateOptions, + callback: Callback + ): void; + + /** + * Updates multiple documents in the collection. + * + * @param ns - The namespace. + * @param filter - The filter. + * @param update - The update. + * @param options - The options. + * @param callback - The callback. + */ + updateMany( + ns: string, + filter: Filter, + update: UpdateFilter, + options: UpdateOptions, + callback: Callback + ): void; + + /** + * Returns the results of currentOp. + * + * @param includeAll - if true also list currently idle operations in the result. + * @param callback - The callback. + */ + currentOp(includeAll: boolean, callback: Callback): void; + + /** + * Returns the most recent topology description from the server's SDAM events. + * https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-monitoring.rst#events + */ + getLastSeenTopology(): null | TopologyDescription; + + /** + * Returns the result of serverStats. + */ + serverstats(callback: Callback): void; + + /** + * Returns the result of top. + * + * @param callback - the callback. + */ + top(callback: Callback): void; + + /** + * Create a new view. + * + * @param name - The collectionName for the view. + * @param sourceNs - The source `.` for the view. + * @param pipeline - The agggregation pipeline for the view. + * @param options - Options e.g. collation. + * @param callback - The callback. + */ + createView( + name: string, + sourceNs: string, + pipeline: Document[], + options: CreateCollectionOptions, + callback: Callback> + ): void; + + /** + * Update an existing view. + * + * @param name - The collectionName for the view. + * @param sourceNs - The source `.` for the view. + * @param pipeline - The agggregation pipeline for the view. + * @param options - Options e.g. collation. + * @param callback - The callback. + */ + updateView( + name: string, + sourceNs: string, + pipeline: Document[], + options: Document, + callback: Callback + ): void; + + /** + * Convenience for dropping a view as a passthrough to `dropCollection()`. + * + * @param ns - The namespace. + * @param callback - The callback. + */ + dropView(ns: string, callback: Callback): void; + + /** + * Sample documents from the collection. + * + * @param ns - The namespace to sample. + * @param args - The sampling options. + * @param options - Driver options (ie. maxTimeMs, session, batchSize ...) + */ + sample( + ns: string, + args?: { query?: Filter; size?: number; fields?: Document }, + options?: AggregateOptions + ): AggregationCursor; + + /** + * Create a ClientSession that can be passed to commands. + */ + startSession(clientType: ClientType): CompassClientSession; + + /** + * Kill a session and terminate all in progress operations. + * @param clientSession - a ClientSession (can be created with startSession()) + */ + killSessions( + sessions: CompassClientSession | CompassClientSession[] + ): Promise; + + isConnected(): boolean; + + /** + * Get the stats for a database. + * + * @param name - The database name. + * @param callback - The callback. + */ + databaseStats( + name: string + ): Promise & { name: string }>; +} + +export class DataServiceImpl extends EventEmitter implements DataService { private readonly _connectionOptions: Readonly; private _isConnecting = false; private _mongoClientConnectionOptions?: { @@ -164,13 +751,6 @@ class DataService extends EventEmitter { this._useCRUDClient = enabled; } - /** - * Get the kitchen sink information about a collection. - * - * @param ns - The namespace. - * @param options - The options. - * @param callback - The callback. - */ collection(ns: string, options: unknown, callback: Callback): void { // @ts-expect-error async typings are not nice :( async.parallel( @@ -195,12 +775,6 @@ class DataService extends EventEmitter { ); } - /** - * Get the stats for all collections in the database. - * - * @param databaseName - The database name. - * @param callback - The callback. - */ collections( databaseName: string, callback: Callback @@ -225,13 +799,6 @@ class DataService extends EventEmitter { }); } - /** - * Get the stats for a collection. - * - * @param databaseName - The database name. - * @param collectionName - The collection name. - * @param callback - The callback. - */ collectionStats( databaseName: string, collectionName: string, @@ -260,13 +827,6 @@ class DataService extends EventEmitter { }); } - /** - * Returns normalized collection info provided by listCollection command for a - * specific collection - * - * @param dbName database name - * @param collName collection name - */ async collectionInfo( dbName: string, collName: string @@ -279,13 +839,6 @@ class DataService extends EventEmitter { } } - /** - * Execute a command. - * - * @param databaseName - The db name. - * @param comm - The command. - * @param callback - The callback. - */ command( databaseName: string, comm: Document, @@ -301,30 +854,14 @@ class DataService extends EventEmitter { }); } - /** - * Is the data service allowed to perform write operations. - * - * @returns If the data service is writable. - */ isWritable(): boolean { return this._isWritable; } - /** - * Is the data service connected to a mongos. - * - * @returns If the data service is connected to a mongos. - */ isMongos(): boolean { return this._topologyType === 'Sharded'; - } - - /** - * Return the current topology type, as reported by the driver's topology - * update events. - * - * @returns The current topology type. - */ + } + currentTopologyType(): TopologyType { return this._topologyType; } @@ -377,9 +914,6 @@ class DataService extends EventEmitter { return authenticatedUserRoles; } - /** - * List all collections for a database. - */ async listCollections( databaseName: string, filter: Document = {}, @@ -469,9 +1003,6 @@ class DataService extends EventEmitter { } } - /** - * List all databases on the currently connected instance. - */ async listDatabases({ nameOnly, privileges = null, @@ -621,13 +1152,6 @@ class DataService extends EventEmitter { } } - /** - * Count the number of documents in the collection. - * - * @param ns - The namespace to search on. - * @param options - The query options. - * @param callback - The callback function. - */ estimatedCount( ns: string, options: EstimatedDocumentCountOptions, @@ -647,14 +1171,6 @@ class DataService extends EventEmitter { ); } - /** - * Count the number of documents in the collection for the provided filter - * and options. - * - * @param ns - The namespace to search on. - * @param options - The query options. - * @param callback - The callback function. - */ count( ns: string, filter: Filter, @@ -676,13 +1192,6 @@ class DataService extends EventEmitter { ); } - /** - * Creates a collection - * - * @param ns - The namespace. - * @param options - The options. - * @param callback - The callback. - */ createCollection( ns: string, options: CreateCollectionOptions, @@ -706,14 +1215,6 @@ class DataService extends EventEmitter { }); } - /** - * Creates an index - * - * @param ns - The namespace. - * @param spec - The index specification. - * @param options - The options. - * @param callback - The callback. - */ createIndex( ns: string, spec: IndexSpecification, @@ -735,13 +1236,6 @@ class DataService extends EventEmitter { }); } - /** - * Get the kitchen sink information about a database and all its collections. - * - * @param name - The database name. - * @param options - The query options. - * @param callback - The callback. - */ database(name: string, options: unknown, callback: Callback): void { const asyncColls = promisify(this.collections.bind(this)); @@ -756,14 +1250,6 @@ class DataService extends EventEmitter { ); } - /** - * Delete a single document from the collection. - * - * @param ns - The namespace. - * @param filter - The filter. - * @param options - The options. - * @param callback - The callback. - */ deleteOne( ns: string, filter: Filter, @@ -785,14 +1271,6 @@ class DataService extends EventEmitter { }); } - /** - * Deletes multiple documents from a collection. - * - * @param ns - The namespace. - * @param filter - The filter. - * @param options - The options. - * @param callback - The callback. - */ deleteMany( ns: string, filter: Filter, @@ -818,10 +1296,6 @@ class DataService extends EventEmitter { ); } - /** - * Disconnect the service. - * @param callback - The callback. - */ async disconnect(): Promise { log.info(mongoLogId(1_001_000_016), this._logCtx(), 'Disconnecting'); @@ -844,12 +1318,6 @@ class DataService extends EventEmitter { } } - /** - * Drops a collection from a database - * - * @param ns - The namespace. - * @param callback - The callback. - */ dropCollection(ns: string, callback: Callback): void { const logop = this._startLogOp( mongoLogId(1_001_000_059), @@ -866,12 +1334,6 @@ class DataService extends EventEmitter { }); } - /** - * Drops a database - * - * @param name - The database name. - * @param callback - The callback. - */ dropDatabase(name: string, callback: Callback): void { const logop = this._startLogOp( mongoLogId(1_001_000_040), @@ -890,13 +1352,6 @@ class DataService extends EventEmitter { }); } - /** - * Drops an index from a collection - * - * @param ns - The namespace. - * @param name - The index name. - * @param callback - The callback. - */ dropIndex(ns: string, name: string, callback: Callback): void { const logop = this._startLogOp( mongoLogId(1_001_000_060), @@ -913,16 +1368,6 @@ class DataService extends EventEmitter { }); } - /** - * Execute an aggregation framework pipeline with the provided options on the - * collection. - * - * - * @param ns - The namespace to search on. - * @param pipeline - The aggregation pipeline. - * @param options - The aggregation options. - * @param callback - The callback function. - */ aggregate( ns: string, pipeline: Document[], @@ -963,14 +1408,6 @@ class DataService extends EventEmitter { return cursor; } - /** - * Find documents for the provided filter and options on the collection. - * - * @param ns - The namespace to search on. - * @param filter - The query filter. - * @param options - The query options. - * @param callback - The callback function. - */ find( ns: string, filter: Filter, @@ -991,13 +1428,6 @@ class DataService extends EventEmitter { }); } - /** - * Fetch documents for the provided filter and options on the collection. - * - * @param ns - The namespace to search on. - * @param filter - The query filter. - * @param options - The query options. - */ fetch( ns: string, filter: Filter, @@ -1014,15 +1444,6 @@ class DataService extends EventEmitter { return this._collection(ns, 'CRUD').find(filter, options); } - /** - * Find one document and replace it with the replacement. - * - * @param ns - The namespace to search on. - * @param filter - The filter. - * @param replacement - The replacement doc. - * @param options - The query options. - * @param callback - The callback. - */ findOneAndReplace( ns: string, filter: Filter, @@ -1050,15 +1471,6 @@ class DataService extends EventEmitter { ); } - /** - * Find one document and update it with the update operations. - * - * @param ns - The namespace to search on. - * @param filter - The filter. - * @param update - The update operations doc. - * @param options - The query options. - * @param callback - The callback. - */ findOneAndUpdate( ns: string, filter: Filter, @@ -1086,14 +1498,6 @@ class DataService extends EventEmitter { ); } - /** - * Returns explain plan for the provided filter and options on the collection. - * - * @param ns - The namespace to search on. - * @param filter - The query filter. - * @param options - The query options. - * @param callback - The callback function. - */ explain( ns: string, filter: Filter, @@ -1119,13 +1523,6 @@ class DataService extends EventEmitter { }); } - /** - * Get the indexes for the collection. - * - * @param ns - The collection namespace. - * @param options - The options (unused). - * @param callback - The callback. - */ indexes(ns: string, options: unknown, callback: Callback): void { const logop = this._startLogOp( mongoLogId(1_001_000_047), @@ -1146,9 +1543,6 @@ class DataService extends EventEmitter { ); } - /** - * Get the current instance details. - */ async instance(): Promise { let csfleMode: InstanceDetails['csfleMode']; if (this._crudClient && checkIsCSFLEConnection(this._crudClient)) { @@ -1186,14 +1580,6 @@ class DataService extends EventEmitter { } } - /** - * Insert a single document into the database. - * - * @param ns - The namespace. - * @param doc - The document to insert. - * @param options - The options. - * @param callback - The callback. - */ insertOne( ns: string, doc: Document, @@ -1215,14 +1601,6 @@ class DataService extends EventEmitter { }); } - /** - * Inserts multiple documents into the collection. - * - * @param ns - The namespace. - * @param docs - The documents to insert. - * @param options - The options. - * @param callback - The callback. - */ insertMany( ns: string, docs: Document[], @@ -1247,14 +1625,6 @@ class DataService extends EventEmitter { }); } - /** - * Inserts multiple documents into the collection. - * - * @param ns - The namespace. - * @param docs - The documents to insert. - * @param options - The options. - * @deprecated - */ putMany( ns: string, docs: Document[], @@ -1263,13 +1633,6 @@ class DataService extends EventEmitter { return this._collection(ns, 'CRUD').insertMany(docs, options); } - /** - * Update a collection. - * - * @param ns - The namespace. - * @param flags - The flags. - * @param callback - The callback. - */ updateCollection( ns: string, // Collection name to update that will be passed to the collMod command will @@ -1301,15 +1664,6 @@ class DataService extends EventEmitter { }); } - /** - * Update a single document in the collection. - * - * @param ns - The namespace. - * @param filter - The filter. - * @param update - The update. - * @param options - The options. - * @param callback - The callback. - */ updateOne( ns: string, filter: Filter, @@ -1337,15 +1691,6 @@ class DataService extends EventEmitter { ); } - /** - * Updates multiple documents in the collection. - * - * @param ns - The namespace. - * @param filter - The filter. - * @param update - The update. - * @param options - The options. - * @param callback - The callback. - */ updateMany( ns: string, filter: Filter, @@ -1373,12 +1718,6 @@ class DataService extends EventEmitter { ); } - /** - * Returns the results of currentOp. - * - * @param includeAll - if true also list currently idle operations in the result. - * @param callback - The callback. - */ currentOp(includeAll: boolean, callback: Callback): void { const logop = this._startLogOp( mongoLogId(1_001_000_053), @@ -1410,17 +1749,10 @@ class DataService extends EventEmitter { }); } - /** - * Returns the most recent topology description from the server's SDAM events. - * https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-discovery-and-monitoring-monitoring.rst#events - */ getLastSeenTopology(): null | TopologyDescription { return this._lastSeenTopology; } - /** - * Returns the result of serverStats. - */ serverstats(callback: Callback): void { const logop = this._startLogOp( mongoLogId(1_001_000_061), @@ -1441,11 +1773,6 @@ class DataService extends EventEmitter { }); } - /** - * Returns the result of top. - * - * @param callback - the callback. - */ top(callback: Callback): void { const logop = this._startLogOp(mongoLogId(1_001_000_062), 'Running top'); this._initializedClient('META') @@ -1461,15 +1788,6 @@ class DataService extends EventEmitter { }); } - /** - * Create a new view. - * - * @param name - The collectionName for the view. - * @param sourceNs - The source `.` for the view. - * @param pipeline - The agggregation pipeline for the view. - * @param options - Options e.g. collation. - * @param callback - The callback. - */ createView( name: string, sourceNs: string, @@ -1503,15 +1821,6 @@ class DataService extends EventEmitter { }); } - /** - * Update an existing view. - * - * @param name - The collectionName for the view. - * @param sourceNs - The source `.` for the view. - * @param pipeline - The agggregation pipeline for the view. - * @param options - Options e.g. collation. - * @param callback - The callback. - */ updateView( name: string, sourceNs: string, @@ -1548,23 +1857,10 @@ class DataService extends EventEmitter { }); } - /** - * Convenience for dropping a view as a passthrough to `dropCollection()`. - * - * @param ns - The namespace. - * @param callback - The callback. - */ dropView(ns: string, callback: Callback): void { this.dropCollection(ns, callback); } - /** - * Sample documents from the collection. - * - * @param ns - The namespace to sample. - * @param args - The sampling options. - * @param options - Driver options (ie. maxTimeMs, session, batchSize ...) - */ sample( ns: string, { @@ -1600,9 +1896,6 @@ class DataService extends EventEmitter { }); } - /** - * Create a ClientSession that can be passed to commands. - */ startSession(clientType: ClientType): CompassClientSession { const session = this._initializedClient( clientType @@ -1611,10 +1904,6 @@ class DataService extends EventEmitter { return session; } - /** - * Kill a session and terminate all in progress operations. - * @param clientSession - a ClientSession (can be created with startSession()) - */ killSessions( sessions: CompassClientSession | CompassClientSession[] ): Promise { @@ -1834,12 +2123,6 @@ class DataService extends EventEmitter { return client; } - /** - * Get the stats for a database. - * - * @param name - The database name. - * @param callback - The callback. - */ async databaseStats( name: string ): Promise & { name: string }> { diff --git a/packages/data-service/src/index.ts b/packages/data-service/src/index.ts index 68be7847471..b526feba6ab 100644 --- a/packages/data-service/src/index.ts +++ b/packages/data-service/src/index.ts @@ -6,7 +6,7 @@ import { promisifyAmpersandMethod, } from './connection-storage'; import { getConnectionTitle } from './connection-title'; -import DataService from './data-service'; +import { DataService, DataServiceImpl } from './data-service'; import { convertConnectionModelToInfo, convertConnectionInfoToModel, @@ -23,6 +23,7 @@ export { ConnectionOptions, ConnectionStorage, DataService, + DataServiceImpl, connect, getConnectionTitle, convertConnectionModelToInfo, diff --git a/packages/databases-collections/electron/renderer/index.js b/packages/databases-collections/electron/renderer/index.js index f3e68995d63..0aedd0ceb93 100644 --- a/packages/databases-collections/electron/renderer/index.js +++ b/packages/databases-collections/electron/renderer/index.js @@ -67,7 +67,7 @@ render(DatabasesCollectionsPlugin); // Data service initialization and connection. import Connection from 'mongodb-connection-model'; -import { DataService } from 'mongodb-data-service'; +import { DataServiceImpl } from 'mongodb-data-service'; const connection = new Connection({ hostname: 'localhost', @@ -75,7 +75,7 @@ const connection = new Connection({ ns: 'admin' }); -const dataService = new DataService(connection); +const dataService = new DataServiceImpl(connection); appRegistry.emit('data-service-initialized', dataService); dataService.connect((error, ds) => {