From b1cfdc9ab7257e7cab9238a4ae61758df96ee7ff Mon Sep 17 00:00:00 2001 From: Valentin Agachi Date: Sat, 18 Apr 2020 00:07:55 +0100 Subject: [PATCH] [mongoose] Use mongodb.UpdateQuery type (#43894) --- types/mongoose/index.d.ts | 59 +- types/mongoose/test/definitions.ts | 26 + types/mongoose/test/document.ts | 149 +++ types/mongoose/test/model.ts | 477 +++++++++ .../{mongoose-tests.ts => test/mongoose.ts} | 907 +----------------- types/mongoose/test/query.ts | 373 +++++++ types/mongoose/tsconfig.json | 5 +- 7 files changed, 1065 insertions(+), 931 deletions(-) create mode 100644 types/mongoose/test/definitions.ts create mode 100644 types/mongoose/test/document.ts create mode 100644 types/mongoose/test/model.ts rename types/mongoose/{mongoose-tests.ts => test/mongoose.ts} (63%) create mode 100644 types/mongoose/test/query.ts diff --git a/types/mongoose/index.d.ts b/types/mongoose/index.d.ts index dc1211f352..67a3807809 100644 --- a/types/mongoose/index.d.ts +++ b/types/mongoose/index.d.ts @@ -112,6 +112,15 @@ declare module "mongoose" { /* FilterQuery alias type for using as type for filter/conditions parameters */ export type FilterQuery = MongooseFilterQuery>; + /** + * Patched version of UpdateQuery to also allow: + * - setting attributes directly in the root, without a `$set` wrapper + * - setting attributes via dot-notation + */ + export type MongooseUpdateQuery = mongodb.UpdateQuery & mongodb.MatchKeysAndValues; + + export type UpdateQuery = MongooseUpdateQuery>; + /** * Gets and optionally overwrites the function used to pluralize collection names * @param fn function to use for pluralization of collection names @@ -2009,21 +2018,21 @@ declare module "mongoose" { * https://mongoosejs.com/docs/api.html#mongoose_Mongoose-set */ findOneAndUpdate(callback?: (err: any, doc: DocType | null) => void): DocumentQuery & QueryHelpers; - findOneAndUpdate(update: any, + findOneAndUpdate(update: UpdateQuery, callback?: (err: any, doc: DocType | null, res: any) => void): DocumentQuery & QueryHelpers; - findOneAndUpdate(query: FilterQuery, update: any, + findOneAndUpdate(query: FilterQuery, update: UpdateQuery, callback?: (err: any, doc: DocType | null, res: any) => void): DocumentQuery & QueryHelpers; - findOneAndUpdate(query: FilterQuery, update: any, + findOneAndUpdate(query: FilterQuery, update: UpdateQuery, options: { rawResult: true } & { upsert: true } & { new: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void) : Query> & QueryHelpers; - findOneAndUpdate(query: FilterQuery, update: any, + findOneAndUpdate(query: FilterQuery, update: UpdateQuery, options: { upsert: true } & { new: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, doc: DocType, res: any) => void): DocumentQuery & QueryHelpers; - findOneAndUpdate(query: FilterQuery, update: any, options: { rawResult: true } & QueryFindOneAndUpdateOptions, + findOneAndUpdate(query: FilterQuery, update: UpdateQuery, options: { rawResult: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void) : Query> & QueryHelpers; - findOneAndUpdate(query: FilterQuery, update: any, options: QueryFindOneAndUpdateOptions, + findOneAndUpdate(query: FilterQuery, update: UpdateQuery, options: QueryFindOneAndUpdateOptions, callback?: (err: any, doc: DocType | null, res: any) => void): DocumentQuery & QueryHelpers; /** @@ -2332,10 +2341,10 @@ declare module "mongoose" { * @param doc the update command */ update(callback?: (err: any, affectedRows: number) => void): Query & QueryHelpers; - update(doc: any, callback?: (err: any, affectedRows: number) => void): Query & QueryHelpers; - update(criteria: FilterQuery, doc: any, + update(doc: UpdateQuery, callback?: (err: any, affectedRows: number) => void): Query & QueryHelpers; + update(criteria: FilterQuery, doc: UpdateQuery, callback?: (err: any, affectedRows: number) => void): Query & QueryHelpers; - update(criteria: FilterQuery, doc: any, options: QueryUpdateOptions, + update(criteria: FilterQuery, doc: UpdateQuery, options: QueryUpdateOptions, callback?: (err: any, affectedRows: number) => void): Query & QueryHelpers; /** Specifies a path for use with chaining. */ @@ -3236,20 +3245,20 @@ declare module "mongoose" { * @param id value of _id to query by */ findByIdAndUpdate(): DocumentQuery & QueryHelpers; - findByIdAndUpdate(id: any | number | string, update: any, + findByIdAndUpdate(id: any | number | string, update: UpdateQuery, callback?: (err: any, res: T | null) => void): DocumentQuery & QueryHelpers; - findByIdAndUpdate(id: any | number | string, update: any, + findByIdAndUpdate(id: any | number | string, update: UpdateQuery, options: { rawResult: true } & { upsert: true } & { new: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, res: T) => void): DocumentQuery & QueryHelpers; - findByIdAndUpdate(id: any | number | string, update: any, + findByIdAndUpdate(id: any | number | string, update: UpdateQuery, options: { upsert: true, new: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, res: mongodb.FindAndModifyWriteOpResultObject) => void) : Query> & QueryHelpers; - findByIdAndUpdate(id: any | number | string, update: any, + findByIdAndUpdate(id: any | number | string, update: UpdateQuery, options: { rawResult : true } & QueryFindOneAndUpdateOptions, callback?: (err: any, res: mongodb.FindAndModifyWriteOpResultObject) => void) : Query> & QueryHelpers; - findByIdAndUpdate(id: any | number | string, update: any, + findByIdAndUpdate(id: any | number | string, update: UpdateQuery, options: QueryFindOneAndUpdateOptions, callback?: (err: any, res: T | null) => void): DocumentQuery & QueryHelpers; @@ -3310,20 +3319,20 @@ declare module "mongoose" { + * https://mongoosejs.com/docs/api.html#mongoose_Mongoose-set */ findOneAndUpdate(): DocumentQuery & QueryHelpers; - findOneAndUpdate(conditions: FilterQuery, update: any, + findOneAndUpdate(conditions: FilterQuery, update: UpdateQuery, callback?: (err: any, doc: T | null, res: any) => void): DocumentQuery & QueryHelpers; - findOneAndUpdate(conditions: FilterQuery, update: any, + findOneAndUpdate(conditions: FilterQuery, update: UpdateQuery, options: { rawResult : true } & { upsert: true, new: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void) : Query> & QueryHelpers; - findOneAndUpdate(conditions: FilterQuery, update: any, + findOneAndUpdate(conditions: FilterQuery, update: UpdateQuery, options: { upsert: true, new: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, doc: T, res: any) => void): DocumentQuery & QueryHelpers; - findOneAndUpdate(conditions: FilterQuery, update: any, + findOneAndUpdate(conditions: FilterQuery, update: UpdateQuery, options: { rawResult: true } & QueryFindOneAndUpdateOptions, callback?: (err: any, doc: mongodb.FindAndModifyWriteOpResultObject, res: any) => void) : Query> & QueryHelpers; - findOneAndUpdate(conditions: FilterQuery, update: any, + findOneAndUpdate(conditions: FilterQuery, update: UpdateQuery, options: QueryFindOneAndUpdateOptions, callback?: (err: any, doc: T | null, res: any) => void): DocumentQuery & QueryHelpers; @@ -3418,17 +3427,17 @@ declare module "mongoose" { * Updates documents in the database without returning them. * All update values are cast to their appropriate SchemaTypes before being sent. */ - update(conditions: FilterQuery, doc: any, + update(conditions: FilterQuery, doc: UpdateQuery, callback?: (err: any, raw: any) => void): Query & QueryHelpers; - update(conditions: FilterQuery, doc: any, options: ModelUpdateOptions, + update(conditions: FilterQuery, doc: UpdateQuery, options: ModelUpdateOptions, callback?: (err: any, raw: any) => void): Query & QueryHelpers; - updateOne(conditions: FilterQuery, doc: any, + updateOne(conditions: FilterQuery, doc: UpdateQuery, callback?: (err: any, raw: any) => void): Query & QueryHelpers; - updateOne(conditions: FilterQuery, doc: any, options: ModelUpdateOptions, + updateOne(conditions: FilterQuery, doc: UpdateQuery, options: ModelUpdateOptions, callback?: (err: any, raw: any) => void): Query & QueryHelpers; - updateMany(conditions: FilterQuery, doc: any, + updateMany(conditions: FilterQuery, doc: UpdateQuery, callback?: (err: any, raw: any) => void): Query & QueryHelpers; - updateMany(conditions: FilterQuery, doc: any, options: ModelUpdateOptions, + updateMany(conditions: FilterQuery, doc: UpdateQuery, options: ModelUpdateOptions, callback?: (err: any, raw: any) => void): Query & QueryHelpers; /** Creates a Query, applies the passed conditions, and returns the Query. */ diff --git a/types/mongoose/test/definitions.ts b/types/mongoose/test/definitions.ts new file mode 100644 index 0000000000..cf32ce07c5 --- /dev/null +++ b/types/mongoose/test/definitions.ts @@ -0,0 +1,26 @@ +import * as mongodb from 'mongodb'; +import * as mongoose from 'mongoose'; + +export const MyModel = mongoose.model('test', new mongoose.Schema({ + name: { + type: String, + alias: 'foo', + default: 'Val ' + }, + wheels: Number +})); + +export interface OtherLocation extends mongoose.Document { + type: string; +} + +export interface Location extends mongoose.Document { + _id: mongodb.ObjectId; + name: string; + address: string; + rating: number; + reviews: string[]; + ref1: mongodb.ObjectId; + // This type is useful for using with `populate()` + ref2: mongodb.ObjectId | OtherLocation; +}; diff --git a/types/mongoose/test/document.ts b/types/mongoose/test/document.ts new file mode 100644 index 0000000000..26fdf09d54 --- /dev/null +++ b/types/mongoose/test/document.ts @@ -0,0 +1,149 @@ +import * as mongoose from 'mongoose'; + +import { MyModel } from './definitions'; + +// dummy variables +var cb = function () {}; + +/* + * section document.js + * https://mongoosejs.com/docs/api/document.html + */ +var doc = new mongoose.Document(); +doc.$isDefault('path').valueOf(); +doc.$locals.field = 'value'; +const docDotDepopulate: mongoose.Document = doc.depopulate('path'); +doc.equals(doc).valueOf(); +doc.execPopulate().then(function (arg) { + arg.execPopulate(); +}).catch(function (err) {}); +doc.get('path', Number); +doc.get('path', Number, { virtuals: true, getters: false }); +doc.init(doc).init(doc, {}); +doc.inspect(); +doc.invalidate('path', new Error('hi')).toString(); +doc.invalidate('path', new Error('hi'), 999).toString(); +doc.isDirectModified('path').valueOf(); +doc.isInit('path').valueOf(); +doc.isModified('path').valueOf(); +doc.isSelected('path').valueOf(); +doc.markModified('path'); +doc.modifiedPaths()[0].toLowerCase(); +doc.populate(function (err, doc) { + doc.populate('path', function (err, doc) { + doc.populate({ + path: 'path', + select: 'path', + match: {} + }); + }); +}); +doc.populated('path'); +doc.set('path', 999, {}).set({ path: 999 }); +doc.overwrite({path: 999}); +doc.toJSON({ + getters: true, + virtuals: false +}); +doc.toObject({ + transform: function (doc, ret, options) { + doc.toObject(); + } +}); +doc.toString().toLowerCase(); +doc.unmarkModified('path'); +doc.update(doc, cb).cursor(); +doc.update(doc, { + safe: true, + upsert: true +}, cb).cursor(); +doc.validate({}, function (err) {}); +doc.validate().then(null).catch(null); +(() => { + // Scope to avoid type mixing + var validationError = doc.validateSync(['path1', 'path2']); + if (validationError) { + validationError.stack + } +})(); + +/* practical examples */ + +doc = new MyModel(); +doc.$isDefault('name'); +MyModel.findOne().populate('author').exec(function (err, doc) { + if (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); +}); +MyModel.bulkWrite([], { ordered: false }, (err, res) => { + console.log(res.modifiedCount); +}); +doc.populate('path'); +doc.populate({path: 'hello'}); +doc.populate('path', cb) +doc.populate({path: 'hello'}, cb); +doc.populate(cb); +doc.populate({path: 'hello'}).execPopulate().catch(cb); +doc.update({ + $inc: { wheels: 1 } +}, { w: 1 }, cb); + +const ImageSchema = new mongoose.Schema({ + name: {type: String, required: true}, + 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 +} + +const ImageModel = mongoose.model('image', ImageSchema); + +ImageModel.findOne({}, function(err, doc) { + if (doc) { + doc.name; + doc.id; + } +}); + +/* Using flatten maps example */ +interface Submission extends mongoose.Document { + name: string; + fields: Record; +} +var SubmissionSchema = new mongoose.Schema({ + name: String, + fields: { + type: Map, + of: String + } +}); +const SubmissionModel = mongoose.model('Submission', SubmissionSchema); +const submission = new SubmissionModel({ + name: "Submission Name", + fields: { + extra: "Value", + other: "Thing" + } +}); +submission.save() +.then(result => { + console.log(result.toObject({ + flattenMaps: true + })); +}) +.catch(() => { + console.log("Flatten maps error"); +}); diff --git a/types/mongoose/test/model.ts b/types/mongoose/test/model.ts new file mode 100644 index 0000000000..e3a2a17758 --- /dev/null +++ b/types/mongoose/test/model.ts @@ -0,0 +1,477 @@ +import * as mongodb from 'mongodb'; +import * as mongoose from 'mongoose'; + +// dummy variables +var cb = function () {}; + +/* + * section model.js + * http://mongoosejs.com/docs/api.html#model-js + */ +var MongoModel = mongoose.model('MongoModel', new mongoose.Schema({ + name: String, + type: { + type: mongoose.Schema.Types.Mixed, + required: true + } +}), 'myCollection', true); + +MongoModel.init().then(cb); +MongoModel.find({}).$where('indexOf("val") !== -1').exec(function (err, docs) { + docs[0].save(); + docs[0].__v; +}); +MongoModel.findById(999, function (err, doc) { + var handleSave = function(err: Error, product: mongoose.Document) {}; + if (!doc) { + return; + } + doc.increment(); + doc.save(handleSave).then(cb).catch(cb); + doc.save({ validateBeforeSave: false }, handleSave).then(cb).catch(cb); + doc.save({ safe: true }, handleSave).then(cb).catch(cb); + doc.save({ safe: { w: 2, j: true } }, handleSave).then(cb).catch(cb); + 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) { product.save(); }) + .then(function(p) { p.save() }).catch(cb); + doc.save({ validateBeforeSave: false }, function(err, product) { + product.save(); + }).then(function(p) { p.save() }).catch(cb); +}); +MongoModel = (new MongoModel()).model('MongoModel'); +var mongoModel = new MongoModel(); +mongoModel.remove(function (err, product) { + if (err) throw(err); + MongoModel.findById(product._id, function (err, product) { + if (product) { + product.id.toLowerCase(); + product.remove(); + } + }); +}); +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' } }) + .exec(cb); +MongoModel.count({ type: 'jungle' }, function (err, count) { + count.toFixed(); +}); +MongoModel.create({ + type: 'jelly bean' +}, { + type: 'snickers' +}, cb).then(function (a) { + a.save(); +}) +MongoModel.create([{ type: 'jelly bean' }, { + type: 'snickers' +}], function (err, candies) { + var jellybean = candies[0]; + var snickers = candies[1]; +}).then(function (arg) { + arg[0].save(); + arg[1].save(); +}); +MongoModel.createCollection().then(() => {}); +MongoModel.createCollection({ capped: true, max: 42 }).then(() => {}); +MongoModel.createCollection({ capped: true, max: 42 }, err => {}); +MongoModel.distinct('url', { clicks: {$gt: 100}}, function (err, result) {}); +MongoModel.distinct('url').exec(cb); +MongoModel.syncIndexes().then(() => {}); +MongoModel.syncIndexes({}).then(() => {}); +MongoModel.syncIndexes(null).then(() => {}); +MongoModel.syncIndexes(undefined).then(() => {}); +MongoModel.syncIndexes({}, err => {}); +MongoModel.syncIndexes(null, err => {}); +MongoModel.syncIndexes(undefined, err => {}); +MongoModel.listIndexes(); +MongoModel.listIndexes(cb); +MongoModel.ensureIndexes({}, cb); +MongoModel.find({ name: 'john', age: { $gte: 18 }}); +MongoModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) { + docs[0].remove(); + docs[1].execPopulate(); +}); +MongoModel.find({ name: /john/i }, 'name friends', function (err, docs) { }) +MongoModel.find({ name: /john/i }, null, { skip: 10 }) +MongoModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {}); +MongoModel.find({ name: /john/i }, null, { skip: 10 }).exec(function (err, docs) {}); +MongoModel.findById(999, function (err, adventure) {}); +MongoModel.findById(999).exec(cb); +MongoModel.findById(999, 'name length', function (err, adventure) { + if (adventure) { + adventure.save(); + } +}); +MongoModel.findById(999, 'name length').exec(cb); +MongoModel.findById(999, '-length').exec(function (err, adventure) { + if (adventure) { + adventure.addListener('click', cb); + } +}); +MongoModel.findById(999, 'name', { lean: true }, function (err, doc) {}); +MongoModel.findById(999, 'name').lean().exec(function (err, doc) {}); +MongoModel.findByIdAndRemove(999, {}, cb); +MongoModel.findByIdAndRemove(999, {}); +MongoModel.findByIdAndRemove(999, cb); +MongoModel.findByIdAndRemove(999); +MongoModel.findByIdAndRemove(); +MongoModel.findByIdAndUpdate(999, {}, {}, cb); +MongoModel.findByIdAndUpdate(999, {}, {}); +MongoModel.findByIdAndUpdate(999, {}, { upsert: true, new: true }); +MongoModel.findByIdAndUpdate(999, {}, cb); +MongoModel.findByIdAndUpdate(999, {}); +MongoModel.findByIdAndUpdate(); +MongoModel.findOne({ type: 'iphone' }, function (err, adventure) {}); +MongoModel.findOne({ type: 'iphone' }).exec(function (err, adventure) {}); +MongoModel.findOne({ type: 'iphone' }, 'name', function (err, adventure) {}); +MongoModel.findOne({ type: 'iphone' }, 'name').exec(function (err, adventure) {}); +MongoModel.findOne({ type: 'iphone' }, 'name', { lean: true }, cb); +MongoModel.findOne({ type: 'iphone' }, 'name', { lean: true }).exec(cb); +MongoModel.findOne({ type: 'iphone' }).select('name').lean().exec(cb); + +interface ModelUser { + _id: any; + name: string; + abctest: string; +} + +MongoModel.findOneAndRemove({}, {}, cb); +MongoModel.findOneAndRemove({}, {}); +MongoModel.findOneAndRemove({}, cb); +MongoModel.findOneAndRemove({}); +MongoModel.findOneAndRemove(); +MongoModel.findOneAndUpdate({}, {}, {}, cb); +MongoModel.findOneAndUpdate({}, {}, {}); +MongoModel.findOneAndUpdate({}, {}, { upsert: true, new: true }); +MongoModel.findOneAndUpdate({}, {}, { upsert: true, new: true, arrayFilters: [{ 'elem._id': 123 }] }); +MongoModel.findOneAndUpdate({}, {}, { upsert: true, new: true, timestamps: true }); +MongoModel.findOneAndUpdate({}, {}, cb); +MongoModel.findOneAndUpdate({}, {}); +MongoModel.findOneAndUpdate(); +MongoModel.geoSearch({ type : "house" }, { + near: [10, 10], maxDistance: 5 +}, function(err, res) { + res[0].remove(); +}); +MongoModel.hydrate({ + _id: '54108337212ffb6d459f854c', + type: 'jelly bean' +}).execPopulate(); +MongoModel.insertMany([ + { name: 'Star Wars' }, + { name: 'The Empire Strikes Back' } +], function(error, docs) {}); +MongoModel.insertMany({name: 'Star Wars'}, function(error, doc) {}); +MongoModel.mapReduce({ + map: cb, + reduce: cb +}, function (err, results) { + console.log(results) +}).then(function (model) { + return model.find().where('value').gt(10).exec(); +}).then(function (docs) { + console.log(docs); +}).then(null, cb); +MongoModel.findById(999, function (err, user) { + if (!user) { + return; + } + var opts = [ + { path: 'company', match: { x: 1 }, select: 'name' }, + { path: 'notes', options: { limit: 10 }, model: 'override' } + ] + MongoModel.populate(user, opts, cb); + MongoModel.populate(user, opts, function (err, user) { + console.log(user); + }); +}); +// $ExpectError +MongoModel.find(999, function (err, users) { + var opts = [{ path: 'company', match: { x: 1 }, select: 'name' }] + var promise = MongoModel.populate(users, opts); + promise.then(console.log); +}); +MongoModel.populate({ + name: 'Indiana Jones', + weapon: 389 +}, { + path: 'weapon', + model: 'Weapon' +}, cb); +var users = [{ name: 'Indiana Jones', weapon: 389 }] +users.push({ name: 'Batman', weapon: 8921 }) +MongoModel.populate(users, { path: 'weapon' }, function (err, users) { + users.forEach(cb); +}); +MongoModel.remove({ title: 'baby born from alien father' }, cb); +MongoModel.remove({_id: '999'}).exec().then(cb).catch(cb); +MongoModel.remove({_id: '999'}).exec().then(res=>console.log(res.ok)); +MongoModel.deleteOne({_id: '999'}).then(res=>console.log(res.ok)); +MongoModel.deleteOne({_id: '999'}).exec().then(res=>console.log(res.ok)); +MongoModel.deleteMany({_id: '999'}).then(res=>console.log('Success?',!!res.ok, 'deleted count', res.n)); +MongoModel.deleteMany({_id: '999'}).exec().then(res=>console.log(res.ok)); +MongoModel.update({ age: { $gt: 18 } }, { oldEnough: true }, cb); +MongoModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true, arrayFilters: [{ element: { $gte: 100 } }] }, cb); +MongoModel.where('age').gte(21).lte(65).exec(cb); +MongoModel.where('age').gte(21).lte(65).where('name', /^b/i); +new (mongoModel.base.model(''))(); +mongoModel.baseModelName && mongoModel.baseModelName.toLowerCase(); +mongoModel.collection.$format(99); +mongoModel.collection.initializeOrderedBulkOp; +mongoModel.collection.findOne; +mongoModel.db.openUri(''); +mongoModel.discriminators; +mongoModel.modelName.toLowerCase(); +MongoModel = mongoModel.base.model('new', mongoModel.schema); +/* inherited properties */ +MongoModel.modelName; +mongoModel.modelName; +MongoModel.collection; +mongoModel.collection; +mongoModel._id; +mongoModel.execPopulate(); +mongoModel.on('data', cb); +mongoModel.addListener('event', cb); +MongoModel.findOne({ title: /timex/i }) + .populate('_creator', 'name') + .exec(function (err, story) { + if (story) { + story.execPopulate(); + } + }); +MongoModel.find({ + id: 999 +}) +.populate({ + path: 'fans', + match: { age: { $gte: 21 }}, + select: 'name -_id', + options: { limit: 5 } +}) +.exec(); + +/* practical example */ + +interface Location extends mongoose.Document { + _id: mongodb.ObjectId; + name: string; + address: string; + rating: number; + facilities: string[]; + coords: number[]; + openingTimes: any[]; + reviews: any[]; +}; +const locationSchema = new mongoose.Schema({ + name: { type: String, required: true }, + address: String, + rating: { type: Number, "default": 0, min: 0, max: 5 }, + facilities: [String], + coords: { type: [Number], index: "2dsphere" }, + openingTimes: [mongoose.Schema.Types.Mixed], + reviews: [mongoose.SchemaTypes.Mixed] +}); + +var locDocument = {}; +var LocModel = mongoose.model("Location", locationSchema); +LocModel.findById(999) + .select("-reviews -rating") + .exec(function (err, location) { + if (!location) { + return; + } + location.name = 'blah'; + location.address = 'blah'; + location.reviews.forEach(review => {}); + location.facilities.forEach(facility => { + facility.toLowerCase(); + }); + }); +LocModel.find() + .select('-reviews -rating') + .exec(function (err, locations) { + locations.forEach(location => { + location.name = 'blah'; + location.address = 'blah'; + location.reviews.forEach(review => {}); + location.facilities.forEach(facility => { + facility.toLowerCase(); + }); + }); + }); +LocModel.find({}).$where('') + .exec(function (err, locations) { + locations[0].name; + locations[1].openingTimes; + }); +LocModel.find({ + name: 'foo', + address: /bar/, // strings are allowed as RegExp + rating: 10, + facilities: { $exists: true }, + 'reviews.0': { $exists: true } // additional queries are allowed +}); +LocModel.find({ _id: new mongodb.ObjectId() }); +LocModel.find({ _id: 'string-allowed' }); +LocModel.find({ _id: locDocument }); +// $ExpectError +LocModel.find({ _id: 123 }); +// $ExpectError +LocModel.find({ _id: { foo: 'bar' } }); +// $ExpectError +LocModel.find({ name: 123 }); +// $ExpectError +LocModel.find({ rating: 'foo' }); +LocModel.count({ name: 'foo'}) + .exec(function (err, count) { + count.toFixed(); + }); +// $ExpectError +LocModel.count({ name: 123 }); +LocModel.countDocuments({ name: 'foo' }); +// $ExpectError +LocModel.countDocuments({ name: 123 }); +LocModel.distinct('') + .select('-review') + .exec(function (err, distinct) { + distinct.concat; + }) + .then(cb).catch(cb); +LocModel.exists({ name: 'foo' }); +// $ExpectError +LocModel.exists({ name: 123 }); +LocModel.findByIdAndRemove() + .exec(function (err, doc) { + if (!doc) { + return; + } + doc.addListener; + doc.openingTimes; + }); +LocModel.findByIdAndUpdate() + .select({}) + .exec(function (err, location) { + if (location) { + location.reviews; + } + }); +LocModel.findOne({}, function (err, doc) { + if (doc) { + doc.openingTimes; + } +}); +LocModel + .findOne({ name: 'foo', rating: 10 }) + .lean() + .exec() + .then(function(doc) { + if (doc) { + // $ExpectType ObjectId + doc._id; + // $ExpectType string + doc.name; + // $ExpectError + doc.unknown; + } + }); +LocModel.findOneAndRemove() + .exec(function (err, location) { + if (location) { + location.name; + } + }); +LocModel.findOneAndRemove({ name: 'foo', rating: 10 }); +LocModel.findOneAndDelete({ name: 'foo', rating: 10 }); +LocModel.findOneAndUpdate({ name: 'foo' }, { rating: 20 }).exec().then(function (arg) { + if (arg) { + arg.openingTimes; + } +}); +LocModel.findOneAndUpdate( + // find a document with that filter + { name: "aa" }, + // document to insert when nothing was found + { $set: { name: "bb" } }, + // options + {upsert: true, new: true, runValidators: true, + rawResult: true, multipleCastError: true }); +LocModel.geoSearch({}, { + near: [1, 2], + maxDistance: 22 +}, function (err, res) { res[0].openingTimes; }); +LocModel.remove({ name: 'foo' }); +LocModel.deleteOne({ name: 'foo' }); +LocModel.deleteMany({ name: 'foo' }); +LocModel.replaceOne({ name: 'foo' }, { name: 'bar' }); + +LocModel.update({ name: 'foo' }, { + name: 'bar', + 'reviews.0': 'test', + $unset: { + rating: '' + }, + $pull: { + facilities: 'foo' + }, + $push: { + coords: 100 + } +}); +// $ExpectError +LocModel.update({ name: 'foo' }, { name: 123 }); +// $ExpectError +LocModel.update({ name: 'foo' }, { $pull: { facilities: 123 } }); +// $ExpectError +LocModel.update({ name: 'foo' }, { $push: { coords: 'bar' } }); + +LocModel.updateOne({ name: 'foo' }, { + name: 'bar', + 'reviews.0': 'test', + $unset: { + rating: '' + }, + $pull: { + facilities: 'foo' + }, + $push: { + coords: 100 + } +}); +// $ExpectError +LocModel.updateOne({ name: 'foo' }, { name: 123 }); +// $ExpectError +LocModel.updateOne({ name: 'foo' }, { $pull: { facilities: 123 } }); +// $ExpectError +LocModel.updateOne({ name: 'foo' }, { $push: { coords: 'bar' } }); + +LocModel.updateMany({ name: 'foo' }, { + name: 'bar', + 'reviews.0': 'test', + $unset: { + rating: '' + }, + $pull: { + facilities: 'foo' + }, + $push: { + coords: 100 + } +}); +// $ExpectError +LocModel.updateMany({ name: 'foo' }, { name: 123 }); +// $ExpectError +LocModel.updateMany({ name: 'foo' }, { $pull: { facilities: 123 } }); +// $ExpectError +LocModel.updateMany({ name: 'foo' }, { $push: { coords: 'bar' } }); diff --git a/types/mongoose/mongoose-tests.ts b/types/mongoose/test/mongoose.ts similarity index 63% rename from types/mongoose/mongoose-tests.ts rename to types/mongoose/test/mongoose.ts index 37b9038cc2..387607e571 100644 --- a/types/mongoose/mongoose-tests.ts +++ b/types/mongoose/test/mongoose.ts @@ -1,6 +1,8 @@ import * as mongodb from 'mongodb'; import * as mongoose from 'mongoose'; +import { MyModel } from './definitions'; + // dummy variables var cb = function () {}; @@ -759,153 +761,6 @@ new mongoose.Schema({}) mongoose.plugin(AwesomeLoggerPlugin, {modelName: 'Executive', timestamp: 'yyyy/MM/dd'}) - -/* - * section document.js - * https://mongoosejs.com/docs/api/document.html - */ -var doc = new mongoose.Document(); -doc.$isDefault('path').valueOf(); -doc.$locals.field = 'value'; -const docDotDepopulate: mongoose.Document = doc.depopulate('path'); -doc.equals(doc).valueOf(); -doc.execPopulate().then(function (arg) { - arg.execPopulate(); -}).catch(function (err) {}); -doc.get('path', Number); -doc.get('path', Number, { virtuals: true, getters: false }); -doc.init(doc).init(doc, {}); -doc.inspect(); -doc.invalidate('path', new Error('hi')).toString(); -doc.invalidate('path', new Error('hi'), 999).toString(); -doc.isDirectModified('path').valueOf(); -doc.isInit('path').valueOf(); -doc.isModified('path').valueOf(); -doc.isSelected('path').valueOf(); -doc.markModified('path'); -doc.modifiedPaths()[0].toLowerCase(); -doc.populate(function (err, doc) { - doc.populate('path', function (err, doc) { - doc.populate({ - path: 'path', - select: 'path', - match: {} - }); - }); -}); -doc.populated('path'); -doc.set('path', 999, {}).set({ path: 999 }); -doc.overwrite({path: 999}); -doc.toJSON({ - getters: true, - virtuals: false -}); -doc.toObject({ - transform: function (doc, ret, options) { - doc.toObject(); - } -}); -doc.toString().toLowerCase(); -doc.unmarkModified('path'); -doc.update(doc, cb).cursor(); -doc.update(doc, { - safe: true, - upsert: true -}, cb).cursor(); -doc.validate({}, function (err) {}); -doc.validate().then(null).catch(null); -(() => { - // Scope to avoid type mixing - var validationError = doc.validateSync(['path1', 'path2']); - if (validationError) { - validationError.stack - } -})() -/* practical examples */ -var MyModel = mongoose.model('test', new mongoose.Schema({ - name: { - type: String, - alias: 'foo', - default: 'Val ' - } -})); -doc = new MyModel(); -doc.$isDefault('name'); -MyModel.findOne().populate('author').exec(function (err, doc) { - if (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); -}); -MyModel.bulkWrite([], { ordered: false }, (err, res) => { - console.log(res.modifiedCount); -}); -doc.populate('path'); -doc.populate({path: 'hello'}); -doc.populate('path', cb) -doc.populate({path: 'hello'}, cb); -doc.populate(cb); -doc.populate({path: 'hello'}).execPopulate().catch(cb); -doc.update({$inc: {wheels:1}}, { w: 1 }, cb); - -const ImageSchema = new mongoose.Schema({ - name: {type: String, required: true}, - 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 -} - -const ImageModel = mongoose.model('image', ImageSchema); - -ImageModel.findOne({}, function(err, doc) { - if (doc) { - doc.name; - doc.id; - } -}); - -/* Using flatten maps example */ -interface Submission extends mongoose.Document { - name: string; - fields: Record; -} -var SubmissionSchema = new mongoose.Schema({ - name: String, - fields: { - type: Map, - of: String - } -}); -const SubmissionModel = mongoose.model('Submission', SubmissionSchema); -const submission = new SubmissionModel({ - name: "Submission Name", - fields: { - extra: "Value", - other: "Thing" - } -}); -submission.save() -.then(result => { - console.log(result.toObject({ - flattenMaps: true - })); -}) -.catch(() => { - console.log("Flatten maps error"); -}); - /* * section types/subdocument.js * http://mongoosejs.com/docs/api.html#types-subdocument-js @@ -1066,354 +921,6 @@ map.delete('key'); map.toObject().delete; map.toObject({ flattenMaps: true }).key; -/* - * section query.js - * http://mongoosejs.com/docs/api.html#query-js - */ -var query = >{}; -query.$where('').$where(cb); -query.all(99).all('path', 99); -query.and([{ color: 'green' }, { status: 'ok' }]).and([]); -query.batchSize(100).batchSize(100); -var lowerLeft = [40.73083, -73.99756] -var upperRight = [40.741404, -73.988135] -query.where('loc').within().box(lowerLeft, upperRight) -query.where('loc').wtimeout() -query.where('loc').wtimeout(10) -query.box({ ll : lowerLeft, ur : upperRight }).box({}); -var queryModel = mongoose.model('QModel') -query.cast(new queryModel(), {}).hasOwnProperty(''); -query.catch(cb).catch(cb); -query.center({}).center({}); -query.centerSphere({ center: [50, 50], radius: 10 }).centerSphere('path', {}); -query.circle({ center: [50, 50], radius: 10 }).circle('path'); -query.collation({ locale: 'en_US', strength: 1 }); -query.comment('comment').comment('comment'); -query.where({color: 'black'}).count(function (err, count) { - count.toFixed(); -}).then(function (res) { - res.toFixed(); -}).catch(function (err) {}); -query.cursor().close(); -query.distinct('field', {}, cb); -query.distinct('field', {}); -query.distinct('field', cb); -query.distinct('field'); -query.distinct(cb); -query.distinct(); -query.elemMatch('comment', { - author: 'autobot', - votes: {$gte: 5} -}).elemMatch('comment', function (elem) { - elem.where('author').equals('autobot'); - elem.where('votes').gte(5); -}); -query.where('age').equals(49); -query.exec('find', function (err, res) { - res[0].execPopulate(); -}).then(function (arg) { - arg[0].execPopulate(); -}).catch(cb); -query.where('name').exists().exists('age', false); -query.find({name: 'aa'}, function (err, res) { - res[0].execPopulate(); -}).find(); -query.findOne(function (err, res) { - res.execPopulate(); -}).findOne(); -query.findOneAndRemove({name: 'aa'}, { - rawResult: true -}, function (err, doc) { - doc.lastErrorObject -}).findOneAndRemove(); -query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, { - -}); -query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, { - rawResult: true -}, cb); -query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, cb); -query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}); -query.findOneAndUpdate({}, {}, { upsert: true, new: true }); -query.findOneAndUpdate({name: 'bb'}, cb); -query.findOneAndUpdate({name: 'bb'}); -query.findOneAndUpdate(cb); -query.findOneAndUpdate().then(function (doc) { - doc.execPopulate(); -}).catch(cb); -var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]] -query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA }) -var polyB = [[ 0, 0 ], [ 1, 1 ]] -query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB }) -var polyC = [ 0, 0 ] -query.where('loc').within().geometry({ type: 'Point', coordinates: polyC }) -query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC }) -query.getQuery(); -query.getUpdate(); -query.find().where('age').gt(21); -query.find().gt('age', 21); -query.find().where('age').gte(21); -query.find().gte('age', 21); -query.hint({ indexA: 1, indexB: -1}).hint({}); -query.in([1, 2, 3]).in('num', [1, 2, 3]); -query.where('path').intersects().geometry({ - type: 'LineString' - , coordinates: [[180.0, 11.0], [180, 9.0]] -}); -query.where('path').intersects({ - type: 'LineString' - , coordinates: [[180.0, 11.0], [180, 9.0]] -}); -query.find().lean().exec(function (err: any, docs: any) { - docs[0]; -}); -query.limit(20).limit(20); -query.find().where('age').lt(21); -query.find().lt('age', 21); -query.find().where('age').lte(21); -query.find().lte('age', 21); -query - .find() - .map(res => { - res.length; - res[0]._id; - return { b: 123 }; - }) - .map(res => { - res.b; - return { c: true }; - }) - .then(res => { - typeof res.c === 'boolean'; - }); -query - .findOne() - .map(res => { - res.save(); - return res; - }) - .then(res => { - res._id; - }); -query.maxDistance('path', 21).maxDistance(21); -query.maxTimeMS(1000); -query.maxscan(100).maxScan(100); -query.maxScan(100).maxScan(100); -query.merge(query).merge({}); -query.mod([1, 2]).mod([5, 6]); -query.find().where('age').ne(21); -query.find().ne('age', 21); -query.where('loc').near({ center: [10, 10] }); -query.where('loc').near({ center: [10, 10], maxDistance: 5 }); -query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true }); -query.near('loc', { center: [10, 10], maxDistance: 5 }); -query.where('loc').nearSphere({ center: [10, 10], maxDistance: 5 }); -query.find().where('age').in([20, 21]); -query.find().in('age', [20, 21]); -query.nor([{ color: 'green' }, { status: 'ok' }]).nor([]); -query.or([{ color: 'red' }, { status: 'emergency' }]).or([]); -query.find({ color: 'blue' }).orFail(); -query.where('loc').within().polygon([10,20], [13, 25], [7,15]); -query.polygon('loc', [10,20], [13, 25], [7,15]); -query.findOne().populate('owner').exec(function (err, kitten) { - kitten.execPopulate(); -}); -query.find().populate({ - path: 'owner' - , select: 'name' - , match: { color: 'black' } - , options: { sort: { name: -1 }} -}).exec(function (err, kittens) { - kittens[0].execPopulate(); -}); -query.find().populate('owner', 'name', null, {sort: { name: -1 }}).exec(function (err, kittens) { - kittens[0].execPopulate(); -}); -query.read('primary', []).read('primary'); -query.readConcern('majority').readConcern('m'); -query.regex(/re/).regex('path', /re/); -query.remove({}, cb); -query.remove({}); -query.remove(cb); -query.remove(); -query.select('a b'); -query.select('-c -d'); -query.select({ a: 1, b: 1 }); -query.select({ c: 0, d: 0 }); -query.select('+path'); -query.selected(); -query.selectedExclusively(); -query.selectedInclusively(); -query.setOptions({ - tailable: true, - batchSize: true, - lean: false -}); -query.setQuery({ age: 5 }); -query.size(0).size('age', 0); -query.skip(100).skip(100); -query.slaveOk().slaveOk(false); -query.slice('comments', 5); -query.slice('comments', -5); -query.slice('comments', [10, 5]); -query.where('comments').slice(5); -query.where('comments').slice([-10, 5]); -query.snapshot().snapshot(true); -query.sort({ field: 'asc', test: -1 }); -query.sort('field -test'); -query.tailable().tailable(false); -query.then(cb).catch(cb); -(new (query.toConstructor())(1, 2, 3)).toConstructor(); -query.update({}, doc, { - -}, cb); -query.update({}, doc, { - -}); -query.update({}, doc, cb); -query.update({}, doc); -query.update(doc, cb); -query.update(doc); -query.update(cb); -query.update(true); -query.update(); -query.where('age').gte(21).lte(65) - .where('name', /^vonderful/i) - .where('friends').slice(10) - .exec(cb); -query.where('path').within().box({}) -query.where('path').within().circle({}) -query.where('path').within().geometry({type: 'c', coordinates: []}); -query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true }); -query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] }); -query.where('loc').within({ polygon: [[],[],[],[]] }); -query.where('loc').within([], [], []); -query.where('loc').within([], []); -query.where('loc').within({ type: 'LineString', coordinates: [] }); -mongoose.Query.use$geoWithin = false; -/* practical example */ -query. - find({ - occupation: /host/, - 'name.last': 'Ghost', - age: { $gt: 17, $lt: 66 }, - likes: { $in: ['vaporizing', 'talking'] } - }). - limit(10). - sort({ occupation: -1 }). - select({ name: 1, occupation: 1 }). - exec(cb).then(cb).catch(cb); -query. - find({ occupation: /host/ }). - where('name.last').equals('Ghost'). - where('age').gt(17).lt(66). - where('likes').in(['vaporizing', 'talking']). - limit(10). - sort('-occupation'). - select('name occupation'). - exec(cb).then(cb).catch(cb); -/** - * https://mongoosejs.com/docs/api.html#query_Query-lean - */ -query.lean() // true -query.lean(false) -query.lean({}) - -interface OtherLocation extends mongoose.Document { - type: string; -} -interface Location1 extends mongoose.Document { - _id: mongodb.ObjectId; - name: string; - address: string; - rating: number; - reviews: any[]; - ref1: mongodb.ObjectId; - // This type is useful for using with `populate()` - ref2: mongodb.ObjectId | OtherLocation; -}; -var loc1Document = {}; -var loc1Query = >{}; -loc1Query.count({ name: 'foo' }); -// $ExpectError -loc1Query.count({ name: 123 }); -loc1Query.countDocuments({ name: 'foo' }); -loc1Query.find({ _id: new mongodb.ObjectId() }); -loc1Query.find({ _id: 'string-allowed' }); -loc1Query.find({ _id: loc1Document }); -// $ExpectError -loc1Query.find({ _id: 123 }); -// $ExpectError -loc1Query.find({ _id: { foo: 'bar' } }); -loc1Query.find({ ref1: new mongodb.ObjectId() }); -loc1Query.find({ ref1: 'string-allowed' }); -// $ExpectError -loc1Query.find({ ref1: 123 }); -loc1Query.find({ ref2: new mongodb.ObjectId() }); -loc1Query.find({ ref2: 'string-allowed' }); -// $ExpectError -loc1Query.find({ ref2: 123 }); -loc1Query.find({ - name: 'foo', - address: /bar/, // strings are allowed as RegExp - rating: 10, - facilities: { $exists: true }, - 'reviews.0': { $exists: true } // additional queries are allowed -}); -// $ExpectError -loc1Query.find({ name: 123 }); -// $ExpectError -loc1Query.find({ rating: 'foo' }); -loc1Query.findOne({ name: 'foo', rating: 10 }); -// $ExpectError -loc1Query.findOne({ rating: 'foo' }); -loc1Query.findOneAndRemove({ name: 'foo', rating: 10 }); -// $ExpectError -loc1Query.findOneAndRemove({ rating: 'foo' }); -loc1Query.findOneAndUpdate({ name: 'foo', rating: 10 }, { rating: 20 }); -// $ExpectError -loc1Query.findOneAndUpdate({ rating: 'foo' }, { rating: 20 }); -loc1Query.remove({ name: 'foo', rating: 10 }); -// $ExpectError -loc1Query.remove({ rating: 'foo' }); -loc1Query.update({ name: 'foo', rating: 10 }, { rating: 20 }); -// $ExpectError -loc1Query.update({ rating: 'foo' }, { rating: 20 }); -loc1Query.lean().then(location => { - if (location) { - // $ExpectType ObjectId - location._id; - // $ExpectType string - location.name; - // $ExpectType number - location.rating; - // $ExpectError - location.unknown; - // $ExpectError - location.save(); - } -}); - -interface Location2 extends mongoose.Document { - _id: string; - name: string; - rating: number; -}; -var loc2Query = >{}; -loc2Query.lean().then(location => { - if (location) { - // $ExpectType string - location._id; - // $ExpectType string - location.name; - // $ExpectType number - location.rating; - // $ExpectError - location.unknown; - // $ExpectError - location.save(); - } -}); /* * section schema/array.js @@ -1801,416 +1308,6 @@ function testPromise_all() { Promise.all([dc]) } -/* - * section model.js - * http://mongoosejs.com/docs/api.html#model-js - */ -var MongoModel = mongoose.model('MongoModel', new mongoose.Schema({ - name: String, - type: { - type: mongoose.Schema.Types.Mixed, - required: true - } -}), 'myCollection', true); -MongoModel.init().then(cb); -MongoModel.find({}).$where('indexOf("val") !== -1').exec(function (err, docs) { - docs[0].save(); - docs[0].__v; -}); -MongoModel.findById(999, function (err, doc) { - var handleSave = function(err: Error, product: mongoose.Document) {}; - if (!doc) { - return; - } - doc.increment(); - doc.save(handleSave).then(cb).catch(cb); - doc.save({ validateBeforeSave: false }, handleSave).then(cb).catch(cb); - doc.save({ safe: true }, handleSave).then(cb).catch(cb); - doc.save({ safe: { w: 2, j: true } }, handleSave).then(cb).catch(cb); - 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) { product.save(); }) - .then(function(p) { p.save() }).catch(cb); - doc.save({ validateBeforeSave: false }, function(err, product) { - product.save(); - }).then(function(p) { p.save() }).catch(cb); -}); -MongoModel = (new MongoModel()).model('MongoModel'); -var mongoModel = new MongoModel(); -mongoModel.remove(function (err, product) { - if (err) throw(err); - MongoModel.findById(product._id, function (err, product) { - if (product) { - product.id.toLowerCase(); - product.remove(); - } - }); -}); -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' } }) - .exec(cb); -MongoModel.count({ type: 'jungle' }, function (err, count) { - count.toFixed(); -}); -MongoModel.create({ - type: 'jelly bean' -}, { - type: 'snickers' -}, cb).then(function (a) { - a.save(); -}) -MongoModel.create([{ type: 'jelly bean' }, { - type: 'snickers' -}], function (err, candies) { - var jellybean = candies[0]; - var snickers = candies[1]; -}).then(function (arg) { - arg[0].save(); - arg[1].save(); -}); -MongoModel.createCollection().then(() => {}); -MongoModel.createCollection({ capped: true, max: 42 }).then(() => {}); -MongoModel.createCollection({ capped: true, max: 42 }, err => {}); -MongoModel.distinct('url', { clicks: {$gt: 100}}, function (err, result) { -}); -MongoModel.distinct('url').exec(cb); -MongoModel.syncIndexes().then(() => {}); -MongoModel.syncIndexes({}).then(() => {}); -MongoModel.syncIndexes(null).then(() => {}); -MongoModel.syncIndexes(undefined).then(() => {}); -MongoModel.syncIndexes({}, err => {}); -MongoModel.syncIndexes(null, err => {}); -MongoModel.syncIndexes(undefined, err => {}); -MongoModel.listIndexes(); -MongoModel.listIndexes(cb); -MongoModel.ensureIndexes({}, cb); -MongoModel.find({ name: 'john', age: { $gte: 18 }}); -MongoModel.find({ name: 'john', age: { $gte: 18 }}, function (err, docs) { - docs[0].remove(); - docs[1].execPopulate(); -}); -MongoModel.find({ name: /john/i }, 'name friends', function (err, docs) { }) -MongoModel.find({ name: /john/i }, null, { skip: 10 }) -MongoModel.find({ name: /john/i }, null, { skip: 10 }, function (err, docs) {}); -MongoModel.find({ name: /john/i }, null, { skip: 10 }).exec(function (err, docs) {}); -MongoModel.findById(999, function (err, adventure) {}); -MongoModel.findById(999).exec(cb); -MongoModel.findById(999, 'name length', function (err, adventure) { - if (adventure) { - adventure.save(); - } -}); -MongoModel.findById(999, 'name length').exec(cb); -MongoModel.findById(999, '-length').exec(function (err, adventure) { - if (adventure) { - adventure.addListener('click', cb); - } -}); -MongoModel.findById(999, 'name', { lean: true }, function (err, doc) {}); -MongoModel.findById(999, 'name').lean().exec(function (err, doc) {}); -MongoModel.findByIdAndRemove(999, {}, cb); -MongoModel.findByIdAndRemove(999, {}); -MongoModel.findByIdAndRemove(999, cb); -MongoModel.findByIdAndRemove(999); -MongoModel.findByIdAndRemove(); -MongoModel.findByIdAndUpdate(999, {}, {}, cb); -MongoModel.findByIdAndUpdate(999, {}, {}); -MongoModel.findByIdAndUpdate(999, {}, { upsert: true, new: true }); -MongoModel.findByIdAndUpdate(999, {}, cb); -MongoModel.findByIdAndUpdate(999, {}); -MongoModel.findByIdAndUpdate(); -MongoModel.findOne({ type: 'iphone' }, function (err, adventure) {}); -MongoModel.findOne({ type: 'iphone' }).exec(function (err, adventure) {}); -MongoModel.findOne({ type: 'iphone' }, 'name', function (err, adventure) {}); -MongoModel.findOne({ type: 'iphone' }, 'name').exec(function (err, adventure) {}); -MongoModel.findOne({ type: 'iphone' }, 'name', { lean: true }, cb); -MongoModel.findOne({ type: 'iphone' }, 'name', { lean: true }).exec(cb); -MongoModel.findOne({ type: 'iphone' }).select('name').lean().exec(cb); -interface ModelUser { - _id: any; - name: string; - abctest: string; -} -MongoModel.findOneAndRemove({}, {}, cb); -MongoModel.findOneAndRemove({}, {}); -MongoModel.findOneAndRemove({}, cb); -MongoModel.findOneAndRemove({}); -MongoModel.findOneAndRemove(); -MongoModel.findOneAndUpdate({}, {}, {}, cb); -MongoModel.findOneAndUpdate({}, {}, {}); -MongoModel.findOneAndUpdate({}, {}, { upsert: true, new: true }); -MongoModel.findOneAndUpdate({}, {}, { upsert: true, new: true, arrayFilters: [{ 'elem._id': 123 }] }); -MongoModel.findOneAndUpdate({}, {}, { upsert: true, new: true, timestamps: true }); -MongoModel.findOneAndUpdate({}, {}, cb); -MongoModel.findOneAndUpdate({}, {}); -MongoModel.findOneAndUpdate(); -MongoModel.geoSearch({ type : "house" }, { - near: [10, 10], maxDistance: 5 -}, function(err, res) { - res[0].remove(); -}); -MongoModel.hydrate({ - _id: '54108337212ffb6d459f854c', - type: 'jelly bean' -}).execPopulate(); -MongoModel.insertMany([ - { name: 'Star Wars' }, - { name: 'The Empire Strikes Back' } -], function(error, docs) {}); -MongoModel.insertMany({name: 'Star Wars'}, function(error, doc) {}); -MongoModel.mapReduce({ - map: cb, - reduce: cb -}, function (err, results) { - console.log(results) -}).then(function (model) { - return model.find().where('value').gt(10).exec(); -}).then(function (docs) { - console.log(docs); -}).then(null, cb); -MongoModel.findById(999, function (err, user) { - if (!user) { - return; - } - var opts = [ - { path: 'company', match: { x: 1 }, select: 'name' } - , { path: 'notes', options: { limit: 10 }, model: 'override' } - ] - MongoModel.populate(user, opts, cb); - MongoModel.populate(user, opts, function (err, user) { - console.log(user); - }); -}); -// $ExpectError -MongoModel.find(999, function (err, users) { - var opts = [{ path: 'company', match: { x: 1 }, select: 'name' }] - var promise = MongoModel.populate(users, opts); - promise.then(console.log); -}); -MongoModel.populate({ - name: 'Indiana Jones', - weapon: 389 -}, { - path: 'weapon', - model: 'Weapon' -}, cb); -var users = [{ name: 'Indiana Jones', weapon: 389 }] -users.push({ name: 'Batman', weapon: 8921 }) -MongoModel.populate(users, { path: 'weapon' }, function (err, users) { - users.forEach(cb); -}); -MongoModel.remove({ title: 'baby born from alien father' }, cb); -MongoModel.remove({_id: '999'}).exec().then(cb).catch(cb); -MongoModel.remove({_id: '999'}).exec().then(res=>console.log(res.ok)); -MongoModel.deleteOne({_id: '999'}).then(res=>console.log(res.ok)); -MongoModel.deleteOne({_id: '999'}).exec().then(res=>console.log(res.ok)); -MongoModel.deleteMany({_id: '999'}).then(res=>console.log('Success?',!!res.ok, 'deleted count', res.n)); -MongoModel.deleteMany({_id: '999'}).exec().then(res=>console.log(res.ok)); -MongoModel.update({ age: { $gt: 18 } }, { oldEnough: true }, cb); -MongoModel.update({ name: 'Tobi' }, { ferret: true }, { multi: true, arrayFilters: [{ element: { $gte: 100 } }] }, cb); -MongoModel.where('age').gte(21).lte(65).exec(cb); -MongoModel.where('age').gte(21).lte(65).where('name', /^b/i); -new (mongoModel.base.model(''))(); -mongoModel.baseModelName && mongoModel.baseModelName.toLowerCase(); -mongoModel.collection.$format(99); -mongoModel.collection.initializeOrderedBulkOp; -mongoModel.collection.findOne; -mongoModel.db.openUri(''); -mongoModel.discriminators; -mongoModel.modelName.toLowerCase(); -MongoModel = mongoModel.base.model('new', mongoModel.schema); -/* inherited properties */ -MongoModel.modelName; -mongoModel.modelName; -MongoModel.collection; -mongoModel.collection; -mongoModel._id; -mongoModel.execPopulate(); -mongoModel.on('data', cb); -mongoModel.addListener('event', cb); -MongoModel.findOne({ title: /timex/i }) - .populate('_creator', 'name') - .exec(function (err, story) { - if (story) { - story.execPopulate(); - } - }); -MongoModel.find({ - id: 999 -}) -.populate({ - path: 'fans', - match: { age: { $gte: 21 }}, - select: 'name -_id', - options: { limit: 5 } -}) -.exec(); -/* practical example */ -interface Location extends mongoose.Document { - _id: mongodb.ObjectId; - name: string; - address: string; - rating: number; - facilities: string[]; - coords: number[]; - openingTimes: any[]; - reviews: any[]; -}; -const locationSchema = new mongoose.Schema({ - name: { type: String, required: true }, - address: String, - rating: { type: Number, "default": 0, min: 0, max: 5 }, - facilities: [String], - coords: { type: [Number], index: "2dsphere" }, - openingTimes: [mongoose.Schema.Types.Mixed], - reviews: [mongoose.SchemaTypes.Mixed] -}); -var locDocument = {}; -var LocModel = mongoose.model("Location", locationSchema); -LocModel.findById(999) - .select("-reviews -rating") - .exec(function (err, location) { - if (!location) { - return; - } - location.name = 'blah'; - location.address = 'blah'; - location.reviews.forEach(review => {}); - location.facilities.forEach(facility => { - facility.toLowerCase(); - }); - }); -LocModel.find() - .select('-reviews -rating') - .exec(function (err, locations) { - locations.forEach(location => { - location.name = 'blah'; - location.address = 'blah'; - location.reviews.forEach(review => {}); - location.facilities.forEach(facility => { - facility.toLowerCase(); - }); - }); - }); -LocModel.find({}).$where('') - .exec(function (err, locations) { - locations[0].name; - locations[1].openingTimes; - }); -LocModel.find({ - name: 'foo', - address: /bar/, // strings are allowed as RegExp - rating: 10, - facilities: { $exists: true }, - 'reviews.0': { $exists: true } // additional queries are allowed -}); -LocModel.find({ _id: new mongodb.ObjectId() }); -LocModel.find({ _id: 'string-allowed' }); -LocModel.find({ _id: locDocument }); -// $ExpectError -LocModel.find({ _id: 123 }); -// $ExpectError -LocModel.find({ _id: { foo: 'bar' } }); -// $ExpectError -LocModel.find({ name: 123 }); -// $ExpectError -LocModel.find({ rating: 'foo' }); -LocModel.count({ name: 'foo'}) - .exec(function (err, count) { - count.toFixed(); - }); -// $ExpectError -LocModel.count({ name: 123 }); -LocModel.countDocuments({ name: 'foo' }); -// $ExpectError -LocModel.countDocuments({ name: 123 }); -LocModel.distinct('') - .select('-review') - .exec(function (err, distinct) { - distinct.concat; - }) - .then(cb).catch(cb); -LocModel.exists({ name: 'foo' }); -// $ExpectError -LocModel.exists({ name: 123 }); -LocModel.findByIdAndRemove() - .exec(function (err, doc) { - if (!doc) { - return; - } - doc.addListener; - doc.openingTimes; - }); -LocModel.findByIdAndUpdate() - .select({}) - .exec(function (err, location) { - if (location) { - location.reviews; - } - }); -LocModel.findOne({}, function (err, doc) { - if (doc) { - doc.openingTimes; - } -}); -LocModel - .findOne({ name: 'foo', rating: 10 }) - .lean() - .exec() - .then(function(doc) { - if (doc) { - // $ExpectType ObjectId - doc._id; - // $ExpectType string - doc.name; - // $ExpectError - doc.unknown; - } - }); -LocModel.findOneAndRemove() - .exec(function (err, location) { - if (location) { - location.name; - } - }); -LocModel.findOneAndRemove({ name: 'foo', rating: 10 }); -LocModel.findOneAndDelete({ name: 'foo', rating: 10 }); -LocModel.findOneAndUpdate().exec().then(function (arg) { - if (arg) { - arg.openingTimes; - } -}); -LocModel.findOneAndUpdate( - // find a document with that filter - {name: "aa"}, - // document to insert when nothing was found - { $set: {name: "bb"} }, - // options - {upsert: true, new: true, runValidators: true, - rawResult: true, multipleCastError: true }); -LocModel.geoSearch({}, { - near: [1, 2], - maxDistance: 22 -}, function (err, res) { res[0].openingTimes; }); -LocModel.remove({ name: 'foo' }); -LocModel.deleteOne({ name: 'foo' }); -LocModel.deleteMany({ name: 'foo' }); -LocModel.replaceOne({ name: 'foo' }, { name: 'bar' }); -LocModel.update({ name: 'foo' }, { name: 'bar' }); -LocModel.updateOne({ name: 'foo' }, { name: 'bar' }); -LocModel.updateMany({ name: 'foo' }, { name: 'bar' }); - interface IStatics { staticMethod2: (a: number) => string; } diff --git a/types/mongoose/test/query.ts b/types/mongoose/test/query.ts new file mode 100644 index 0000000000..0773ad6e43 --- /dev/null +++ b/types/mongoose/test/query.ts @@ -0,0 +1,373 @@ +import * as mongodb from 'mongodb'; +import * as mongoose from 'mongoose'; + +import { Location } from './definitions'; + +// dummy variables +var cb = function () {}; + +/* + * section query.js + * http://mongoosejs.com/docs/api.html#query-js + */ +var doc = {}; +var query = >{}; +query.$where('').$where(cb); +query.all(99).all('path', 99); +query.and([{ color: 'green' }, { status: 'ok' }]).and([]); +query.batchSize(100).batchSize(100); +var lowerLeft = [40.73083, -73.99756] +var upperRight = [40.741404, -73.988135] +query.where('loc').within().box(lowerLeft, upperRight) +query.where('loc').wtimeout() +query.where('loc').wtimeout(10) +query.box({ ll : lowerLeft, ur : upperRight }).box({}); +var queryModel = mongoose.model('QModel') +query.cast(new queryModel(), {}).hasOwnProperty(''); +query.catch(cb).catch(cb); +query.center({}).center({}); +query.centerSphere({ center: [50, 50], radius: 10 }).centerSphere('path', {}); +query.circle({ center: [50, 50], radius: 10 }).circle('path'); +query.collation({ locale: 'en_US', strength: 1 }); +query.comment('comment').comment('comment'); +query.where({color: 'black'}).count(function (err, count) { + count.toFixed(); +}).then(function (res) { + res.toFixed(); +}).catch(function (err) {}); +query.cursor().close(); +query.distinct('field', {}, cb); +query.distinct('field', {}); +query.distinct('field', cb); +query.distinct('field'); +query.distinct(cb); +query.distinct(); +query.elemMatch('comment', { + author: 'autobot', + votes: {$gte: 5} +}).elemMatch('comment', function (elem) { + elem.where('author').equals('autobot'); + elem.where('votes').gte(5); +}); +query.where('age').equals(49); +query.exec('find', function (err, res) { + res[0].execPopulate(); +}).then(function (arg) { + arg[0].execPopulate(); +}).catch(cb); +query.where('name').exists().exists('age', false); +query.find({name: 'aa'}, function (err, res) { + res[0].execPopulate(); +}).find(); +query.findOne(function (err, res) { + res.execPopulate(); +}).findOne(); +query.findOneAndRemove({name: 'aa'}, { + rawResult: true +}, function (err, doc) { + doc.lastErrorObject +}).findOneAndRemove(); +query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, { + +}); +query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, { + rawResult: true +}, cb); +query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}, cb); +query.findOneAndUpdate({name: 'aa'}, {name: 'bb'}); +query.findOneAndUpdate({}, {}, { upsert: true, new: true }); +query.findOneAndUpdate({name: 'bb'}, cb); +query.findOneAndUpdate({name: 'bb'}); +query.findOneAndUpdate(cb); +query.findOneAndUpdate().then(function (doc) { + doc.execPopulate(); +}).catch(cb); +var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]] +query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA }) +var polyB = [[ 0, 0 ], [ 1, 1 ]] +query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB }) +var polyC = [ 0, 0 ] +query.where('loc').within().geometry({ type: 'Point', coordinates: polyC }) +query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC }) +query.getQuery(); +query.getUpdate(); +query.find().where('age').gt(21); +query.find().gt('age', 21); +query.find().where('age').gte(21); +query.find().gte('age', 21); +query.hint({ indexA: 1, indexB: -1}).hint({}); +query.in([1, 2, 3]).in('num', [1, 2, 3]); +query.where('path').intersects().geometry({ + type: 'LineString' + , coordinates: [[180.0, 11.0], [180, 9.0]] +}); +query.where('path').intersects({ + type: 'LineString' + , coordinates: [[180.0, 11.0], [180, 9.0]] +}); +query.find().lean().exec(function (err: any, docs: any) { + docs[0]; +}); +query.limit(20).limit(20); +query.find().where('age').lt(21); +query.find().lt('age', 21); +query.find().where('age').lte(21); +query.find().lte('age', 21); +query + .find() + .map(res => { + res.length; + res[0]._id; + return { b: 123 }; + }) + .map(res => { + res.b; + return { c: true }; + }) + .then(res => { + typeof res.c === 'boolean'; + }); +query + .findOne() + .map(res => { + res.save(); + return res; + }) + .then(res => { + res._id; + }); +query.maxDistance('path', 21).maxDistance(21); +query.maxTimeMS(1000); +query.maxscan(100).maxScan(100); +query.maxScan(100).maxScan(100); +query.merge(query).merge({}); +query.mod([1, 2]).mod([5, 6]); +query.find().where('age').ne(21); +query.find().ne('age', 21); +query.where('loc').near({ center: [10, 10] }); +query.where('loc').near({ center: [10, 10], maxDistance: 5 }); +query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true }); +query.near('loc', { center: [10, 10], maxDistance: 5 }); +query.where('loc').nearSphere({ center: [10, 10], maxDistance: 5 }); +query.find().where('age').in([20, 21]); +query.find().in('age', [20, 21]); +query.nor([{ color: 'green' }, { status: 'ok' }]).nor([]); +query.or([{ color: 'red' }, { status: 'emergency' }]).or([]); +query.find({ color: 'blue' }).orFail(); +query.where('loc').within().polygon([10,20], [13, 25], [7,15]); +query.polygon('loc', [10,20], [13, 25], [7,15]); +query.findOne().populate('owner').exec(function (err, kitten) { + kitten.execPopulate(); +}); +query.find().populate({ + path: 'owner' + , select: 'name' + , match: { color: 'black' } + , options: { sort: { name: -1 }} +}).exec(function (err, kittens) { + kittens[0].execPopulate(); +}); +query.find().populate('owner', 'name', null, {sort: { name: -1 }}).exec(function (err, kittens) { + kittens[0].execPopulate(); +}); +query.read('primary', []).read('primary'); +query.readConcern('majority').readConcern('m'); +query.regex(/re/).regex('path', /re/); +query.remove({}, cb); +query.remove({}); +query.remove(cb); +query.remove(); +query.select('a b'); +query.select('-c -d'); +query.select({ a: 1, b: 1 }); +query.select({ c: 0, d: 0 }); +query.select('+path'); +query.selected(); +query.selectedExclusively(); +query.selectedInclusively(); +query.setOptions({ + tailable: true, + batchSize: true, + lean: false +}); +query.setQuery({ age: 5 }); +query.size(0).size('age', 0); +query.skip(100).skip(100); +query.slaveOk().slaveOk(false); +query.slice('comments', 5); +query.slice('comments', -5); +query.slice('comments', [10, 5]); +query.where('comments').slice(5); +query.where('comments').slice([-10, 5]); +query.snapshot().snapshot(true); +query.sort({ field: 'asc', test: -1 }); +query.sort('field -test'); +query.tailable().tailable(false); +query.then(cb).catch(cb); +(new (query.toConstructor())(1, 2, 3)).toConstructor(); +query.update({}, doc, { + +}, cb); +query.update({}, doc, { + +}); +query.update({}, doc, cb); +query.update({}, doc); +query.update(doc, cb); +query.update(doc); +query.update(cb); +// $ExpectError +query.update(true); +query.update(); +query.where('age').gte(21).lte(65) + .where('name', /^vonderful/i) + .where('friends').slice(10) + .exec(cb); +query.where('path').within().box({}) +query.where('path').within().circle({}) +query.where('path').within().geometry({type: 'c', coordinates: []}); +query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true }); +query.where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] }); +query.where('loc').within({ polygon: [[],[],[],[]] }); +query.where('loc').within([], [], []); +query.where('loc').within([], []); +query.where('loc').within({ type: 'LineString', coordinates: [] }); +mongoose.Query.use$geoWithin = false; +/* practical example */ +query. + find({ + occupation: /host/, + 'name.last': 'Ghost', + age: { $gt: 17, $lt: 66 }, + likes: { $in: ['vaporizing', 'talking'] } + }). + limit(10). + sort({ occupation: -1 }). + select({ name: 1, occupation: 1 }). + exec(cb).then(cb).catch(cb); +query. + find({ occupation: /host/ }). + where('name.last').equals('Ghost'). + where('age').gt(17).lt(66). + where('likes').in(['vaporizing', 'talking']). + limit(10). + sort('-occupation'). + select('name occupation'). + exec(cb).then(cb).catch(cb); +/** + * https://mongoosejs.com/docs/api.html#query_Query-lean + */ +query.lean() // true +query.lean(false) +query.lean({}) + + +var locDocument = {}; +var locationQuery = >{}; +locationQuery.count({ name: 'foo' }); +// $ExpectError +locationQuery.count({ name: 123 }); +locationQuery.countDocuments({ name: 'foo' }); +locationQuery.find({ _id: new mongodb.ObjectId() }); +locationQuery.find({ _id: 'string-allowed' }); +locationQuery.find({ _id: locDocument }); +// $ExpectError +locationQuery.find({ _id: 123 }); +// $ExpectError +locationQuery.find({ _id: { foo: 'bar' } }); +locationQuery.find({ ref1: new mongodb.ObjectId() }); +locationQuery.find({ ref1: 'string-allowed' }); +// $ExpectError +locationQuery.find({ ref1: 123 }); +locationQuery.find({ ref2: new mongodb.ObjectId() }); +locationQuery.find({ ref2: 'string-allowed' }); +// $ExpectError +locationQuery.find({ ref2: 123 }); +locationQuery.find({ + name: 'foo', + address: /bar/, // strings are allowed as RegExp + rating: 10, + facilities: { $exists: true }, + 'reviews.0': { $exists: true } // additional queries are allowed +}); +// $ExpectError +locationQuery.find({ name: 123 }); +// $ExpectError +locationQuery.find({ rating: 'foo' }); +locationQuery.findOne({ name: 'foo', rating: 10 }); +// $ExpectError +locationQuery.findOne({ rating: 'foo' }); +locationQuery.findOneAndRemove({ name: 'foo', rating: 10 }); +// $ExpectError +locationQuery.findOneAndRemove({ rating: 'foo' }); +locationQuery.findOneAndUpdate({ name: 'foo', rating: 10 }, { rating: 20 }); +// $ExpectError +locationQuery.findOneAndUpdate({ rating: 'foo' }, { rating: 20 }); +locationQuery.remove({ name: 'foo', rating: 10 }); +// $ExpectError +locationQuery.remove({ rating: 'foo' }); + +locationQuery.update({ name: 'foo', rating: 10 }, { rating: 20 }); +// $ExpectError +locationQuery.update({ rating: 'foo' }, {rating: 20 }); +locationQuery.update({ name: 'foo' }, { + rating: 20, + 'untyped.field': 'test', + $set: { + name: 'bar', + 'untyped.field': 'foo' + }, + $unset: { + address: '' + }, + $pull: { + reviews: 'foo', + 'untyped.field': 'foo' + }, + $push: { + reviews: 'bar', + 'untyped.field': 'bar' + } +}); +// $ExpectError +locationQuery.update({ name: 'foo' }, { name: 123 }); +// $ExpectError +locationQuery.update({ name: 'foo' }, { $pull: { reviews: 123 } }); +// $ExpectError +locationQuery.update({ name: 'foo' }, { $push: { reviews: 123 } }); + +locationQuery.lean().then(location => { + if (location) { + // $ExpectType ObjectId + location._id; + // $ExpectType string + location.name; + // $ExpectType number + location.rating; + // $ExpectError + location.unknown; + // $ExpectError + location.save(); + } +}); + +interface LocationWithStringID extends mongoose.Document { + _id: string; + name: string; + rating: number; +}; +var locWithStringIDQuery = >{}; +locWithStringIDQuery.lean().then(location => { + if (location) { + // $ExpectType string + location._id; + // $ExpectType string + location.name; + // $ExpectType number + location.rating; + // $ExpectError + location.unknown; + // $ExpectError + location.save(); + } +}); diff --git a/types/mongoose/tsconfig.json b/types/mongoose/tsconfig.json index 55e06ad201..5a0d9e8c9d 100644 --- a/types/mongoose/tsconfig.json +++ b/types/mongoose/tsconfig.json @@ -18,6 +18,9 @@ }, "files": [ "index.d.ts", - "mongoose-tests.ts" + "test/document.ts", + "test/model.ts", + "test/mongoose.ts", + "test/query.ts" ] } \ No newline at end of file