Skip to content

Commit

Permalink
Merge branch 'master' into Automatticgh-13081
Browse files Browse the repository at this point in the history
  • Loading branch information
lpizzinidev committed Mar 2, 2023
2 parents 64fec6a + 260261d commit daef366
Show file tree
Hide file tree
Showing 8 changed files with 116 additions and 77 deletions.
16 changes: 8 additions & 8 deletions docs/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ Below are the [semver](http://semver.org/) ranges representing which versions of

| MongoDB Server | Mongoose |
| :------------: | :---------------------------: |
| `6.x` | `^6.5.0` |
| `5.x` | `^6.0.0` |
| `4.4.x` | `^5.10.0 \| ^6.0.0` |
| `4.2.x` | `^5.7.0 \| ^6.0.0` |
| `4.0.x` | `^5.2.0 \| ^6.0.0` |
| `3.6.x` | `^5.0.0` |
| `6.x` | `^6.5.0 \| ^7.0.0` |
| `5.x` | `^6.0.0 \| ^7.0.0` |
| `4.4.x` | `^5.10.0 \| ^6.0.0 \| ^7.0.0` |
| `4.2.x` | `^5.7.0 \| ^6.0.0 \| ^7.0.0` |
| `4.0.x` | `^5.2.0 \| ^6.0.0 \| ^7.0.0` |
| `3.6.x` | `^5.0.0 \| ^6.0.0 \| ^7.0.0` |
| `3.4.x` | `^4.7.3 \| ^5.0.0` |
| `3.2.x` | `^4.3.0 \| 5.0.0` |
| `3.2.x` | `^4.3.0 \| ^5.0.0` |
| `3.0.x` | `^3.8.22 \| ^4.0.0 \| ^5.0.0` |
| `2.6.x` | `^3.8.8 \| ^4.0.0` |
| `2.6.x` | `^3.8.8 \| ^4.0.0 \| ^5.0.0` |
| `2.4.x` | `^3.8.0 \| ^4.0.0` |

Note that Mongoose `5.x` dropped support for all versions of MongoDB before `3.0.0`. If you need to use MongoDB `2.6` or older, use Mongoose `4.x`.
9 changes: 1 addition & 8 deletions lib/cast.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,11 @@ module.exports = function cast(schema, obj, options, context) {
if (!Array.isArray(val)) {
throw new CastError('Array', val, path);
}
for (let k = val.length - 1; k >= 0; k--) {
for (let k = 0; k < val.length; ++k) {
if (val[k] == null || typeof val[k] !== 'object') {
throw new CastError('Object', val[k], path + '.' + k);
}
val[k] = cast(schema, val[k], options, context);
if (Object.keys(val[k]).length === 0) {
val.splice(k, 1);
}
}

if (val.length === 0) {
delete obj[path];
}
} else if (path === '$where') {
type = typeof val;
Expand Down
5 changes: 4 additions & 1 deletion lib/schema/uuid.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,10 @@ SchemaUUID.checkRequired = SchemaType.checkRequired;
*/

SchemaUUID.prototype.checkRequired = function checkRequired(value) {
return UUID_FORMAT.test(value);
if (Buffer.isBuffer(value)) {
value = binaryToString(value);
}
return value != null && UUID_FORMAT.test(value);
};

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/schematype.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ SchemaType.prototype.validators;
* @memberOf SchemaType
*/

SchemaType.prototype.validators;
SchemaType.prototype.isRequired;

/**
* Split the current dottet path into segments
Expand Down
18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
"sift": "16.0.1"
},
"devDependencies": {
"@babel/core": "7.20.12",
"@babel/core": "7.21.0",
"@babel/preset-env": "7.20.2",
"@typescript-eslint/eslint-plugin": "5.50.0",
"@typescript-eslint/parser": "5.50.0",
"@typescript-eslint/eslint-plugin": "5.54.0",
"@typescript-eslint/parser": "5.54.0",
"acquit": "1.3.0",
"acquit-ignore": "0.2.1",
"acquit-require": "0.1.1",
Expand All @@ -45,7 +45,7 @@
"crypto-browserify": "3.12.0",
"dotenv": "16.0.3",
"dox": "1.0.0",
"eslint": "8.33.0",
"eslint": "8.35.0",
"eslint-plugin-mocha-no-only": "1.1.1",
"express": "^4.18.1",
"highlight.js": "11.7.0",
Expand Down Expand Up @@ -75,12 +75,12 @@
"docs:clean:stable": "rimraf index.html && rimraf -rf ./docs/*.html && rimraf -rf ./docs/api && rimraf -rf ./docs/tutorials/*.html && rimraf -rf ./docs/typescript/*.html && rimraf -rf ./docs/*.html && rimraf -rf ./docs/source/_docs && rimraf -rf ./tmp",
"docs:clean:5x": "rimraf index.html && rimraf -rf ./docs/5.x && rimraf -rf ./docs/source/_docs && rimraf -rf ./tmp",
"docs:clean:6x": "rimraf index.html && rimraf -rf ./docs/6.x && rimraf -rf ./docs/source/_docs && rimraf -rf ./tmp",
"docs:copy:tmp": "mkdirp ./tmp/docs/css && mkdirp ./tmp/docs/js && mkdirp ./tmp/docs/images && mkdirp ./tmp/docs/tutorials && mkdirp ./tmp/docs/typescript && ncp ./docs/css ./tmp/docs/css --filter=.css$ && ncp ./docs/js ./tmp/docs/js --filter=.js$ && ncp ./docs/images ./tmp/docs/images && ncp ./docs/tutorials ./tmp/docs/tutorials && ncp ./docs/typescript ./tmp/docs/typescript && cp index.html ./tmp",
"docs:copy:tmp": "mkdirp ./tmp/docs/css && mkdirp ./tmp/docs/js && mkdirp ./tmp/docs/images && mkdirp ./tmp/docs/tutorials && mkdirp ./tmp/docs/typescript && ncp ./docs/css ./tmp/docs/css --filter=.css$ && ncp ./docs/js ./tmp/docs/js --filter=.js$ && ncp ./docs/images ./tmp/docs/images && ncp ./docs/tutorials ./tmp/docs/tutorials && ncp ./docs/typescript ./tmp/docs/typescript && cp index.html ./tmp && cp docs/*.html ./tmp/docs/",
"docs:copy:tmp:5x": "rimraf ./docs/5.x && ncp ./tmp ./docs/5.x",
"docs:copy:tmp:6x": "rimraf ./docs/5.x && ncp ./tmp ./docs/5.x",
"docs:copy:tmp:6x": "rimraf ./docs/6.x && ncp ./tmp ./docs/6.x",
"docs:checkout:gh-pages": "git checkout gh-pages",
"docs:checkout:5x": "git checkout 5.x",
"docs:checkout:6x": "git checkout 5.x",
"docs:checkout:6x": "git checkout 6.x",
"docs:generate": "node ./scripts/website.js",
"docs:generate:search": "node ./scripts/generateSearch.js",
"docs:merge:stable": "git merge master",
Expand All @@ -89,8 +89,8 @@
"docs:test": "npm run docs:generate && npm run docs:generate:search",
"docs:view": "node ./scripts/static.js",
"docs:prepare:publish:stable": "npm run docs:checkout:gh-pages && npm run docs:merge:stable && npm run docs:clean:stable && npm run docs:generate && npm run docs:generate:search",
"docs:prepare:publish:5x": "npm run docs:checkout:5x && npm run docs:merge:5x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && docs:checkout:gh-pages && docs:copy:tmp:5x",
"docs:prepare:publish:6x": "npm run docs:checkout:6x && npm run docs:merge:6x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && docs:checkout:gh-pages && docs:copy:tmp:6x",
"docs:prepare:publish:5x": "npm run docs:checkout:5x && npm run docs:merge:5x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && npm run docs:checkout:gh-pages && npm run docs:copy:tmp:5x",
"docs:prepare:publish:6x": "npm run docs:checkout:6x && npm run docs:merge:6x && npm run docs:clean:stable && npm run docs:generate && npm run docs:copy:tmp && npm run docs:checkout:gh-pages && npm run docs:copy:tmp:6x",
"docs:check-links": "blc http://127.0.0.1:8089 -ro",
"lint": "eslint .",
"lint-js": "eslint . --ext .js",
Expand Down
4 changes: 1 addition & 3 deletions scripts/generateSearch.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ markdown.setOptions({
}
});

mongoose.set('strictQuery', false);

// 5.13.5 -> 5.x, 6.8.2 -> 6.x, etc.
version = version.slice(0, version.indexOf('.')) + '.x';

Expand Down Expand Up @@ -127,7 +125,7 @@ async function run() {
process.exit(-1);
}

await mongoose.connect(config.uri, { dbName: 'mongoose' });
await mongoose.connect(config.uri, { dbName: 'mongoose', serverSelectionTimeoutMS: 5000 });

// wait for the index to be created
await Content.init();
Expand Down
76 changes: 29 additions & 47 deletions test/docs/cast.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,58 +101,40 @@ describe('Cast Tutorial', function() {
await query.exec();
});

describe('strictQuery', function() {
it('strictQuery true - simple object', async function() {
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
strictQuery: true
});
Character = mongoose.model('Character', schema);

const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

await query.exec();
query.getFilter(); // Empty object `{}`, Mongoose removes `notInSchema`
// acquit:ignore:start
assert.deepEqual(query.getFilter(), {});
// acquit:ignore:end
it('strictQuery true', async function() {
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
strictQuery: true
});
Character = mongoose.model('Character', schema);

it('strictQuery true - conditions', async function() {
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
strictQuery: true
});
Character = mongoose.model('Character', schema);
const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

const query = Character.findOne({ $or: [{ notInSchema: { $lt: 'not a number' } }], $and: [{ name: 'abc' }, { age: { $gt: 18 } }, { notInSchema: { $lt: 'not a number' } }] });
await query.exec();
query.getFilter(); // Empty object `{}`, Mongoose removes `notInSchema`
// acquit:ignore:start
assert.deepEqual(query.getFilter(), {});
// acquit:ignore:end
});

await query.exec();
query.getFilter(); // Empty object `{}`, Mongoose removes `notInSchema`
// acquit:ignore:start
assert.deepEqual(query.getFilter(), { $and: [{ name: 'abc' }, { age: { $gt: 18 } }] });
// acquit:ignore:end
it('strictQuery throw', async function() {
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
strictQuery: 'throw'
});
Character = mongoose.model('Character', schema);

it('strictQuery throw', async function() {
mongoose.deleteModel('Character');
const schema = new mongoose.Schema({ name: String, age: Number }, {
strictQuery: 'throw'
});
Character = mongoose.model('Character', schema);

const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

const err = await query.exec().then(() => null, err => err);
err.name; // 'StrictModeError'
// Path "notInSchema" is not in schema and strictQuery is 'throw'.
err.message;
// acquit:ignore:start
assert.equal(err.name, 'StrictModeError');
assert.equal(err.message, 'Path "notInSchema" is not in schema and ' +
'strictQuery is \'throw\'.');
// acquit:ignore:end
});
const query = Character.findOne({ notInSchema: { $lt: 'not a number' } });

const err = await query.exec().then(() => null, err => err);
err.name; // 'StrictModeError'
// Path "notInSchema" is not in schema and strictQuery is 'throw'.
err.message;
// acquit:ignore:start
assert.equal(err.name, 'StrictModeError');
assert.equal(err.message, 'Path "notInSchema" is not in schema and ' +
'strictQuery is \'throw\'.');
// acquit:ignore:end
});

it('implicit in', async function() {
Expand All @@ -172,4 +154,4 @@ describe('Cast Tutorial', function() {
});
// acquit:ignore:end
});
});
});
63 changes: 63 additions & 0 deletions test/schema.validation.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const start = require('./common');

const assert = require('assert');
const random = require('./util').random;
const { v4: uuidv4 } = require('uuid');

const mongoose = start.mongoose;
const Schema = mongoose.Schema;
Expand Down Expand Up @@ -1468,5 +1469,67 @@ describe('schema', function() {
assert.ifError(err);
});
});

it('should validate required UUID fields correctly (gh-12991)', function() {
const uuidSchema = new mongoose.Schema({
_id: { type: mongoose.Schema.Types.UUID, required: true },
name: { type: mongoose.Schema.Types.String, required: true }
});

const uuidRefSchema = new mongoose.Schema({
_id: { type: mongoose.Schema.Types.UUID, required: true },
uuidRef: { type: mongoose.Schema.Types.UUID, ref: 'UUIDModel', required: true },
uuidNonRef: { type: mongoose.Schema.Types.UUID, required: true },
uuidRefNonRequired: { type: mongoose.Schema.Types.UUID, ref: 'UUIDModel' },
name: { type: mongoose.Schema.Types.String, required: true }
});

const UUIDModel = mongoose.model('UUIDModel', uuidSchema, 'uuids');

const UUIDRefModel = mongoose.model('UUIDRefModel', uuidRefSchema, 'uuidRefs');

const uuid = new UUIDModel({ _id: uuidv4(), name: 'uuidName' });
assert.ifError(uuid.validateSync());

const uuidRef = new UUIDRefModel({
_id: uuidv4(),
uuidRef: uuidv4(),
uuidNonRef: uuidv4(),
uuidRefNonRequired: uuidv4(),
name: 'uuidRefName'
});
assert.ifError(uuidRef.validateSync());

const uuidRef2 = new UUIDRefModel({
_id: uuidv4(),
uuidNonRef: uuidv4(),
uuidRefNonRequired: uuidv4(),
name: 'uuidRefName'
});

const err2 = uuidRef2.validateSync();
assert.ok(err2);
assert.ok(err2.errors['uuidRef']);

const uuidRef3 = new UUIDRefModel({
_id: uuidv4(),
uuidRef: uuidv4(),
uuidRefNonRequired: uuidv4(),
name: 'uuidRefName'
});

const err3 = uuidRef3.validateSync();
assert.ok(err3);
assert.ok(err3.errors['uuidNonRef']);

const uuidRef4 = new UUIDRefModel({
_id: uuidv4(),
uuidRef: uuidv4(),
uuidNonRef: uuidv4(),
name: 'uuidRefName'
});

assert.ifError(uuidRef4.validateSync());
});
});
});

0 comments on commit daef366

Please sign in to comment.