Set min mongodb to 3.6 in prep for parse-server 4.0 (#6445)
* Set min mongodb to 3.6 in prep for parse-server 4.0 fixes: 6444 * don't use anonymous functions when we can just pass the function. Also remove the boolean argument in tests that no longer exists. * generate the correct lock file. ooops.
This commit is contained in:
@@ -18,8 +18,6 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img alt="MongoDB 3.2" src="https://img.shields.io/badge/mongodb-3.2-green.svg?logo=mongodb&style=flat">
|
||||
<img alt="MongoDB 3.4" src="https://img.shields.io/badge/mongodb-3.4-green.svg?logo=mongodb&style=flat">
|
||||
<img alt="MongoDB 3.6" src="https://img.shields.io/badge/mongodb-3.6-green.svg?logo=mongodb&style=flat">
|
||||
<img alt="MongoDB 4.0" src="https://img.shields.io/badge/mongodb-4.0-green.svg?logo=mongodb&style=flat">
|
||||
</p>
|
||||
@@ -80,7 +78,7 @@ The fastest and easiest way to get started is to run MongoDB and Parse Server lo
|
||||
|
||||
Before you start make sure you have installed:
|
||||
|
||||
- [NodeJS](https://www.npmjs.com/) that includes `npm`
|
||||
- [NodeJS](https://www.npmjs.com/) that includes `npm`
|
||||
- [MongoDB](https://www.mongodb.com/) or [PostgreSQL](https://www.postgresql.org/)
|
||||
- Optionally [Docker](https://www.docker.com/)
|
||||
|
||||
@@ -337,7 +335,7 @@ It’s possible to change the default pages of the app and redirect the user to
|
||||
```js
|
||||
var server = ParseServer({
|
||||
...otherOptions,
|
||||
|
||||
|
||||
customPages: {
|
||||
passwordResetSuccess: "http://yourapp.com/passwordResetSuccess",
|
||||
verifyEmailSuccess: "http://yourapp.com/verifyEmailSuccess",
|
||||
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -9032,9 +9032,9 @@
|
||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
||||
},
|
||||
"mongodb": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.3.tgz",
|
||||
"integrity": "sha512-II7P7A3XUdPiXRgcN96qIoRa1oesM6qLNZkzfPluNZjVkgQk3jnQwOT6/uDk4USRDTTLjNFw2vwfmbRGTA7msg==",
|
||||
"version": "3.5.4",
|
||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.4.tgz",
|
||||
"integrity": "sha512-xGH41Ig4dkSH5ROGezkgDbsgt/v5zbNUwE3TcFsSbDc6Qn3Qil17dhLsESSDDPTiyFDCPJRpfd4887dtsPgKtA==",
|
||||
"requires": {
|
||||
"bl": "^2.2.0",
|
||||
"bson": "^1.1.1",
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
"lodash": "4.17.15",
|
||||
"lru-cache": "5.1.1",
|
||||
"mime": "2.4.4",
|
||||
"mongodb": "3.5.3",
|
||||
"mongodb": "3.5.4",
|
||||
"node-rsa": "1.0.7",
|
||||
"parse": "2.11.0",
|
||||
"pg-promise": "10.4.4",
|
||||
|
||||
@@ -3,118 +3,56 @@ const validateQuery = DatabaseController._validateQuery;
|
||||
|
||||
describe('DatabaseController', function() {
|
||||
describe('validateQuery', function() {
|
||||
describe('with skipMongoDBServer13732Workaround disabled (the default)', function() {
|
||||
it('should restructure simple cases of SERVER-13732', done => {
|
||||
const query = {
|
||||
$or: [{ a: 1 }, { a: 2 }],
|
||||
_rperm: { $in: ['a', 'b'] },
|
||||
foo: 3,
|
||||
};
|
||||
validateQuery(query, false);
|
||||
expect(query).toEqual({
|
||||
$or: [
|
||||
{ a: 1, _rperm: { $in: ['a', 'b'] }, foo: 3 },
|
||||
{ a: 2, _rperm: { $in: ['a', 'b'] }, foo: 3 },
|
||||
],
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not restructure SERVER-13732 queries with $nears', done => {
|
||||
let query = { $or: [{ a: 1 }, { b: 1 }], c: { $nearSphere: {} } };
|
||||
validateQuery(query, false);
|
||||
expect(query).toEqual({
|
||||
$or: [{ a: 1 }, { b: 1 }],
|
||||
c: { $nearSphere: {} },
|
||||
});
|
||||
query = { $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } };
|
||||
validateQuery(query, false);
|
||||
expect(query).toEqual({ $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } });
|
||||
done();
|
||||
});
|
||||
|
||||
it('should push refactored keys down a tree for SERVER-13732', done => {
|
||||
const query = {
|
||||
a: 1,
|
||||
$or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }],
|
||||
};
|
||||
validateQuery(query, false);
|
||||
expect(query).toEqual({
|
||||
$or: [
|
||||
{ $or: [{ b: 1, a: 1 }, { b: 2, a: 1 }] },
|
||||
{ $or: [{ c: 1, a: 1 }, { c: 2, a: 1 }] },
|
||||
],
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('should reject invalid queries', done => {
|
||||
expect(() => validateQuery({ $or: { a: 1 } }, false)).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should accept valid queries', done => {
|
||||
expect(() =>
|
||||
validateQuery({ $or: [{ a: 1 }, { b: 2 }] }, false)
|
||||
).not.toThrow();
|
||||
done();
|
||||
it('should not restructure simple cases of SERVER-13732', done => {
|
||||
const query = {
|
||||
$or: [{ a: 1 }, { a: 2 }],
|
||||
_rperm: { $in: ['a', 'b'] },
|
||||
foo: 3,
|
||||
};
|
||||
validateQuery(query);
|
||||
expect(query).toEqual({
|
||||
$or: [{ a: 1 }, { a: 2 }],
|
||||
_rperm: { $in: ['a', 'b'] },
|
||||
foo: 3,
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
describe('with skipMongoDBServer13732Workaround enabled', function() {
|
||||
it('should not restructure simple cases of SERVER-13732', done => {
|
||||
const query = {
|
||||
$or: [{ a: 1 }, { a: 2 }],
|
||||
_rperm: { $in: ['a', 'b'] },
|
||||
foo: 3,
|
||||
};
|
||||
validateQuery(query, true);
|
||||
expect(query).toEqual({
|
||||
$or: [{ a: 1 }, { a: 2 }],
|
||||
_rperm: { $in: ['a', 'b'] },
|
||||
foo: 3,
|
||||
});
|
||||
done();
|
||||
it('should not restructure SERVER-13732 queries with $nears', done => {
|
||||
let query = { $or: [{ a: 1 }, { b: 1 }], c: { $nearSphere: {} } };
|
||||
validateQuery(query);
|
||||
expect(query).toEqual({
|
||||
$or: [{ a: 1 }, { b: 1 }],
|
||||
c: { $nearSphere: {} },
|
||||
});
|
||||
query = { $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } };
|
||||
validateQuery(query);
|
||||
expect(query).toEqual({ $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } });
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not push refactored keys down a tree for SERVER-13732', done => {
|
||||
const query = {
|
||||
a: 1,
|
||||
$or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }],
|
||||
};
|
||||
validateQuery(query);
|
||||
expect(query).toEqual({
|
||||
a: 1,
|
||||
$or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }],
|
||||
});
|
||||
|
||||
it('should not restructure SERVER-13732 queries with $nears', done => {
|
||||
let query = { $or: [{ a: 1 }, { b: 1 }], c: { $nearSphere: {} } };
|
||||
validateQuery(query, true);
|
||||
expect(query).toEqual({
|
||||
$or: [{ a: 1 }, { b: 1 }],
|
||||
c: { $nearSphere: {} },
|
||||
});
|
||||
query = { $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } };
|
||||
validateQuery(query, true);
|
||||
expect(query).toEqual({ $or: [{ a: 1 }, { b: 1 }], c: { $near: {} } });
|
||||
done();
|
||||
});
|
||||
done();
|
||||
});
|
||||
|
||||
it('should not push refactored keys down a tree for SERVER-13732', done => {
|
||||
const query = {
|
||||
a: 1,
|
||||
$or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }],
|
||||
};
|
||||
validateQuery(query, true);
|
||||
expect(query).toEqual({
|
||||
a: 1,
|
||||
$or: [{ $or: [{ b: 1 }, { b: 2 }] }, { $or: [{ c: 1 }, { c: 2 }] }],
|
||||
});
|
||||
it('should reject invalid queries', done => {
|
||||
expect(() => validateQuery({ $or: { a: 1 } })).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
it('should reject invalid queries', done => {
|
||||
expect(() => validateQuery({ $or: { a: 1 } }, true)).toThrow();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should accept valid queries', done => {
|
||||
expect(() =>
|
||||
validateQuery({ $or: [{ a: 1 }, { b: 2 }] }, true)
|
||||
).not.toThrow();
|
||||
done();
|
||||
});
|
||||
it('should accept valid queries', done => {
|
||||
expect(() => validateQuery({ $or: [{ a: 1 }, { b: 2 }] })).not.toThrow();
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -34,8 +34,7 @@ export class Config {
|
||||
);
|
||||
config.database = new DatabaseController(
|
||||
cacheInfo.databaseController.adapter,
|
||||
schemaCache,
|
||||
cacheInfo.skipMongoDBServer13732Workaround
|
||||
schemaCache
|
||||
);
|
||||
} else {
|
||||
config[key] = cacheInfo[key];
|
||||
|
||||
@@ -69,73 +69,14 @@ const isSpecialQueryKey = key => {
|
||||
return specialQuerykeys.indexOf(key) >= 0;
|
||||
};
|
||||
|
||||
const validateQuery = (
|
||||
query: any,
|
||||
skipMongoDBServer13732Workaround: boolean
|
||||
): void => {
|
||||
const validateQuery = (query: any): void => {
|
||||
if (query.ACL) {
|
||||
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Cannot query on ACL.');
|
||||
}
|
||||
|
||||
if (query.$or) {
|
||||
if (query.$or instanceof Array) {
|
||||
query.$or.forEach(el =>
|
||||
validateQuery(el, skipMongoDBServer13732Workaround)
|
||||
);
|
||||
|
||||
if (!skipMongoDBServer13732Workaround) {
|
||||
/* In MongoDB 3.2 & 3.4, $or queries which are not alone at the top
|
||||
* level of the query can not make efficient use of indexes due to a
|
||||
* long standing bug known as SERVER-13732.
|
||||
*
|
||||
* This bug was fixed in MongoDB version 3.6.
|
||||
*
|
||||
* For versions pre-3.6, the below logic produces a substantial
|
||||
* performance improvement inside the database by avoiding the bug.
|
||||
*
|
||||
* For versions 3.6 and above, there is no performance improvement and
|
||||
* the logic is unnecessary. Some query patterns are even slowed by
|
||||
* the below logic, due to the bug having been fixed and better
|
||||
* query plans being chosen.
|
||||
*
|
||||
* When versions before 3.4 are no longer supported by this project,
|
||||
* this logic, and the accompanying `skipMongoDBServer13732Workaround`
|
||||
* flag, can be removed.
|
||||
*
|
||||
* This block restructures queries in which $or is not the sole top
|
||||
* level element by moving all other top-level predicates inside every
|
||||
* subdocument of the $or predicate, allowing MongoDB's query planner
|
||||
* to make full use of the most relevant indexes.
|
||||
*
|
||||
* EG: {$or: [{a: 1}, {a: 2}], b: 2}
|
||||
* Becomes: {$or: [{a: 1, b: 2}, {a: 2, b: 2}]}
|
||||
*
|
||||
* The only exceptions are $near and $nearSphere operators, which are
|
||||
* constrained to only 1 operator per query. As a result, these ops
|
||||
* remain at the top level
|
||||
*
|
||||
* https://jira.mongodb.org/browse/SERVER-13732
|
||||
* https://github.com/parse-community/parse-server/issues/3767
|
||||
*/
|
||||
Object.keys(query).forEach(key => {
|
||||
const noCollisions = !query.$or.some(subq =>
|
||||
Object.prototype.hasOwnProperty.call(subq, key)
|
||||
);
|
||||
let hasNears = false;
|
||||
if (query[key] != null && typeof query[key] == 'object') {
|
||||
hasNears = '$near' in query[key] || '$nearSphere' in query[key];
|
||||
}
|
||||
if (key != '$or' && noCollisions && !hasNears) {
|
||||
query.$or.forEach(subquery => {
|
||||
subquery[key] = query[key];
|
||||
});
|
||||
delete query[key];
|
||||
}
|
||||
});
|
||||
query.$or.forEach(el =>
|
||||
validateQuery(el, skipMongoDBServer13732Workaround)
|
||||
);
|
||||
}
|
||||
query.$or.forEach(validateQuery);
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
@@ -146,9 +87,7 @@ const validateQuery = (
|
||||
|
||||
if (query.$and) {
|
||||
if (query.$and instanceof Array) {
|
||||
query.$and.forEach(el =>
|
||||
validateQuery(el, skipMongoDBServer13732Workaround)
|
||||
);
|
||||
query.$and.forEach(validateQuery);
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
@@ -159,9 +98,7 @@ const validateQuery = (
|
||||
|
||||
if (query.$nor) {
|
||||
if (query.$nor instanceof Array && query.$nor.length > 0) {
|
||||
query.$nor.forEach(el =>
|
||||
validateQuery(el, skipMongoDBServer13732Workaround)
|
||||
);
|
||||
query.$nor.forEach(validateQuery);
|
||||
} else {
|
||||
throw new Parse.Error(
|
||||
Parse.Error.INVALID_QUERY,
|
||||
@@ -487,21 +424,15 @@ class DatabaseController {
|
||||
adapter: StorageAdapter;
|
||||
schemaCache: any;
|
||||
schemaPromise: ?Promise<SchemaController.SchemaController>;
|
||||
skipMongoDBServer13732Workaround: boolean;
|
||||
_transactionalSession: ?any;
|
||||
|
||||
constructor(
|
||||
adapter: StorageAdapter,
|
||||
schemaCache: any,
|
||||
skipMongoDBServer13732Workaround: boolean
|
||||
) {
|
||||
constructor(adapter: StorageAdapter, schemaCache: any) {
|
||||
this.adapter = adapter;
|
||||
this.schemaCache = schemaCache;
|
||||
// We don't want a mutable this.schema, because then you could have
|
||||
// one request that uses different schemas for different parts of
|
||||
// it. Instead, use loadSchema to get a schema.
|
||||
this.schemaPromise = null;
|
||||
this.skipMongoDBServer13732Workaround = skipMongoDBServer13732Workaround;
|
||||
this._transactionalSession = null;
|
||||
}
|
||||
|
||||
@@ -660,7 +591,7 @@ class DatabaseController {
|
||||
if (acl) {
|
||||
query = addWriteACL(query, acl);
|
||||
}
|
||||
validateQuery(query, this.skipMongoDBServer13732Workaround);
|
||||
validateQuery(query);
|
||||
return schemaController
|
||||
.getOneSchema(className, true)
|
||||
.catch(error => {
|
||||
@@ -939,7 +870,7 @@ class DatabaseController {
|
||||
if (acl) {
|
||||
query = addWriteACL(query, acl);
|
||||
}
|
||||
validateQuery(query, this.skipMongoDBServer13732Workaround);
|
||||
validateQuery(query);
|
||||
return schemaController
|
||||
.getOneSchema(className)
|
||||
.catch(error => {
|
||||
@@ -1460,7 +1391,7 @@ class DatabaseController {
|
||||
query = addReadACL(query, aclGroup);
|
||||
}
|
||||
}
|
||||
validateQuery(query, this.skipMongoDBServer13732Workaround);
|
||||
validateQuery(query);
|
||||
if (count) {
|
||||
if (!classExists) {
|
||||
return 0;
|
||||
@@ -1893,7 +1824,7 @@ class DatabaseController {
|
||||
]);
|
||||
}
|
||||
|
||||
static _validateQuery: (any, boolean) => void;
|
||||
static _validateQuery: any => void;
|
||||
}
|
||||
|
||||
module.exports = DatabaseController;
|
||||
|
||||
@@ -171,7 +171,6 @@ export function getDatabaseController(
|
||||
const {
|
||||
databaseURI,
|
||||
databaseOptions,
|
||||
skipMongoDBServer13732Workaround,
|
||||
collectionPrefix,
|
||||
schemaCacheTTL,
|
||||
enableSingleSchemaCache,
|
||||
@@ -195,8 +194,7 @@ export function getDatabaseController(
|
||||
}
|
||||
return new DatabaseController(
|
||||
databaseAdapter,
|
||||
new SchemaCache(cacheController, schemaCacheTTL, enableSingleSchemaCache),
|
||||
skipMongoDBServer13732Workaround
|
||||
new SchemaCache(cacheController, schemaCacheTTL, enableSingleSchemaCache)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -371,12 +371,6 @@ module.exports.ParseServerOptions = {
|
||||
help: 'Disables console output',
|
||||
action: parsers.booleanParser,
|
||||
},
|
||||
skipMongoDBServer13732Workaround: {
|
||||
env: 'PARSE_SKIP_MONGODB_SERVER_13732_WORKAROUND',
|
||||
help: 'Circumvent Parse workaround for historical MongoDB bug SERVER-13732',
|
||||
action: parsers.booleanParser,
|
||||
default: false,
|
||||
},
|
||||
startLiveQueryServer: {
|
||||
env: 'PARSE_SERVER_START_LIVE_QUERY_SERVER',
|
||||
help: 'Starts the liveQuery server',
|
||||
|
||||
@@ -67,7 +67,6 @@
|
||||
* @property {String} serverURL URL to your parse server with http:// or https://.
|
||||
* @property {Number} sessionLength Session duration, in seconds, defaults to 1 year
|
||||
* @property {Boolean} silent Disables console output
|
||||
* @property {Boolean} skipMongoDBServer13732Workaround Circumvent Parse workaround for historical MongoDB bug SERVER-13732
|
||||
* @property {Boolean} startLiveQueryServer Starts the liveQuery server
|
||||
* @property {String[]} userSensitiveFields Personally identifiable information fields in the user table the should be removed for non-authorized users. Deprecated @see protectedFields
|
||||
* @property {Boolean} verbose Set the logging to verbose
|
||||
|
||||
@@ -64,10 +64,6 @@ export interface ParseServerOptions {
|
||||
databaseOptions: ?any;
|
||||
/* Adapter module for the database */
|
||||
databaseAdapter: ?Adapter<StorageAdapter>;
|
||||
/* Circumvent Parse workaround for historical MongoDB bug SERVER-13732
|
||||
:ENV: PARSE_SKIP_MONGODB_SERVER_13732_WORKAROUND
|
||||
:DEFAULT: false */
|
||||
skipMongoDBServer13732Workaround: ?boolean;
|
||||
/* Full path to your cloud code main.js */
|
||||
cloud: ?string;
|
||||
/* A collection prefix for the classes
|
||||
|
||||
Reference in New Issue
Block a user