diff --git a/test/types/connection.test.ts b/test/types/connection.test.ts index a8fabba80c6..2fd9c679646 100644 --- a/test/types/connection.test.ts +++ b/test/types/connection.test.ts @@ -1,26 +1,91 @@ -import { createConnection, Schema, Connection } from 'mongoose'; +import { createConnection, Schema, Collection, Connection, ConnectionSyncIndexesResult, Model } from 'mongoose'; +import * as mongodb from 'mongodb'; +import { expectError, expectType } from 'tsd'; + +expectType(createConnection()); +expectType(createConnection('mongodb://localhost:27017/test')); +expectType(createConnection('mongodb://localhost:27017/test', { appName: 'mongoose' })); +expectType(createConnection('mongodb://localhost:27017/test', { appName: 'mongoose' }, (err, res) => (expectType(res)))); const conn = createConnection(); -conn.model('Test', new Schema({ name: { type: String } })); +expectType>(conn.model('Test', new Schema<{ name: string }>({ name: { type: String } }))); +expectType>(conn.model<{ name: string }>('Test', new Schema({ name: { type: String } }))); + +expectType>(conn.openUri('mongodb://localhost:27017/test')); +expectType>(conn.openUri('mongodb://localhost:27017/test', { bufferCommands: true })); +expectType(conn.openUri('mongodb://localhost:27017/test', { bufferCommands: true }, (err, value) => { expectType(value); })); + +conn.readyState === 0; +conn.readyState === 99; + +expectError(conn.readyState = 0); + +expectType(new Connection()); +expectType>(new Connection().asPromise()); + +expectType>>(conn.createCollection('some')); +expectType(conn.createCollection('some', (err, res) => { + expectType>(res); +})); + +expectType>(conn.dropCollection('some')); +expectType(conn.dropCollection('some', () => { + // do nothing +})); + +expectError(conn.deleteModel()); +expectType(conn.deleteModel('something')); + +expectType>(conn.modelNames()); + +expectType>(createConnection('mongodb://localhost:27017/test').close()); +expectType>(createConnection('mongodb://localhost:27017/test').close(true)); +expectType(createConnection('mongodb://localhost:27017/test').close(() => { + // do nothing. +})); +expectType(createConnection('mongodb://localhost:27017/test').close(true, () => { + // do nothing. +})); +expectType(createConnection('mongodb://localhost:27017/test').close(false, () => { + // do nothing. +})); + +expectType(conn.db); + +expectType(conn.getClient()); +expectType(conn.setClient(new mongodb.MongoClient('mongodb://localhost:27017/test'))); + +expectType>(conn.transaction(async(res) => { + expectType(res); + return 'a'; +})); + +expectError(conn.user = 'invalid'); +expectError(conn.pass = 'invalid'); +expectError(conn.host = 'invalid'); +expectError(conn.port = 'invalid'); + +expectType(conn.collection('test')); +expectType(conn.db.collection('test')); -conn.openUri('mongodb://localhost:27017/test').then(() => console.log('Connected!')); +expectType>(conn.startSession()); +expectType>(conn.startSession({ causalConsistency: true })); +expectType(conn.startSession((err, res) => { expectType(res); })); +expectType(conn.startSession(undefined, (err, res) => { expectType(res); })); +expectType(conn.startSession(null, (err, res) => { expectType(res); })); +expectType(conn.startSession({}, (err, res) => { expectType(res); })); -createConnection('mongodb://localhost:27017/test').asPromise().then((conn: Connection) => { - conn.host; -}); +expectType>(conn.syncIndexes()); +expectType>(conn.syncIndexes({ continueOnError: true })); +expectType>(conn.syncIndexes({ background: true })); -createConnection('mongodb://localhost:27017/test').close(); +expectType(conn.syncIndexes(undefined, (err, value) => { expectType(value); })); +expectType(conn.syncIndexes(null, (err, value) => { expectType(value); })); +expectType(conn.syncIndexes({ continueOnError: true }, (err, value) => { expectType(value); })); +expectType(conn.syncIndexes({ background: true }, (err, value) => { expectType(value); })); -conn.db.collection('Test').findOne({ name: String }).then(doc => console.log(doc)); -conn.collection('Test').findOne({ name: String }).then(doc => console.log(doc)); -conn.syncIndexes({ continueOnError: true }).then(result => { - result['User'].forEach((index) => { - index.includes('name'); - }); - result['Order'].message; - result['Order'].code; -}); -conn.syncIndexes({ continueOnError: false, background: true }).then().catch(err => { - err.errors['Order'].code; -}); \ No newline at end of file +expectType(conn.useDb('test')); +expectType(conn.useDb('test', {})); +expectType(conn.useDb('test', { noListener: true })); +expectType(conn.useDb('test', { useCache: true })); diff --git a/types/Connection.d.ts b/types/Connection.d.ts new file mode 100644 index 00000000000..1d1da6f5433 --- /dev/null +++ b/types/Connection.d.ts @@ -0,0 +1,212 @@ +import mongodb = require('mongodb'); +import events = require('events'); + +declare module 'mongoose' { + + /** + * Connection ready state + * + * - 0 = disconnected + * - 1 = connected + * - 2 = connecting + * - 3 = disconnecting + * - 99 = uninitialized + */ + export enum ConnectionStates { + disconnected = 0, + connected = 1, + connecting = 2, + disconnecting = 3, + uninitialized = 99, + } + + /** Expose connection states for user-land */ + export const STATES: typeof ConnectionStates; + + interface ConnectOptions extends mongodb.MongoClientOptions { + /** Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection. */ + bufferCommands?: boolean; + /** The name of the database you want to use. If not provided, Mongoose uses the database name from connection string. */ + dbName?: string; + /** username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility. */ + user?: string; + /** password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility. */ + pass?: string; + /** Set to false to disable automatic index creation for all models associated with this connection. */ + autoIndex?: boolean; + /** Set to `true` to make Mongoose automatically call `createCollection()` on every model created on this connection. */ + autoCreate?: boolean; + } + + class Connection extends events.EventEmitter { + /** Returns a promise that resolves when this connection successfully connects to MongoDB */ + asPromise(): Promise; + + /** Closes the connection */ + close(force: boolean, callback: CallbackWithoutResult): void; + close(callback: CallbackWithoutResult): void; + close(force?: boolean): Promise; + + /** Retrieves a collection, creating it if not cached. */ + collection(name: string, options?: mongodb.CreateCollectionOptions): Collection; + + /** A hash of the collections associated with this connection */ + readonly collections: { [index: string]: Collection }; + + /** A hash of the global options that are associated with this connection */ + readonly config: any; + + /** The mongodb.Db instance, set when the connection is opened */ + readonly db: mongodb.Db; + + /** + * Helper for `createCollection()`. Will explicitly create the given collection + * with specified options. Used to create [capped collections](https://docs.mongodb.com/manual/core/capped-collections/) + * and [views](https://docs.mongodb.com/manual/core/views/) from mongoose. + */ + createCollection(name: string, options: mongodb.CreateCollectionOptions, callback: Callback>): void; + createCollection(name: string, callback: Callback>): void; + createCollection(name: string, options?: mongodb.CreateCollectionOptions): Promise>; + + /** + * Removes the model named `name` from this connection, if it exists. You can + * use this function to clean up any models you created in your tests to + * prevent OverwriteModelErrors. + */ + deleteModel(name: string): this; + + /** + * Helper for `dropCollection()`. Will delete the given collection, including + * all documents and indexes. + */ + dropCollection(collection: string, callback: CallbackWithoutResult): void; + dropCollection(collection: string): Promise; + + /** + * Helper for `dropDatabase()`. Deletes the given database, including all + * collections, documents, and indexes. + */ + dropDatabase(callback: CallbackWithoutResult): void; + dropDatabase(): Promise; + + /** Gets the value of the option `key`. */ + get(key: string): any; + + /** + * Returns the [MongoDB driver `MongoClient`](http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html) instance + * that this connection uses to talk to MongoDB. + */ + getClient(): mongodb.MongoClient; + + /** + * The host name portion of the URI. If multiple hosts, such as a replica set, + * this will contain the first host name in the URI + */ + readonly host: string; + + /** + * A number identifier for this connection. Used for debugging when + * you have [multiple connections](/docs/connections.html#multiple_connections). + */ + readonly id: number; + + /** + * A [POJO](https://masteringjs.io/tutorials/fundamentals/pojo) containing + * a map from model names to models. Contains all models that have been + * added to this connection using [`Connection#model()`](/docs/api/connection.html#connection_Connection-model). + */ + readonly models: Readonly<{ [index: string]: Model }>; + + /** Defines or retrieves a model. */ + model( + name: string, + schema?: Schema, + collection?: string, + options?: CompileModelOptions + ): U; + model(name: string, schema?: Schema, collection?: string, options?: CompileModelOptions): Model; + + /** Returns an array of model names created on this connection. */ + modelNames(): Array; + + /** The name of the database this connection points to. */ + readonly name: string; + + /** Opens the connection with a URI using `MongoClient.connect()`. */ + openUri(uri: string, options: ConnectOptions, callback: Callback): Connection; + openUri(uri: string, callback: Callback): Connection; + openUri(uri: string, options?: ConnectOptions): Promise; + + /** The password specified in the URI */ + readonly pass: string; + + /** + * The port portion of the URI. If multiple hosts, such as a replica set, + * this will contain the port from the first host name in the URI. + */ + readonly port: number; + + /** Declares a plugin executed on all schemas you pass to `conn.model()` */ + plugin(fn: (schema: S, opts?: any) => void, opts?: O): Connection; + + /** The plugins that will be applied to all models created on this connection. */ + plugins: Array; + + /** + * Connection ready state + * + * - 0 = disconnected + * - 1 = connected + * - 2 = connecting + * - 3 = disconnecting + * - 99 = uninitialized + */ + readonly readyState: ConnectionStates; + + /** Sets the value of the option `key`. */ + set(key: string, value: any): any; + + /** + * Set the [MongoDB driver `MongoClient`](http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html) instance + * that this connection uses to talk to MongoDB. This is useful if you already have a MongoClient instance, and want to + * reuse it. + */ + setClient(client: mongodb.MongoClient): this; + + /** + * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://docs.mongodb.com/manual/release-notes/3.6/#client-sessions) + * for benefits like causal consistency, [retryable writes](https://docs.mongodb.com/manual/core/retryable-writes/), + * and [transactions](http://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html). + */ + startSession(options: mongodb.ClientSessionOptions | undefined | null, callback: Callback): void; + startSession(callback: Callback): void; + startSession(options?: mongodb.ClientSessionOptions): Promise; + + /** + * Makes the indexes in MongoDB match the indexes defined in every model's + * schema. This function will drop any indexes that are not defined in + * the model's schema except the `_id` index, and build any indexes that + * are in your schema but not in MongoDB. + */ + syncIndexes(options: SyncIndexesOptions | undefined | null, callback: Callback): void; + syncIndexes(options?: SyncIndexesOptions): Promise; + + /** + * _Requires MongoDB >= 3.6.0._ Executes the wrapped async function + * in a transaction. Mongoose will commit the transaction if the + * async function executes successfully and attempt to retry if + * there was a retryable error. + */ + transaction(fn: (session: mongodb.ClientSession) => Promise): Promise; + + /** Switches to a different database using the same connection pool. */ + useDb(name: string, options?: { useCache?: boolean, noListener?: boolean }): Connection; + + /** The username specified in the URI */ + readonly user: string; + + /** Watches the entire underlying database for changes. Similar to [`Model.watch()`](/docs/api/model.html#model_Model.watch). */ + watch(pipeline?: Array, options?: mongodb.ChangeStreamOptions): mongodb.ChangeStream; + } + +} diff --git a/types/index.d.ts b/types/index.d.ts index 8bd724845cc..d1c221a672e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,5 @@ /// +/// import events = require('events'); import mongodb = require('mongodb'); @@ -7,14 +8,6 @@ import stream = require('stream'); declare module 'mongoose' { - export enum ConnectionStates { - disconnected = 0, - connected = 1, - connecting = 2, - disconnecting = 3, - uninitialized = 99, - } - class NativeDate extends global.Date {} /** The Mongoose Date [SchemaType](/docs/schematypes.html). */ @@ -63,9 +56,6 @@ declare module 'mongoose' { /** The various Mongoose SchemaTypes. */ export const SchemaTypes: typeof Schema.Types; - /** Expose connection states for user-land */ - export const STATES: typeof ConnectionStates; - /** Opens Mongoose's default connection to MongoDB, see [connections docs](https://mongoosejs.com/docs/connections.html) */ export function connect(uri: string, options: ConnectOptions, callback: CallbackWithoutResult): void; export function connect(uri: string, callback: CallbackWithoutResult): void; @@ -99,10 +89,11 @@ declare module 'mongoose' { /** An array containing all models associated with this Mongoose instance. */ export const models: Models; + /** Creates a Connection instance. */ + export function createConnection(uri: string, options: ConnectOptions, callback: Callback): void; export function createConnection(uri: string, options?: ConnectOptions): Connection; export function createConnection(): Connection; - export function createConnection(uri: string, options: ConnectOptions, callback: Callback): void; /** * Removes the model named `name` from the default connection, if it exists. @@ -287,190 +278,6 @@ declare module 'mongoose' { // eslint-disable-next-line @typescript-eslint/no-empty-interface interface ClientSession extends mongodb.ClientSession { } - interface ConnectOptions extends mongodb.MongoClientOptions { - /** Set to false to [disable buffering](http://mongoosejs.com/docs/faq.html#callback_never_executes) on all models associated with this connection. */ - bufferCommands?: boolean; - /** The name of the database you want to use. If not provided, Mongoose uses the database name from connection string. */ - dbName?: string; - /** username for authentication, equivalent to `options.auth.user`. Maintained for backwards compatibility. */ - user?: string; - /** password for authentication, equivalent to `options.auth.password`. Maintained for backwards compatibility. */ - pass?: string; - /** Set to false to disable automatic index creation for all models associated with this connection. */ - autoIndex?: boolean; - /** Set to `true` to make Mongoose automatically call `createCollection()` on every model created on this connection. */ - autoCreate?: boolean; - } - - class Connection extends events.EventEmitter { - /** Returns a promise that resolves when this connection successfully connects to MongoDB */ - asPromise(): Promise; - - /** Closes the connection */ - close(callback: CallbackWithoutResult): void; - close(force: boolean, callback: CallbackWithoutResult): void; - close(force?: boolean): Promise; - - /** Retrieves a collection, creating it if not cached. */ - collection(name: string, options?: mongodb.CreateCollectionOptions): Collection; - - /** A hash of the collections associated with this connection */ - collections: { [index: string]: Collection }; - - /** A hash of the global options that are associated with this connection */ - config: any; - - /** The mongodb.Db instance, set when the connection is opened */ - db: mongodb.Db; - - /** - * Helper for `createCollection()`. Will explicitly create the given collection - * with specified options. Used to create [capped collections](https://docs.mongodb.com/manual/core/capped-collections/) - * and [views](https://docs.mongodb.com/manual/core/views/) from mongoose. - */ - createCollection(name: string, options?: mongodb.CreateCollectionOptions): Promise>; - createCollection(name: string, cb: Callback>): void; - createCollection(name: string, options: mongodb.CreateCollectionOptions, cb?: Callback>): Promise>; - - /** - * Removes the model named `name` from this connection, if it exists. You can - * use this function to clean up any models you created in your tests to - * prevent OverwriteModelErrors. - */ - deleteModel(name: string): this; - - /** - * Helper for `dropCollection()`. Will delete the given collection, including - * all documents and indexes. - */ - dropCollection(collection: string): Promise; - dropCollection(collection: string, cb: CallbackWithoutResult): void; - - /** - * Helper for `dropDatabase()`. Deletes the given database, including all - * collections, documents, and indexes. - */ - dropDatabase(): Promise; - dropDatabase(cb: CallbackWithoutResult): void; - - /** Gets the value of the option `key`. Equivalent to `conn.options[key]` */ - get(key: string): any; - - /** - * Returns the [MongoDB driver `MongoClient`](http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html) instance - * that this connection uses to talk to MongoDB. - */ - getClient(): mongodb.MongoClient; - - /** - * The host name portion of the URI. If multiple hosts, such as a replica set, - * this will contain the first host name in the URI - */ - host: string; - - /** - * A number identifier for this connection. Used for debugging when - * you have [multiple connections](/docs/connections.html#multiple_connections). - */ - id: number; - - /** - * A [POJO](https://masteringjs.io/tutorials/fundamentals/pojo) containing - * a map from model names to models. Contains all models that have been - * added to this connection using [`Connection#model()`](/docs/api/connection.html#connection_Connection-model). - */ - models: { [index: string]: Model }; - - /** Defines or retrieves a model. */ - model(name: string, schema?: Schema, collection?: string, options?: CompileModelOptions): Model; - model( - name: string, - schema?: Schema, - collection?: string, - options?: CompileModelOptions - ): U; - - /** Returns an array of model names created on this connection. */ - modelNames(): Array; - - /** The name of the database this connection points to. */ - name: string; - - /** Opens the connection with a URI using `MongoClient.connect()`. */ - openUri(uri: string, options?: ConnectOptions): Promise; - openUri(uri: string, callback: (err: CallbackError, conn?: Connection) => void): Connection; - openUri(uri: string, options: ConnectOptions, callback: (err: CallbackError, conn?: Connection) => void): Connection; - - /** The password specified in the URI */ - pass: string; - - /** - * The port portion of the URI. If multiple hosts, such as a replica set, - * this will contain the port from the first host name in the URI. - */ - port: number; - - /** Declares a plugin executed on all schemas you pass to `conn.model()` */ - plugin(fn: (schema: Schema, opts?: any) => void, opts?: any): Connection; - - /** The plugins that will be applied to all models created on this connection. */ - plugins: Array; - - /** - * Connection ready state - * - * - 0 = disconnected - * - 1 = connected - * - 2 = connecting - * - 3 = disconnecting - */ - readyState: number; - - /** Sets the value of the option `key`. Equivalent to `conn.options[key] = val` */ - set(key: string, value: any): any; - - /** - * Set the [MongoDB driver `MongoClient`](http://mongodb.github.io/node-mongodb-native/3.5/api/MongoClient.html) instance - * that this connection uses to talk to MongoDB. This is useful if you already have a MongoClient instance, and want to - * reuse it. - */ - setClient(client: mongodb.MongoClient): this; - - /** - * _Requires MongoDB >= 3.6.0._ Starts a [MongoDB session](https://docs.mongodb.com/manual/release-notes/3.6/#client-sessions) - * for benefits like causal consistency, [retryable writes](https://docs.mongodb.com/manual/core/retryable-writes/), - * and [transactions](http://thecodebarbarian.com/a-node-js-perspective-on-mongodb-4-transactions.html). - */ - startSession(options?: mongodb.ClientSessionOptions): Promise; - startSession(options: mongodb.ClientSessionOptions, cb: Callback): void; - - /** - * Makes the indexes in MongoDB match the indexes defined in every model's - * schema. This function will drop any indexes that are not defined in - * the model's schema except the `_id` index, and build any indexes that - * are in your schema but not in MongoDB. - */ - syncIndexes(options?: SyncIndexesOptions): Promise; - syncIndexes(options: SyncIndexesOptions | null, callback: Callback): void; - - /** - * _Requires MongoDB >= 3.6.0._ Executes the wrapped async function - * in a transaction. Mongoose will commit the transaction if the - * async function executes successfully and attempt to retry if - * there was a retryable error. - */ - transaction(fn: (session: mongodb.ClientSession) => Promise): Promise; - - /** Switches to a different database using the same connection pool. */ - useDb(name: string, options?: { useCache?: boolean, noListener?: boolean }): Connection; - - /** The username specified in the URI */ - user: string; - - /** Watches the entire underlying database for changes. Similar to [`Model.watch()`](/docs/api/model.html#model_Model.watch). */ - watch(pipeline?: Array, options?: mongodb.ChangeStreamOptions): mongodb.ChangeStream; - } - /* * section collection.js * http://mongoosejs.com/docs/api.html#collection-js