Skip to content

Commit

Permalink
fix(array): allow opting out of converting non-arrays into arrays wit…
Browse files Browse the repository at this point in the history
…h `castNonArrays` option

Fix #7371
  • Loading branch information
vkarpov15 committed Jan 17, 2019
1 parent ced6251 commit d5f76bc
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 10 deletions.
26 changes: 21 additions & 5 deletions lib/schema/array.js
Expand Up @@ -128,6 +128,17 @@ function SchemaArray(key, cast, options, schemaOptions) {
*/
SchemaArray.schemaName = 'Array';

/**
* Options for all arrays.
*
* - `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.
*
* @static options
* @api public
*/

SchemaArray.options = { castNonArrays: true };

/*!
* Inherits from SchemaType.
*/
Expand Down Expand Up @@ -217,12 +228,17 @@ SchemaArray.prototype.cast = function(value, doc, init) {

return value;
}
// gh-2442: if we're loading this from the db and its not an array, mark
// the whole array as modified.
if (!!doc && !!init) {
doc.markModified(this.path);

if (init || SchemaArray.options.castNonArrays) {
// gh-2442: if we're loading this from the db and its not an array, mark
// the whole array as modified.
if (!!doc && !!init) {
doc.markModified(this.path);
}
return this.cast([value], doc, init);
}
return this.cast([value], doc, init);

throw new CastError('Array', util.inspect(value), this.path);
};

/*!
Expand Down
14 changes: 14 additions & 0 deletions lib/schema/documentarray.js
Expand Up @@ -61,6 +61,17 @@ function DocumentArray(key, schema, options, schemaOptions) {
*/
DocumentArray.schemaName = 'DocumentArray';

/**
* Options for all document arrays.
*
* - `castNonArrays`: `true` by default. If `false`, Mongoose will throw a CastError when a value isn't an array. If `true`, Mongoose will wrap the provided value in an array before casting.
*
* @static options
* @api public
*/

DocumentArray.options = { castNonArrays: true };

/*!
* Inherits from ArrayType.
*/
Expand Down Expand Up @@ -310,6 +321,9 @@ DocumentArray.prototype.cast = function(value, doc, init, prev, options) {
const _opts = { transform: false, virtuals: false };

if (!Array.isArray(value)) {
if (!init && !DocumentArray.options.castNonArrays) {
throw new CastError('DocumentArray', util.inspect(value), this.path);
}
// gh-2442 mark whole array as modified if we're initializing a doc from
// the db and the path isn't an array in the document
if (!!doc && init) {
Expand Down
21 changes: 16 additions & 5 deletions test/types.array.test.js
Expand Up @@ -1114,25 +1114,36 @@ describe('types array', function() {
});

describe('options', function() {
let options;
let arrOptions;
let docArrOptions;

beforeEach(function() {
options = Object.assign({}, mongoose.Schema.Types.Array.options);
arrOptions = Object.assign({}, mongoose.Schema.Types.Array.options);
docArrOptions = Object.assign({}, mongoose.Schema.Types.DocumentArray.options);
});

afterEach(function() {
mongoose.Schema.Types.Array.options = options;
mongoose.Schema.Types.Array.options = arrOptions;
mongoose.Schema.Types.DocumentArray.options = docArrOptions;
});

it('castNonArrays (gh-7371)', function() {
mongoose.Schema.Types.Array.options.castNonArrays = false;
mongoose.Schema.Types.DocumentArray.options.castNonArrays = false;

const schema = new Schema({ arr: [String] });
const schema = new Schema({ arr: [String], docArr: [{ name: String }] });
const Model = db.model('gh7371', schema);

const doc = new Model({ arr: 'fail' });
let doc = new Model({ arr: 'fail', docArr: { name: 'fail' } });
assert.ok(doc.validateSync().errors);
assert.equal(doc.validateSync().errors['arr'].name, 'CastError');
assert.equal(doc.validateSync().errors['docArr'].name, 'CastError');

doc = new Model({ arr: ['good'] });
assert.ifError(doc.validateSync());
doc.arr.push('foo');
assert.ifError(doc.validateSync());
assert.deepEqual(doc.arr.toObject(), ['good', 'foo']);

return Promise.resolve();
});
Expand Down

0 comments on commit d5f76bc

Please sign in to comment.