Skip to content

Commit e6a4c50

Browse files
committed
Adding 'defaultLimit' option to allow changing the default limit for queries' size (issue parse-community#8149)
1 parent 780ee02 commit e6a4c50

File tree

8 files changed

+66
-6
lines changed

8 files changed

+66
-6
lines changed

spec/ParseQuery.spec.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,19 @@ describe('Parse.Query testing', () => {
314314
equal(results.length, 0);
315315
});
316316

317+
it('query without limit respects default limit', async done => {
318+
const baz = new TestObject({ foo: 'baz' });
319+
const qux = new TestObject({ foo: 'qux' });
320+
await reconfigureServer({ defaultLimit: 1 });
321+
Parse.Object.saveAll([baz, qux]).then(function () {
322+
const query = new Parse.Query(TestObject);
323+
query.find().then(function (results) {
324+
equal(results.length, 1);
325+
done();
326+
});
327+
});
328+
});
329+
317330
it('query with limit', function (done) {
318331
const baz = new TestObject({ foo: 'baz' });
319332
const qux = new TestObject({ foo: 'qux' });
@@ -327,6 +340,20 @@ describe('Parse.Query testing', () => {
327340
});
328341
});
329342

343+
it('query with limit overrides default limit', async done => {
344+
const baz = new TestObject({ foo: 'baz' });
345+
const qux = new TestObject({ foo: 'qux' });
346+
await reconfigureServer({ defaultLimit: 2 });
347+
Parse.Object.saveAll([baz, qux]).then(function () {
348+
const query = new Parse.Query(TestObject);
349+
query.limit(1);
350+
query.find().then(function (results) {
351+
equal(results.length, 1);
352+
done();
353+
});
354+
});
355+
});
356+
330357
it('query with limit equal to maxlimit', async () => {
331358
const baz = new TestObject({ foo: 'baz' });
332359
const qux = new TestObject({ foo: 'qux' });

spec/index.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -462,13 +462,27 @@ describe('server', () => {
462462
.then(done);
463463
});
464464

465+
it('fails if default limit is negative', done => {
466+
reconfigureServer({ defaultLimit: -1 }).catch(error => {
467+
expect(error).toEqual('Default limit must be a value greater than 0.');
468+
done();
469+
});
470+
});
471+
465472
it('fails if maxLimit is negative', done => {
466473
reconfigureServer({ maxLimit: -100 }).catch(error => {
467474
expect(error).toEqual('Max limit must be a value greater than 0.');
468475
done();
469476
});
470477
});
471478

479+
it('fails if maxLimit is smaller than the default limit', done => {
480+
reconfigureServer({ defaultLimit: 101, maxLimit: 100 }).catch(error => {
481+
expect(error).toEqual('Max limit must be greater than the default limit.');
482+
done();
483+
});
484+
});
485+
472486
it('fails if you try to set revokeSessionOnPasswordReset to non-boolean', done => {
473487
reconfigureServer({ revokeSessionOnPasswordReset: 'non-bool' }).catch(done);
474488
});

src/Config.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ export class Config {
6363
revokeSessionOnPasswordReset,
6464
expireInactiveSessions,
6565
sessionLength,
66+
defaultLimit,
6667
maxLimit,
6768
emailVerifyTokenValidityDuration,
6869
accountLockout,
@@ -110,7 +111,8 @@ export class Config {
110111
}
111112
this.validateSessionConfiguration(sessionLength, expireInactiveSessions);
112113
this.validateMasterKeyIps(masterKeyIps);
113-
this.validateMaxLimit(maxLimit);
114+
this.validateDefaultLimit(defaultLimit);
115+
this.validateMaxLimit(maxLimit, defaultLimit);
114116
this.validateAllowHeaders(allowHeaders);
115117
this.validateIdempotencyOptions(idempotencyOptions);
116118
this.validatePagesOptions(pages);
@@ -453,10 +455,19 @@ export class Config {
453455
}
454456
}
455457

456-
static validateMaxLimit(maxLimit) {
458+
static validateDefaultLimit(defaultLimit) {
459+
if (defaultLimit <= 0) {
460+
throw 'Default limit must be a value greater than 0.';
461+
}
462+
}
463+
464+
static validateMaxLimit(maxLimit, defaultLimit) {
457465
if (maxLimit <= 0) {
458466
throw 'Max limit must be a value greater than 0.';
459467
}
468+
if (maxLimit < defaultLimit) {
469+
throw 'Max limit must be greater than the default limit.';
470+
}
460471
}
461472

462473
static validateAllowHeaders(allowHeaders) {

src/GraphQL/helpers/objectsQueries.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ const calculateSkipAndLimit = (skipInput, first, after, last, before, maxLimit)
272272
}
273273

274274
if ((skip || 0) >= before) {
275-
// If the before index is less then the skip, no objects will be returned
275+
// If the before index is less than the skip, no objects will be returned
276276
limit = 0;
277277
} else if ((!limit && limit !== 0) || (skip || 0) + limit > before) {
278278
// If there is no limit set, the limit is calculated. Or, if the limit (plus skip) is bigger than the before index, the new limit is set.

src/Options/Definitions.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,11 @@ module.exports.ParseServerOptions = {
154154
required: true,
155155
default: 'mongodb://localhost:27017/parse',
156156
},
157+
defaultLimit: {
158+
env: 'PARSE_SERVER_DEFAULT_LIMIT',
159+
help: 'Default limit for the size of results set on queries, defaults to 100',
160+
action: parsers.numberParser('defaultLimit'),
161+
},
157162
directAccess: {
158163
env: 'PARSE_SERVER_DIRECT_ACCESS',
159164
help:

src/Options/docs.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
* @property {Adapter<StorageAdapter>} databaseAdapter Adapter module for the database
3232
* @property {DatabaseOptions} databaseOptions Options to pass to the database client
3333
* @property {String} databaseURI The full URI to your database. Supported databases are mongodb or postgres.
34+
* @property {Number} defaultLimit Default limit for the size of results set on queries, defaults to 100
3435
* @property {Boolean} directAccess Set to `true` if Parse requests within the same Node.js environment as Parse Server should be routed to Parse Server directly instead of via the HTTP interface. Default is `false`.<br><br>If set to `false` then Parse requests within the same Node.js environment as Parse Server are executed as HTTP requests sent to Parse Server via the `serverURL`. For example, a `Parse.Query` in Cloud Code is calling Parse Server via a HTTP request. The server is essentially making a HTTP request to itself, unnecessarily using network resources such as network ports.<br><br>⚠️ In environments where multiple Parse Server instances run behind a load balancer and Parse requests within the current Node.js environment should be routed via the load balancer and distributed as HTTP requests among all instances via the `serverURL`, this should be set to `false`.
3536
* @property {String} dotNetKey Key for Unity and .Net SDK
3637
* @property {Adapter<MailAdapter>} emailAdapter Adapter module for email sending

src/Options/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ export interface ParseServerOptions {
194194
/* Session duration, in seconds, defaults to 1 year
195195
:DEFAULT: 31536000 */
196196
sessionLength: ?number;
197+
/* Default limit for the size of results set on queries, defaults to 100 */
198+
defaultLimit: ?number;
197199
/* Max value for limit option on queries, defaults to unlimited */
198200
maxLimit: ?number;
199201
/* Sets whether we should expire the inactive sessions, defaults to true. If false, all new sessions are created with no expiration date.

src/Routers/ClassesRouter.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export class ClassesRouter extends PromiseRouter {
2020

2121
handleFind(req) {
2222
const body = Object.assign(req.body, ClassesRouter.JSONFromQuery(req.query));
23-
const options = ClassesRouter.optionsFromBody(body);
23+
const options = ClassesRouter.optionsFromBody(body, req.config.defaultLimit);
2424
if (req.config.maxLimit && body.limit > req.config.maxLimit) {
2525
// Silently replace the limit on the query with the max configured
2626
options.limit = Number(req.config.maxLimit);
@@ -149,7 +149,7 @@ export class ClassesRouter extends PromiseRouter {
149149
return json;
150150
}
151151

152-
static optionsFromBody(body) {
152+
static optionsFromBody(body, defaultLimit) {
153153
const allowConstraints = [
154154
'skip',
155155
'limit',
@@ -180,7 +180,7 @@ export class ClassesRouter extends PromiseRouter {
180180
if (body.limit || body.limit === 0) {
181181
options.limit = Number(body.limit);
182182
} else {
183-
options.limit = Number(100);
183+
options.limit = Number(defaultLimit || 100);
184184
}
185185
if (body.order) {
186186
options.order = String(body.order);

0 commit comments

Comments
 (0)