Skip to content

Commit

Permalink
Merge branch 'master' into gh6750
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed Jul 27, 2018
2 parents 8af7c86 + 88457b0 commit a0aaa82
Show file tree
Hide file tree
Showing 13 changed files with 233 additions and 81 deletions.
16 changes: 8 additions & 8 deletions docs/schematypes.jade
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,8 @@ block content
* `trim`: boolean, whether to always call `.trim()` on the value
* `match`: RegExp, creates a [validator](./validation.html) that checks if the value matches the given regular expression
* `enum`: Array, creates a [validator](./validation.html) that checks if the value is in the given array.
* `minlength`: Number, creates a [validator](./validation.html) that checks if the value length is not less then the given number
* `maxlength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater then the given number
* `minlength`: Number, creates a [validator](./validation.html) that checks if the value length is not less than the given number
* `maxlength`: Number, creates a [validator](./validation.html) that checks if the value length is not greater than the given number

<h5>Number</h5>

Expand Down Expand Up @@ -266,7 +266,7 @@ block content
console.log(mongoose.Schema.Types.Boolean.convertToFalse);

mongoose.Schema.Types.Boolean.convertToFalse.add('nay');
console.log(new M({ b: 'nay' }).b); // true
console.log(new M({ b: 'nay' }).b); // false
```

<h4 id="arrays">Arrays</h4>
Expand All @@ -278,10 +278,10 @@ block content

```javascript
var ToySchema = new Schema({ name: String });
var ToyBox = new Schema({
var ToyBoxSchema = new Schema({
toys: [ToySchema],
buffers: [Buffer],
string: [String],
strings: [String],
numbers: [Number]
// ... etc
});
Expand All @@ -290,14 +290,14 @@ block content
Arrays are special because they implicitly have a default value of `[]` (empty array).

```javascript
var Toy = mongoose.model('Test', ToySchema);
console.log((new Toy()).toys); // []
var ToyBox = mongoose.model('ToyBox', ToyBoxSchema);
console.log((new ToyBox()).toys); // []
```

To overwrite this default, you need to set the default value to `undefined`

```javascript
var ToySchema = new Schema({
var ToyBoxSchema = new Schema({
toys: {
type: [ToySchema],
default: undefined
Expand Down
11 changes: 11 additions & 0 deletions docs/transactions.jade
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,17 @@ block content
[require:transactions.*save]
```

## With the Aggregation Framework

The `Model.aggregate()` function also supports transactions. Mongoose
aggregations have a [`session()` helper](/docs/api.html#aggregate_Aggregate-session)
that sets the [`session` option](/docs/api.html#aggregate_Aggregate-option).
Below is an example of executing an aggregation within a transaction.

```javascript
[require:transactions.*aggregate]
```

block append layout
script.
_native.init("CK7DT53U", {
Expand Down
22 changes: 22 additions & 0 deletions lib/aggregate.js
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,27 @@ Aggregate.prototype.hint = function(value) {
return this;
};

/**
* Sets the session for this aggregation. Useful for [transactions](/docs/transactions.html).
*
* ####Example:
*
* const session = await Model.startSession();
* await Model.aggregate(..).session(session);
*
* @param {ClientSession} session
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
*/

Aggregate.prototype.session = function(session) {
if (session == null) {
delete this.options.session;
return;
}
this.options.session = session;
return this;
};

/**
* Lets you set arbitrary options, for middleware or plugins.
*
Expand All @@ -645,6 +666,7 @@ Aggregate.prototype.hint = function(value) {
* @param [options.maxTimeMS] number limits the time this aggregation will run, see [MongoDB docs on `maxTimeMS`](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/)
* @param [options.allowDiskUse] boolean if true, the MongoDB server will use the hard drive to store data during this aggregation
* @param [options.collation] object see [`Aggregate.prototype.collation()`](./docs/api.html#aggregate_Aggregate-collation)
* @param [options.session] ClientSession see [`Aggregate.prototype.session()`](./docs/api.html#aggregate_Aggregate-session)
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
* @return {Aggregate} this
* @api public
Expand Down
7 changes: 7 additions & 0 deletions lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,13 @@ Connection.prototype.openUri = function(uri, options, callback) {
options = null;
}

if (['string', 'number'].indexOf(typeof options) !== -1) {
throw new MongooseError('Mongoose 5.x no longer supports ' +
'`mongoose.connect(host, dbname, port)` or ' +
'`mongoose.createConnection(host, dbname, port)`. See ' +
'http://mongoosejs.com/docs/connections.html for supported connection syntax');
}

const Promise = PromiseProvider.get();
const _this = this;

Expand Down
11 changes: 11 additions & 0 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -2757,6 +2757,17 @@ Document.prototype.populate = function populate() {
populateOptions.path = nestedPath + '.' + populateOptions.path;
});
}

// Use `$session()` by default if the document has an associated session
// See gh-6754
if (this.$session() != null) {
const session = this.$session();
paths.forEach(path => {
path.options = path.options || {};
path.options.session = session;
});
}

topLevelModel.populate(this, paths, fn);
}

Expand Down
37 changes: 37 additions & 0 deletions lib/helpers/query/applyQueryMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';

/*!
* Apply query middleware
*
* @param {Query} query constructor
* @param {Model} model
*/

module.exports = function applyQueryMiddleware(Query, model) {
const kareemOptions = {
useErrorHandlers: true,
numCallbackParams: 1,
nullResultByDefault: true
};

// `update()` thunk has a different name because `_update` was already taken
Query.prototype._execUpdate = model.hooks.createWrapper('update',
Query.prototype._execUpdate, null, kareemOptions);

[
'count',
'countDocuments',
'estimatedDocumentCount',
'find',
'findOne',
'findOneAndDelete',
'findOneAndRemove',
'findOneAndUpdate',
'replaceOne',
'updateMany',
'updateOne'
].forEach(fn => {
Query.prototype[`_${fn}`] = model.hooks.createWrapper(fn,
Query.prototype[`_${fn}`], null, kareemOptions);
});
};
3 changes: 0 additions & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,6 @@ Mongoose.prototype.get = Mongoose.prototype.set;
* var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
* db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
*
* // with [host, database_name[, port] signature
* db = mongoose.createConnection('localhost', 'database', port)
*
* // and options
* var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
* db = mongoose.createConnection('localhost', 'database', port, opts)
Expand Down
104 changes: 35 additions & 69 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,40 +4,41 @@
* Module dependencies.
*/

var Aggregate = require('./aggregate');
var ChangeStream = require('./cursor/ChangeStream');
var Document = require('./document');
var DocumentNotFoundError = require('./error').DocumentNotFoundError;
var DivergentArrayError = require('./error').DivergentArrayError;
var Error = require('./error');
var EventEmitter = require('events').EventEmitter;
var MongooseMap = require('./types/map');
var OverwriteModelError = require('./error').OverwriteModelError;
var PromiseProvider = require('./promise_provider');
var Query = require('./query');
var Schema = require('./schema');
var VersionError = require('./error').VersionError;
var ParallelSaveError = require('./error').ParallelSaveError;
var applyHooks = require('./helpers/model/applyHooks');
var applyMethods = require('./helpers/model/applyMethods');
var applyStatics = require('./helpers/model/applyStatics');
var applyWriteConcern = require('./helpers/schema/applyWriteConcern');
var cast = require('./cast');
var castUpdate = require('./helpers/query/castUpdate');
var discriminator = require('./helpers/model/discriminator');
var getDiscriminatorByValue = require('./queryhelpers').getDiscriminatorByValue;
var immediate = require('./helpers/immediate');
var internalToObjectOptions = require('./options').internalToObjectOptions;
var isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
var get = require('lodash.get');
var getSchemaTypes = require('./helpers/populate/getSchemaTypes');
var getVirtual = require('./helpers/populate/getVirtual');
var modifiedPaths = require('./helpers/update/modifiedPaths');
var mpath = require('mpath');
var parallel = require('async/parallel');
var parallelLimit = require('async/parallelLimit');
var setDefaultsOnInsert = require('./helpers/setDefaultsOnInsert');
var utils = require('./utils');
const Aggregate = require('./aggregate');
const ChangeStream = require('./cursor/ChangeStream');
const Document = require('./document');
const DocumentNotFoundError = require('./error').DocumentNotFoundError;
const DivergentArrayError = require('./error').DivergentArrayError;
const Error = require('./error');
const EventEmitter = require('events').EventEmitter;
const MongooseMap = require('./types/map');
const OverwriteModelError = require('./error').OverwriteModelError;
const PromiseProvider = require('./promise_provider');
const Query = require('./query');
const Schema = require('./schema');
const VersionError = require('./error').VersionError;
const ParallelSaveError = require('./error').ParallelSaveError;
const applyQueryMiddleware = require('./helpers/query/applyQueryMiddleware');
const applyHooks = require('./helpers/model/applyHooks');
const applyMethods = require('./helpers/model/applyMethods');
const applyStatics = require('./helpers/model/applyStatics');
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
const cast = require('./cast');
const castUpdate = require('./helpers/query/castUpdate');
const discriminator = require('./helpers/model/discriminator');
const getDiscriminatorByValue = require('./queryhelpers').getDiscriminatorByValue;
const immediate = require('./helpers/immediate');
const internalToObjectOptions = require('./options').internalToObjectOptions;
const isPathSelectedInclusive = require('./helpers/projection/isPathSelectedInclusive');
const get = require('lodash.get');
const getSchemaTypes = require('./helpers/populate/getSchemaTypes');
const getVirtual = require('./helpers/populate/getVirtual');
const modifiedPaths = require('./helpers/update/modifiedPaths');
const mpath = require('mpath');
const parallel = require('async/parallel');
const parallelLimit = require('async/parallelLimit');
const setDefaultsOnInsert = require('./helpers/setDefaultsOnInsert');
const utils = require('./utils');

const VERSION_WHERE = 1;
const VERSION_INC = 2;
Expand Down Expand Up @@ -4380,41 +4381,6 @@ function applyQueryMethods(model, methods) {
}
}

/*!
* Apply query middleware
*
* @param {Model} model
*/

function applyQueryMiddleware(Query, model) {
const kareemOptions = {
useErrorHandlers: true,
numCallbackParams: 1,
nullResultByDefault: true
};

// `update()` thunk has a different name because `_update` was already taken
Query.prototype._execUpdate = model.hooks.createWrapper('update',
Query.prototype._execUpdate, null, kareemOptions);

[
'count',
'countDocuments',
'estimatedDocumentCount',
'find',
'findOne',
'findOneAndDelete',
'findOneAndRemove',
'findOneAndUpdate',
'replaceOne',
'updateMany',
'updateOne'
].forEach(fn => {
Query.prototype[`_${fn}`] = model.hooks.createWrapper(fn,
Query.prototype[`_${fn}`], null, kareemOptions);
});
}

/*!
* Subclass this model with `conn`, `schema`, and `collection` settings.
*
Expand Down
4 changes: 4 additions & 0 deletions lib/types/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ class MongooseMap extends Map {
return new Map(this);
}

toObject() {
return new Map(this);
}

toJSON() {
let ret = {};
const keys = this.keys();
Expand Down
5 changes: 4 additions & 1 deletion lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,10 @@ exports.isMongooseObject = function(v) {
return false;
}

return v.$__ != null || v.isMongooseArray || v.isMongooseBuffer;
return v.$__ != null || // Document
v.isMongooseArray || // Array or Document Array
v.isMongooseBuffer || // Buffer
v.$isMongooseMap; // Map
};
var isMongooseObject = exports.isMongooseObject;

Expand Down
7 changes: 7 additions & 0 deletions test/connection.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,13 @@ describe('connections:', function() {
}).catch(done);
});

it('throws helpful error with legacy syntax (gh-6756)', function(done) {
assert.throws(function() {
mongoose.createConnection('localhost', 'dbname', 27017);
}, /mongoosejs\.com.*connections\.html/);
done();
});

it('resolving with q (gh-5714)', function(done) {
var bootMongo = Q.defer();

Expand Down

0 comments on commit a0aaa82

Please sign in to comment.