Add: Mongoose 5 types (#23070)

* move v4 types

* add newline-per-chained-call tslint rule to avoi having to refactor the entire test file

* mongoose 5 types

* update SchemaToObjectOptions

* reuse toObject definition, add it to schema options, remove retainKeyOrder

* add paths to mongoose-deep-populate

* rm a no longer supported createConnection signature

* Object -> any @ mongoose 4

* object ->any @ mongoose 5

* rm todo comment

* rm Mongoose thenable type

* Add changes between 4.7 and 5.0

* Add path to mongoose/v4 to all dependent projects

* fix dropDatabase() brainfart.

* Add more missing methods

* rm newline-chained-call rule from tslint

* Revert "Add path to mongoose/v4 to all dependent projects"

This reverts commit 162b8ad
This commit is contained in:
Art
2018-01-26 13:32:00 -08:00
committed by Andy
parent 831b49efaf
commit ccdc539cc4
8 changed files with 5336 additions and 408 deletions
@@ -12,6 +12,11 @@
"typeRoots": [
"../"
],
"paths": {
"mongoose": [
"mongoose/v4"
]
},
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true
+321 -344
View File
File diff suppressed because it is too large Load Diff
+114 -64
View File
@@ -20,33 +20,31 @@ var cb = function () {};
* http://mongoosejs.com/docs/api.html#index-js
*/
var connectUri = 'mongodb://user:pass@localhost:port/database';
mongoose.connect(connectUri).then(cb).catch(cb);
mongoose.connect(connectUri, {
const connection1: Promise<mongoose.Mongoose> = mongoose.connect(connectUri);
const connection2: Promise<mongoose.Mongoose> = mongoose.connect(connectUri, {
user: 'larry',
pass: 'housan',
config: {
autoIndex: true
},
mongos: true
}).then(cb);
mongoose.connect(connectUri, function (error) {
mongos: true,
bufferCommands: false
});
const connection3: null = mongoose.connect(connectUri, function (error) {
error.stack;
});
var mongooseConnection: mongoose.Connection = mongoose.createConnection();
mongooseConnection.dropDatabase().then(()=>{});
mongooseConnection.dropCollection('foo').then(()=>{});
mongoose.createConnection(connectUri).open('');
mongoose.createConnection(connectUri, {
db: {
native_parser: true
}
}).open('');
mongoose.createConnection('localhost', 'database', 3000).open('');
mongoose.createConnection('localhost', 'database', 3000, {
user: 'larry',
config: {
autoIndex: false
}
}).open('');
mongoose.disconnect(cb).then(cb);
const dcWithCallback: null = mongoose.disconnect(cb);
const dcPromise: Promise<void> = mongoose.disconnect();
mongoose.get('test');
mongoose.model('Actor', new mongoose.Schema({
name: String
@@ -67,29 +65,6 @@ mongoose.Types.ObjectId;
mongoose.Types.Decimal128;
mongoose.version.toLowerCase();
/*
* section querystream.js
* http://mongoosejs.com/docs/api.html#querystream-js
*/
var querystream = <mongoose.QueryStream> {};
querystream.destroy(new Error());
querystream.pause();
querystream.pipe(process.stdout, {end: true}).end();
querystream.resume();
querystream.paused;
querystream.readable;
/* inherited properties */
querystream.getMaxListeners();
/* practical examples */
var QSModel = <typeof mongoose.Model> {};
var QSStream: mongoose.QueryStream = QSModel.find().stream();
QSStream.on('data', function (doc: any) {
doc.save();
}).on('error', function (err: any) {
throw err;
}).on('close', cb);
QSModel.where('created').gte(20000).stream().pipe(process.stdout);
/*
* section collection.js
* http://mongoosejs.com/docs/api.html#collection-js
@@ -174,6 +149,8 @@ mongooseError.stack;
mongoose.Error.messages.hasOwnProperty('');
mongoose.Error.Messages.hasOwnProperty('');
const plural: string = mongoose.pluralize('foo');
/*
* section querycursor.js
* http://mongoosejs.com/docs/api.html#querycursor-js
@@ -209,6 +186,16 @@ querycursor.map(function (doc) {
console.log(doc.foo);
});
QCModel.watch().once('change', (change: any) => {
console.log(change);
});
QCModel.watch({
maxAwaitTimeMS: 10
}).once('change', (change: any) => {
console.log(change);
});
/*
* section virtualtype.js
* http://mongoosejs.com/docs/api.html#virtualtype-js
@@ -369,7 +356,22 @@ new mongoose.Schema({
integerOnly: {
type: Number,
get: (v: number) => Math.round(v),
set: (v: number) => Math.round(v)
set: (v: number) => Math.round(v),
validate: {
isAsync: false,
validator: (val: number): boolean => {
return false;
}
}
},
asyncValidated: {
type: Number,
validate: {
isAsync: true,
validator: (val: number, done): void => {
setImmediate(done, true);
}
}
}
});
new mongoose.Schema({ name: { type: String, validate: [
@@ -431,8 +433,8 @@ new mongoose.Schema({
});
export default function(schema: mongoose.Schema) {
schema.pre('init', function(this: mongoose.Document, next: (err?: Error) => void, data: any): void {
data.name = 'Hello world';
schema.pre('init', function(this: mongoose.Document, next: (err?: Error) => void): void {
console.log('success!');
});
}
@@ -442,13 +444,13 @@ export default function(schema: mongoose.Schema) {
*/
var doc = <mongoose.MongooseDocument> {};
doc.$isDefault('path').valueOf();
doc.depopulate('path');
const docDotDepopulate: mongoose.MongooseDocument = doc.depopulate('path');
doc.equals(doc).valueOf();
doc.execPopulate().then(function (arg) {
arg.execPopulate();
}).catch(function (err) {});
doc.get('path', Number);
doc.init(doc, cb).init(doc, {}, cb);
doc.init(doc).init(doc, {});
doc.inspect();
doc.invalidate('path', new Error('hi'), 999).toString();
doc.isDirectModified('path').valueOf();
@@ -491,6 +493,7 @@ doc.validateSync(['path1', 'path2']).stack;
var MyModel = mongoose.model('test', new mongoose.Schema({
name: {
type: String,
alias: 'foo',
default: 'Val '
}
}));
@@ -501,6 +504,14 @@ MyModel.findOne().populate('author').exec(function (err, doc) {
doc.depopulate('author');
}
});
MyModel.replaceOne({foo: 'bar'}, {qux: 'baz'}).where();
MyModel.replaceOne({foo: 'bar'}, {qux: 'baz'}, (err, raw) => {})
MyModel.bulkWrite([{foo:'bar'}]).then(r => {
console.log(r.deletedCount);
});
MyModel.bulkWrite([], (err, res) => {
console.log(res.modifiedCount)
})
doc.populate('path');
doc.populate({path: 'hello'});
doc.populate('path', cb)
@@ -514,6 +525,8 @@ const ImageSchema = new mongoose.Schema({
id: {type: Number, unique: true, required: true, index: true},
}, { id: false });
const clonedSchema: mongoose.Schema = new mongoose.Schema().clone();
interface ImageDoc extends mongoose.Document {
name: string,
id: number
@@ -731,7 +744,7 @@ query.findOne(function (err, res) {
res.execPopulate();
}).findOne();
query.findOneAndRemove({name: 'aa'}, {
passRawResult: true
rawResult: true
}, function (err, doc) {
doc.execPopulate();
}).findOneAndRemove();
@@ -739,7 +752,7 @@ query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, {
});
query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, {
passRawResult: true
rawResult: true
}, cb);
query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, cb);
query.findOneAndUpdate({name: 'aa'}, {name: 'bb'});
@@ -842,10 +855,6 @@ query.where('comments').slice([-10, 5]);
query.snapshot().snapshot(true);
query.sort({ field: 'asc', test: -1 });
query.sort('field -test');
query.stream().on('data', function (doc: any) {
}).on('error', function (err: any) {
}).on('close', function () {
});
query.tailable().tailable(false);
query.then(cb).catch(cb);
(new (query.toConstructor())(1, 2, 3)).toConstructor();
@@ -1023,7 +1032,7 @@ schemaembedded.sparse(true);
* http://mongoosejs.com/docs/api.html#aggregate-js
*/
var aggregate: mongoose.Aggregate<Object[]>;
aggregate = mongoose.model('ex').aggregate({ $match: { age: { $gte: 21 }}});
aggregate = mongoose.model('ex').aggregate([{ $match: { age: { $gte: 21 }}}]);
aggregate = new mongoose.Aggregate<Object[]>();
aggregate = new mongoose.Aggregate<Object[]>({ $project: { a: 1, b: 1 } });
aggregate = new mongoose.Aggregate<Object[]>({ $project: { a: 1, b: 1 } }, { $skip: 5 });
@@ -1035,6 +1044,8 @@ aggregate.append([{ $match: { daw: 'Logic Audio X' }} ]);
aggregate.collation({ locale: 'en_US', strength: 1 });
aggregate.cursor({ batchSize: 1000 }).exec().each(cb);
aggregate.exec().then(cb).catch(cb);
aggregate.option({foo: 'bar'}).exec();
const aggregateDotPipeline: any[] = aggregate.pipeline();
aggregate.explain(cb).then(cb).catch(cb);
aggregate.group({ _id: "$department" }).group({ _id: "$department" });
aggregate.limit(10).limit(10);
@@ -1241,7 +1252,7 @@ mongoose.model('').findOne({})
str.toLowerCase;
});
mongoose.model('').aggregate()
mongoose.model('').aggregate([])
.then(function (arg) {
return 2;
}).then(function (num) {
@@ -1278,7 +1289,7 @@ MongoModel.find({}).$where('indexOf("val") !== -1').exec(function (err, docs) {
docs[0].__v;
});
MongoModel.findById(999, function (err, doc) {
var handleSave = function(err: Error, product: mongoose.Document, numAffected: number) {};
var handleSave = function(err: Error, product: mongoose.Document) {};
if (!doc) {
return;
}
@@ -1290,9 +1301,9 @@ MongoModel.findById(999, function (err, doc) {
doc.save({ safe: { w: 'majority', wtimeout: 10000 } }, handleSave).then(cb).catch(cb);
// test if Typescript can infer the types of (err, product, numAffected)
doc.save(function(err, product, numAffected) { product.save(); })
doc.save(function(err, product) { product.save(); })
.then(function(p) { p.save() }).catch(cb);
doc.save({ validateBeforeSave: false }, function(err, product, numAffected) {
doc.save({ validateBeforeSave: false }, function(err, product) {
product.save();
}).then(function(p) { p.save() }).catch(cb);
});
@@ -1311,10 +1322,13 @@ mongoModel.save().then(function (product) {
product.save().then(cb).catch(cb);
});
MongoModel.aggregate(
{ $group: { _id: null, maxBalance: { $max: '$balance' }}}
, { $project: { _id: 0, maxBalance: 1 }}
, cb);
MongoModel.aggregate()
[
{ $group: { _id: null, maxBalance: { $max: '$balance' }}},
{ $project: { _id: 0, maxBalance: 1 }}
],
cb
);
MongoModel.aggregate([])
.group({ _id: null, maxBalance: { $max: '$balance' } })
.exec(cb);
MongoModel.count({ type: 'jungle' }, function (err, count) {
@@ -1402,14 +1416,6 @@ MongoModel.findOneAndUpdate({}, {}, {});
MongoModel.findOneAndUpdate({}, {}, cb);
MongoModel.findOneAndUpdate({}, {});
MongoModel.findOneAndUpdate();
MongoModel.geoNear([1,3], { maxDistance : 5, spherical : true }, function(err, results, stats) {
results[0].on('data', cb);
});
MongoModel.geoNear({ type : "Point", coordinates : [9,9] }, {
maxDistance : 5, spherical : true
}, function(err, results, stats) {
console.log(results);
});
MongoModel.geoSearch({ type : "house" }, {
near: [10, 10], maxDistance: 5
}, function(err, res) {
@@ -1649,3 +1655,47 @@ const x = new extended({
username: 'hi', // required in baseSchema
email: 'beddiw', // required in extededSchema
});
new mongoose.Schema({}, {
timestamps: {
createdAt: 'foo',
updatedAt: 'bar'
}
});
new mongoose.Schema({}, {
collation: {
strength: 1,
locale: 'en_US'
}
});
new mongoose.Schema({}, {
toObject: {
versionKey: false
},
toJSON: {
depopulate: true
}
})
const aggregatePrototypeGraphLookup: mongoose.Aggregate<any> = MyModel.aggregate([]).graphLookup({});
const addFieldsAgg: mongoose.Aggregate<any> = aggregatePrototypeGraphLookup.addFields({})
MyModel.findById('foo').then((doc: mongoose.Document) => {
const a: boolean = doc.isDirectSelected('bar');
const b: boolean = doc.isDeleted();
doc.isDeleted(true);
});
MyModel.translateAliases({});
const queryPrototypeError: Error | null = MyModel.findById({}).error();
const queryProrotypeErrorSetUnset: mongoose.Query<any> = MyModel.findById({}).error(null).error(new Error('foo'));
MyModel.createIndexes().then(() => {});
MyModel.createIndexes((err: any): void => {}).then(() => {});
mongoose.connection.createCollection('foo').then(() => {});
mongoose.connection.createCollection('foo', {wtimeout: 5}).then(() => {});
mongoose.connection.createCollection('foo', {wtimeout: 5}, (err: Error, coll): void => {coll.collectionName}).then(() => {});
+233
View File
@@ -0,0 +1,233 @@
## MongooseJS Typescript Docs
Below are some examples of how to use these Definitions.<br>
Scenarios where the Typescript code is identical to plain Javascript code are omitted.
### Table of Contents
* [Mongoose Methods, Properties, Constructors](#mongoose-methods-properties-constructors)
* [Creating and Saving Documents](#creating-and-saving-documents)
* [Promises](#promises)
* [Instance Methods, Virtual Properties](#instance-methods-and-virtual-properties)
* [Static Methods](#static-methods)
* [Plugins](#plugins)
* [FAQ and Common Mistakes](#faq-and-common-mistakes)
#### Mongoose Methods, Properties, Constructors
You can call methods from the mongoose instance using:
```typescript
import * as mongoose from 'mongoose';
var MyModel = mongoose.model(...);
var MySchema: mongoose.Schema = new mongoose.Schema(...);
```
Alternatively, you can import individual names and call them:
```typescript
import { model, Schema } from 'mongoose';
var MyModel = model(...);
var MySchema: Schema = new Schema(...):
```
[top](#mongoosejs-typescript-docs)
#### Creating and Saving Documents
```typescript
import {Document, model, Model, Schema} from 'mongoose';
var UserSchema: Schema = new Schema({
username: {
type: String,
required: true,
unique: true
},
age: Number,
friends: [String],
data: [Schema.Types.Mixed]
});
interface IUser extends Document {
username: string;
age: number;
friends: string[];
data: any[];
}
var UserModel: Model<IUser> = model<IUser>('User', UserSchema);
var user = new UserModel({name: 'Jane'});
user.username; // IUser properties are available
user.save(); // mongoose Document methods are available
UserModel.findOne({}, (err: any, user: IUser) => {
user.username; // IUser properties are available
user.save(); // mongoose Document methods are available
});
```
[top](#mongoosejs-typescript-docs)
#### Promises
These definitions use `global.Promise` by default. If you would like to use mongoose's own mpromise
definition (which is deprecated), you can install definitions for [mongoose-promise](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/mongoose-promise).
If you'd like to use something other than `global.Promise`, you'll need to create a simple `.d.ts` file:
```typescript
// promise-bluebird.d.ts
import * as Bluebird from 'bluebird';
declare module 'mongoose' {
type Promise<T> = Bluebird<T>;
}
// promise-q.d.ts
import * as Q from 'q';
declare module 'mongoose' {
type Promise<T> = Q.Promise<T>;
}
// another-promise.d.ts
...
```
To use it, you will need to `/// <reference path="promise-bluebird.d.ts" />` in one of your source code files,
or include the `.d.ts` file in your compile.
To assign the new promise library in your code, you will need to use one of the following options (since
Typescript does not allow assigning properties of imported modules):
* `(<any>mongoose).Promise = YOUR_PROMISE;`
* `require('mongoose').Promise = YOUR_PROMISE;`
* `import mongoose = require('mongoose'); ... mongoose.Promise = YOUR_PROMISE;`
[top](#mongoosejs-typescript-docs)
#### Instance Methods and Virtual Properties
```typescript
import {Document, model, Model, Schema} from 'mongoose';
var UserSchema: Schema = new Schema({
name: String
});
UserSchema.methods.method1 = function () { return '' };
UserSchema.virtual('nameInCaps').get(function () {
return this.name.toUpperCase();
});
UserSchema.virtual('nameInCaps').set(function (caps) {
this.name = caps.toLowerCase();
});
interface IUser extends Document {
name: string;
method1: () => string;
nameInCaps: string;
}
var UserModel: Model<IUser> = model<IUser>('User', UserSchema);
var user = new UserModel({name: 'Billy'});
user.method1(); // IUser methods are available
user.nameInCaps; // virtual properties can be used
UserModel.findOne({}, (err: any, user: IUser) => {
user.method1(); // IUser methods are available
user.nameInCaps; // virtual properties can be used
});
```
[top](#mongoosejs-typescript-docs)
#### Static Methods
```typescript
import {Document, model, Model, Schema} from 'mongoose';
var UserSchema = new Schema({});
UserSchema.statics.static1 = function () { return '' };
interface IUserDocument extends Document {...}
interface IUserModel extends Model<IUserDocument> {
static1: () => string;
}
var UserModel: IUserModel = model<IUserDocument, IUserModel>('User', UserSchema);
UserModel.static1(); // static methods are available
```
[top](#mongoosejs-typescript-docs)
#### Plugins
To write definitions for plugins, extend the mongoose module and create a simple plugin module:
```typescript
// plugin.d.ts
declare module 'mongoose' {
export interface PassportLocalDocument {...}
export interface PassportLocalSchema extends Schema {...}
export interface PassportLocalModel<T extends PassportLocalDocument> extends Model<T> {...}
...
}
declare module 'passport-local-mongoose' {
import mongoose = require('mongoose');
var _: (schema: mongoose.Schema, options?: Object) => void;
export = _;
}
// user.ts
import {
model,
PassportLocalDocument,
PassportLocalSchema,
PassportLocalModel
Schema
} from 'mongoose';
import * as passportLocalMongoose from 'passport-local-mongoose';
var UserSchema: PassportLocalSchema = new Schema({});
UserSchema.plugin(passportLocalMongoose, options);
interface IUser extends PassportLocalDocument {...}
interface IUserModel<T extends PassportLocalDocument> extends PassportLocalModel<T> {...}
var UserModel: IUserModel<IUser> = model<IUser>('User', UserSchema);
```
Full example for [Passport Local Mongoose](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/passport-local-mongoose/passport-local-mongoose.d.ts)<br>
[top](#mongoosejs-typescript-docs)
#### FAQ and Common Mistakes
**Q: When to use `mongoose.Schema.Types.ObjectId` and `mongoose.Types.ObjectId`**<br>
When creating schemas in code use `mongoose.Schema.Types.ObjectId`. This is not a type, this is an instance
of `SchemaType` containing metadata for the ObjectId type:
```typescript
var UserSchema = new mongoose.Schema({
id: mongoose.Schema.Types.ObjectId
});
```
When defining your interface, you should use the type definition `mongoose.Types.ObjectId`:
```typescript
interface IUser extends mongoose.Document {
id: mongoose.Types.ObjectId; // for type-checking, doesn't affect code behaviour
}
var UserSchema = new UserSchema({
id: mongoose.Schema.Types.ObjectId; // for creating the schema only
});
var User = mongoose.model<IUser>('User', UserSchema);
var user = new User({});
user.id = new mongoose.Types.ObjectId();
```
[top](#mongoosejs-typescript-docs)
**Q: Why are there 2 interfaces for Documents called Document and MongooseDocument?**<br>
People have been using this for a long time:
```typescript
interface IUser extends mongoose.Document {
...
}
```
When it should really be this:
```typescript
interface IUser extends mongoose.model {
...
}
```
For backwards compatibility Document is an interface for [mongoose.model](https://github.com/Automattic/mongoose/blob/master/lib/model.js#L3162)<br>
And MongooseDocument is an interface for [mongoose.Document](https://github.com/Automattic/mongoose/blob/master/lib/model.js#L3162)<br>
At some point in the future this may get fixed, which would require fixing your code.
<br>
[top](#mongoosejs-typescript-docs)
+2905
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+28
View File
@@ -0,0 +1,28 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": false,
"strictNullChecks": true,
"strictFunctionTypes": false,
"baseUrl": "../../",
"typeRoots": [
"../../"
],
"types": [],
"paths": {
"mongoose": [
"mongoose/v4"
]
},
"noEmit": true,
"forceConsistentCasingInFileNames": true
},
"files": [
"index.d.ts",
"mongoose-tests.ts"
]
}
+79
View File
@@ -0,0 +1,79 @@
{
"extends": "dtslint/dt.json",
"rules": {
"adjacent-overload-signatures": false,
"array-type": false,
"arrow-return-shorthand": false,
"ban-types": false,
"callable-types": false,
"comment-format": false,
"dt-header": false,
"eofline": false,
"export-just-namespace": false,
"import-spacing": false,
"interface-name": false,
"interface-over-type-literal": false,
"jsdoc-format": false,
"max-line-length": false,
"member-access": false,
"new-parens": false,
"no-any-union": false,
"no-boolean-literal-compare": false,
"no-conditional-assignment": false,
"no-consecutive-blank-lines": false,
"no-construct": false,
"no-declare-current-package": false,
"no-duplicate-imports": false,
"no-duplicate-variable": false,
"no-empty-interface": false,
"no-for-in-array": false,
"no-inferrable-types": false,
"no-internal-module": false,
"no-irregular-whitespace": false,
"no-mergeable-namespace": false,
"no-misused-new": false,
"no-namespace": false,
"no-object-literal-type-assertion": false,
"no-padding": false,
"no-redundant-jsdoc": false,
"no-redundant-jsdoc-2": false,
"no-redundant-undefined": false,
"no-reference-import": false,
"no-relative-import-in-test": false,
"no-self-import": false,
"no-single-declare-module": false,
"no-string-throw": false,
"no-unnecessary-callback-wrapper": false,
"no-unnecessary-class": false,
"no-unnecessary-generics": false,
"no-unnecessary-qualifier": false,
"no-unnecessary-type-assertion": false,
"no-useless-files": false,
"no-var-keyword": false,
"no-var-requires": false,
"no-void-expression": false,
"no-trailing-whitespace": false,
"object-literal-key-quotes": false,
"object-literal-shorthand": false,
"one-line": false,
"one-variable-per-declaration": false,
"only-arrow-functions": false,
"prefer-conditional-expression": false,
"prefer-const": false,
"prefer-declare-function": false,
"prefer-for-of": false,
"prefer-method-signature": false,
"prefer-template": false,
"radix": false,
"semicolon": false,
"space-before-function-paren": false,
"space-within-parens": false,
"strict-export-declare-modifiers": false,
"trim-file": false,
"triple-equals": false,
"typedef-whitespace": false,
"unified-signatures": false,
"void-return": false,
"whitespace": false
}
}