* Initial Commit * fix flaky test * temporary set ci timeout * turn off ci check * fix postgres tests * fix tests * node flaky test * remove improvements * Update SchemaPerformance.spec.js * fix tests * revert ci * Create Singleton Object * properly clear cache testing * Cleanup * remove fit * try PushController.spec * try push test rewrite * try push enqueue time * Increase test timeout * remove pg server creation test * xit push tests * more xit * remove skipped tests * Fix conflicts * reduce ci timeout * fix push tests * Revert "fix push tests" This reverts commit 05aba62f1cbbca7d5d3e80b9444529f59407cb56. * improve initialization * fix flaky tests * xit flaky test * Update CHANGELOG.md * enable debug logs * Update LogsRouter.spec.js * create initial indexes in series * lint * horizontal scaling documentation * Update Changelog * change horizontalScaling db option * Add enableSchemaHooks option * move enableSchemaHooks to databaseOptions
230 lines
8.8 KiB
JavaScript
230 lines
8.8 KiB
JavaScript
'use strict';
|
|
|
|
const Config = require('../lib/Config');
|
|
const TestUtils = require('../lib/TestUtils');
|
|
const request = require('../lib/request');
|
|
|
|
let config;
|
|
|
|
const masterKeyHeaders = {
|
|
'X-Parse-Application-Id': 'test',
|
|
'X-Parse-Rest-API-Key': 'rest',
|
|
'X-Parse-Master-Key': 'test',
|
|
'Content-Type': 'application/json',
|
|
};
|
|
|
|
const masterKeyOptions = {
|
|
headers: masterKeyHeaders,
|
|
json: true,
|
|
};
|
|
|
|
describe_only_db('mongo')('Parse.Query hint', () => {
|
|
beforeEach(() => {
|
|
config = Config.get('test');
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await TestUtils.destroyAllDataPermanently(false);
|
|
});
|
|
|
|
it('query find with hint string', async () => {
|
|
const object = new TestObject();
|
|
await object.save();
|
|
|
|
const collection = await config.database.adapter._adaptiveCollection('TestObject');
|
|
let explain = await collection._rawFind({ _id: object.id }, { explain: true });
|
|
expect(explain.queryPlanner.winningPlan.stage).toBe('IDHACK');
|
|
explain = await collection._rawFind({ _id: object.id }, { hint: '_id_', explain: true });
|
|
expect(explain.queryPlanner.winningPlan.stage).toBe('FETCH');
|
|
expect(explain.queryPlanner.winningPlan.inputStage.indexName).toBe('_id_');
|
|
});
|
|
|
|
it('query find with hint object', async () => {
|
|
const object = new TestObject();
|
|
await object.save();
|
|
|
|
const collection = await config.database.adapter._adaptiveCollection('TestObject');
|
|
let explain = await collection._rawFind({ _id: object.id }, { explain: true });
|
|
expect(explain.queryPlanner.winningPlan.stage).toBe('IDHACK');
|
|
explain = await collection._rawFind({ _id: object.id }, { hint: { _id: 1 }, explain: true });
|
|
expect(explain.queryPlanner.winningPlan.stage).toBe('FETCH');
|
|
expect(explain.queryPlanner.winningPlan.inputStage.keyPattern).toEqual({
|
|
_id: 1,
|
|
});
|
|
});
|
|
|
|
it_only_mongodb_version('<4.4')('query aggregate with hint string', async () => {
|
|
const object = new TestObject({ foo: 'bar' });
|
|
await object.save();
|
|
|
|
const collection = await config.database.adapter._adaptiveCollection('TestObject');
|
|
let result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
explain: true,
|
|
});
|
|
let { queryPlanner } = result[0].stages[0].$cursor;
|
|
expect(queryPlanner.winningPlan.stage).toBe('COLLSCAN');
|
|
|
|
result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
hint: '_id_',
|
|
explain: true,
|
|
});
|
|
queryPlanner = result[0].stages[0].$cursor.queryPlanner;
|
|
expect(queryPlanner.winningPlan.stage).toBe('FETCH');
|
|
expect(queryPlanner.winningPlan.inputStage.indexName).toBe('_id_');
|
|
});
|
|
|
|
it_only_mongodb_version('>=4.4')('query aggregate with hint string', async () => {
|
|
const object = new TestObject({ foo: 'bar' });
|
|
await object.save();
|
|
|
|
const collection = await config.database.adapter._adaptiveCollection('TestObject');
|
|
let result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
explain: true,
|
|
});
|
|
let { queryPlanner } = result[0].stages[0].$cursor;
|
|
expect(queryPlanner.winningPlan.stage).toBe('PROJECTION_SIMPLE');
|
|
expect(queryPlanner.winningPlan.inputStage.stage).toBe('COLLSCAN');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage).toBeUndefined();
|
|
|
|
result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
hint: '_id_',
|
|
explain: true,
|
|
});
|
|
queryPlanner = result[0].stages[0].$cursor.queryPlanner;
|
|
expect(queryPlanner.winningPlan.stage).toBe('PROJECTION_SIMPLE');
|
|
expect(queryPlanner.winningPlan.inputStage.stage).toBe('FETCH');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.stage).toBe('IXSCAN');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.indexName).toBe('_id_');
|
|
});
|
|
|
|
it_only_mongodb_version('<4.4')('query aggregate with hint object', async () => {
|
|
const object = new TestObject({ foo: 'bar' });
|
|
await object.save();
|
|
|
|
const collection = await config.database.adapter._adaptiveCollection('TestObject');
|
|
let result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
explain: true,
|
|
});
|
|
let { queryPlanner } = result[0].stages[0].$cursor;
|
|
expect(queryPlanner.winningPlan.stage).toBe('COLLSCAN');
|
|
|
|
result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
hint: { _id: 1 },
|
|
explain: true,
|
|
});
|
|
queryPlanner = result[0].stages[0].$cursor.queryPlanner;
|
|
expect(queryPlanner.winningPlan.stage).toBe('FETCH');
|
|
expect(queryPlanner.winningPlan.inputStage.keyPattern).toEqual({ _id: 1 });
|
|
});
|
|
|
|
it_only_mongodb_version('>=4.4')('query aggregate with hint object', async () => {
|
|
const object = new TestObject({ foo: 'bar' });
|
|
await object.save();
|
|
|
|
const collection = await config.database.adapter._adaptiveCollection('TestObject');
|
|
let result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
explain: true,
|
|
});
|
|
let { queryPlanner } = result[0].stages[0].$cursor;
|
|
expect(queryPlanner.winningPlan.stage).toBe('PROJECTION_SIMPLE');
|
|
expect(queryPlanner.winningPlan.inputStage.stage).toBe('COLLSCAN');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage).toBeUndefined();
|
|
|
|
result = await collection.aggregate([{ $group: { _id: '$foo' } }], {
|
|
hint: { _id: 1 },
|
|
explain: true,
|
|
});
|
|
queryPlanner = result[0].stages[0].$cursor.queryPlanner;
|
|
expect(queryPlanner.winningPlan.stage).toBe('PROJECTION_SIMPLE');
|
|
expect(queryPlanner.winningPlan.inputStage.stage).toBe('FETCH');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.stage).toBe('IXSCAN');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.indexName).toBe('_id_');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.keyPattern).toEqual({ _id: 1 });
|
|
});
|
|
|
|
it('query find with hint (rest)', async () => {
|
|
const object = new TestObject();
|
|
await object.save();
|
|
let options = Object.assign({}, masterKeyOptions, {
|
|
url: Parse.serverURL + '/classes/TestObject',
|
|
qs: {
|
|
explain: true,
|
|
},
|
|
});
|
|
let response = await request(options);
|
|
let explain = response.data.results;
|
|
expect(explain.queryPlanner.winningPlan.inputStage.stage).toBe('COLLSCAN');
|
|
|
|
options = Object.assign({}, masterKeyOptions, {
|
|
url: Parse.serverURL + '/classes/TestObject',
|
|
qs: {
|
|
explain: true,
|
|
hint: '_id_',
|
|
},
|
|
});
|
|
response = await request(options);
|
|
explain = response.data.results;
|
|
expect(explain.queryPlanner.winningPlan.inputStage.inputStage.indexName).toBe('_id_');
|
|
});
|
|
|
|
it_only_mongodb_version('<4.4')('query aggregate with hint (rest)', async () => {
|
|
const object = new TestObject({ foo: 'bar' });
|
|
await object.save();
|
|
let options = Object.assign({}, masterKeyOptions, {
|
|
url: Parse.serverURL + '/aggregate/TestObject',
|
|
qs: {
|
|
explain: true,
|
|
group: JSON.stringify({ objectId: '$foo' }),
|
|
},
|
|
});
|
|
let response = await request(options);
|
|
let { queryPlanner } = response.data.results[0].stages[0].$cursor;
|
|
expect(queryPlanner.winningPlan.stage).toBe('COLLSCAN');
|
|
|
|
options = Object.assign({}, masterKeyOptions, {
|
|
url: Parse.serverURL + '/aggregate/TestObject',
|
|
qs: {
|
|
explain: true,
|
|
hint: '_id_',
|
|
group: JSON.stringify({ objectId: '$foo' }),
|
|
},
|
|
});
|
|
response = await request(options);
|
|
queryPlanner = response.data.results[0].stages[0].$cursor.queryPlanner;
|
|
expect(queryPlanner.winningPlan.inputStage.keyPattern).toEqual({ _id: 1 });
|
|
});
|
|
|
|
it_only_mongodb_version('>=4.4')('query aggregate with hint (rest)', async () => {
|
|
const object = new TestObject({ foo: 'bar' });
|
|
await object.save();
|
|
let options = Object.assign({}, masterKeyOptions, {
|
|
url: Parse.serverURL + '/aggregate/TestObject',
|
|
qs: {
|
|
explain: true,
|
|
group: JSON.stringify({ objectId: '$foo' }),
|
|
},
|
|
});
|
|
let response = await request(options);
|
|
let { queryPlanner } = response.data.results[0].stages[0].$cursor;
|
|
expect(queryPlanner.winningPlan.stage).toBe('PROJECTION_SIMPLE');
|
|
expect(queryPlanner.winningPlan.inputStage.stage).toBe('COLLSCAN');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage).toBeUndefined();
|
|
|
|
options = Object.assign({}, masterKeyOptions, {
|
|
url: Parse.serverURL + '/aggregate/TestObject',
|
|
qs: {
|
|
explain: true,
|
|
hint: '_id_',
|
|
group: JSON.stringify({ objectId: '$foo' }),
|
|
},
|
|
});
|
|
response = await request(options);
|
|
queryPlanner = response.data.results[0].stages[0].$cursor.queryPlanner;
|
|
expect(queryPlanner.winningPlan.stage).toBe('PROJECTION_SIMPLE');
|
|
expect(queryPlanner.winningPlan.inputStage.stage).toBe('FETCH');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.stage).toBe('IXSCAN');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.indexName).toBe('_id_');
|
|
expect(queryPlanner.winningPlan.inputStage.inputStage.keyPattern).toEqual({ _id: 1 });
|
|
});
|
|
});
|