Skip to content

Commit

Permalink
Merge pull request #9016 from AbdelrahmanHafez/gh-6658
Browse files Browse the repository at this point in the history
fix(base): allow global option mongoose.set('strictQuery', true);
  • Loading branch information
vkarpov15 committed May 18, 2020
2 parents eab6cc0 + 625a925 commit 63dbf7c
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 5 deletions.
4 changes: 2 additions & 2 deletions docs/guide.pug
Expand Up @@ -688,7 +688,7 @@ block content
_Note that Mongoose does not send the `shardcollection` command for you. You
must configure your shards yourself._

<h3 id="strict">option: strict</h3>
<h3 id="strict"><a href="#strict">option: strict</a></h3>

The strict option, (enabled by default), ensures that values passed to our
model constructor that were not specified in our schema do not get saved to
Expand Down Expand Up @@ -739,7 +739,7 @@ block content
thing.save(); // iAmNotInTheSchema is never saved to the db
```

<h3 id="strictQuery">option: strictQuery</h3>
<h3 id="strictQuery"><a href="#strictQuery">option: strictQuery</a></h3>

For backwards compatibility, the `strict` option does **not** apply to
the `filter` parameter for queries.
Expand Down
1 change: 1 addition & 0 deletions lib/index.js
Expand Up @@ -160,6 +160,7 @@ Mongoose.prototype.driver = require('./driver');
* - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api.html#document_Document-toObject)
* - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()`
* - 'strict': true by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas.
* - 'strictQuery': false by default, may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas.
* - 'selectPopulatedPaths': true by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one.
* - 'typePojoToMixed': true by default, may be `false` or `true`. Sets the default typePojoToMixed for schemas.
* - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query
Expand Down
13 changes: 13 additions & 0 deletions lib/model.js
Expand Up @@ -3381,6 +3381,19 @@ Model.$__insertMany = function(arr, options, callback) {

_this.collection.insertMany(docObjects, options, function(error, res) {
if (error) {
// `writeErrors` is a property reported by the MongoDB driver,
// just not if there's only 1 error.
if (error.writeErrors == null &&
get(error, 'result.result.writeErrors') != null) {
error.writeErrors = error.result.result.writeErrors;
}

// `insertedDocs` is a Mongoose-specific property
const erroredIndexes = new Set(error.writeErrors.map(err => err.index));
error.insertedDocs = docAttributes.filter((doc, i) => {
return !erroredIndexes.has(i);
});

callback(error, null);
return;
}
Expand Down
1 change: 1 addition & 0 deletions lib/schema.js
Expand Up @@ -400,6 +400,7 @@ Schema.prototype.defaultOptions = function(options) {
const baseOptions = get(this, 'base.options', {});
options = utils.options({
strict: 'strict' in baseOptions ? baseOptions.strict : true,
strictQuery: 'strictQuery' in baseOptions ? baseOptions.strictQuery : false,
bufferCommands: true,
capped: false, // { size, max, autoIndexId }
versionKey: '__v',
Expand Down
12 changes: 9 additions & 3 deletions lib/types/core_array.js
Expand Up @@ -879,7 +879,7 @@ class CoreMongooseArray extends Array {
*
* ####Note:
*
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwriting any changes that happen between when you retrieved the object and when you save it._
*
* @api public
* @method unshift
Expand All @@ -889,8 +889,14 @@ class CoreMongooseArray extends Array {
unshift() {
_checkManualPopulation(this, arguments);

let values = [].map.call(arguments, this._cast, this);
values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol]);
let values;
if (this[arraySchemaSymbol] == null) {
values = arguments;
} else {
values = [].map.call(arguments, this._cast, this);
values = this[arraySchemaSymbol].applySetters(values, this[arrayParentSymbol]);
}

[].unshift.apply(this, values);
this._registerAtomic('$set', this);
this._markModified();
Expand Down
1 change: 1 addition & 0 deletions lib/validoptions.js
Expand Up @@ -17,6 +17,7 @@ const VALID_OPTIONS = Object.freeze([
'runValidators',
'selectPopulatedPaths',
'strict',
'strictQuery',
'toJSON',
'toObject',
'useCreateIndex',
Expand Down
36 changes: 36 additions & 0 deletions test/model.test.js
Expand Up @@ -4528,6 +4528,42 @@ describe('Model', function() {
}
});

it('insertMany() `writeErrors` if only one error (gh-8938)', function() {
const QuestionType = new mongoose.Schema({
code: { type: String, required: true, unique: true },
text: String
});
const Question = db.model('Test', QuestionType);

return co(function*() {
yield Question.init();

yield Question.create({ code: 'MEDIUM', text: '123' });
const data = [
{ code: 'MEDIUM', text: '1111' },
{ code: 'test', text: '222' },
{ code: 'HARD', text: '2222' }
];
const opts = { ordered: false, rawResult: true };
let err = yield Question.insertMany(data, opts).catch(err => err);
assert.ok(Array.isArray(err.writeErrors));
assert.equal(err.writeErrors.length, 1);
assert.equal(err.insertedDocs.length, 2);
assert.equal(err.insertedDocs[0].code, 'test');
assert.equal(err.insertedDocs[1].code, 'HARD');

yield Question.deleteMany({});
yield Question.create({ code: 'MEDIUM', text: '123' });
yield Question.create({ code: 'HARD', text: '123' });

err = yield Question.insertMany(data, opts).catch(err => err);
assert.ok(Array.isArray(err.writeErrors));
assert.equal(err.writeErrors.length, 2);
assert.equal(err.insertedDocs.length, 1);
assert.equal(err.insertedDocs[0].code, 'test');
});
});

it('insertMany() ordered option for single validation error', function(done) {
start.mongodVersion(function(err, version) {
if (err) {
Expand Down
29 changes: 29 additions & 0 deletions test/schema.test.js
Expand Up @@ -2425,6 +2425,35 @@ describe('schema', function() {
});
});

describe('mongoose.set(`strictQuery`, value); (gh-6658)', function() {
let strictQueryOriginalValue;

this.beforeEach(() => strictQueryOriginalValue = mongoose.get('strictQuery'));
this.afterEach(() => mongoose.set('strictQuery', strictQueryOriginalValue));

it('setting `strictQuery` on base sets strictQuery to schema (gh-6658)', function() {
// Arrange
mongoose.set('strictQuery', 'some value');

// Act
const schema = new Schema();

// Assert
assert.equal(schema.get('strictQuery'), 'some value');
});

it('`strictQuery` set on base gets overwritten by option set on schema (gh-6658)', function() {
// Arrange
mongoose.set('strictQuery', 'base option');

// Act
const schema = new Schema({}, { strictQuery: 'schema option' });

// Assert
assert.equal(schema.get('strictQuery'), 'schema option');
});
});

it('treats dotted paths with no parent as a nested path (gh-9020)', function() {
const customerSchema = new Schema({
'card.brand': String,
Expand Down
21 changes: 21 additions & 0 deletions test/types.documentarray.test.js
Expand Up @@ -611,6 +611,27 @@ describe('types.documentarray', function() {
'd'
]);
});

it('unshift() after map() works (gh-9012)', function() {
const MyModel = db.model('Test', Schema({
myArray: [{ name: String }]
}));

const doc = new MyModel({
myArray: [{ name: 'b' }, { name: 'c' }]
});
let myArray = doc.myArray;

myArray = myArray.map(val => ({ name: `${val.name} mapped` }));

myArray.unshift({ name: 'a inserted' });

assert.deepEqual(myArray.map(v => v.name), [
'a inserted',
'b mapped',
'c mapped'
]);
});
});

it('cleans modified subpaths on splice() (gh-7249)', function() {
Expand Down

0 comments on commit 63dbf7c

Please sign in to comment.