Files
kami-parse-server/spec/ReadPreferenceOption.spec.js
Antonio Davi Macedo Coelho de Castro afa74d655d Futzing with read preference (#3963)
* allow setting readpreference when using rest api.

* take out partially complete unit test.

* oops. nit

* Include read preference option for find directly from api and adding few more tests

* Adding catch for all tests

* Keep same check for get and find

* Turn read preference case insensitive

* Includes and subqueries read preferences through API

* Fixing bugs regarding changes that were done in master branch during the last year

* Changing behavior to make includeReadPreference and subqueryReadPreference to follow readPreference by default
2019-05-14 12:58:02 -07:00

1404 lines
45 KiB
JavaScript

'use strict';
const Parse = require('parse/node');
const ReadPreference = require('mongodb').ReadPreference;
const request = require('../lib/request');
const Config = require('../lib/Config');
describe_only_db('mongo')('Read preference option', () => {
it('should find in primary by default', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1])
.then(() => {
spyOn(
databaseAdapter.database.serverConfig,
'cursor'
).and.callThrough();
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
return query.find().then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = true;
expect(call.args[2].readPreference).toBe(null);
}
});
expect(myObjectReadPreference).toBe(true);
done();
});
})
.catch(done.fail);
});
it('should preserve the read preference set (#4831)', async () => {
const {
MongoStorageAdapter,
} = require('../lib/Adapters/Storage/Mongo/MongoStorageAdapter');
const adapterOptions = {
uri: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase',
mongoOptions: {
readPreference: ReadPreference.NEAREST,
},
};
await reconfigureServer({
databaseAdapter: new MongoStorageAdapter(adapterOptions),
});
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
await Parse.Object.saveAll([obj0, obj1]);
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
const results = await query.find();
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls.all().forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = true;
expect(call.args[2].readPreference.preference).toBe(
ReadPreference.NEAREST
);
}
});
expect(myObjectReadPreference).toBe(true);
});
it('should change read preference in the beforeFind trigger', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should check read preference as case insensitive', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'sEcOnDarY';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference in the beforeFind trigger even changing query', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.query.equalTo('boolKey', true);
req.readPreference = 'SECONDARY';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(true);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference in the beforeFind trigger even returning query', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
const otherQuery = new Parse.Query('MyObject');
otherQuery.equalTo('boolKey', true);
return otherQuery;
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(true);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference in the beforeFind trigger even returning promise', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
const otherQuery = new Parse.Query('MyObject');
otherQuery.equalTo('boolKey', true);
return Promise.resolve(otherQuery);
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(true);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference to PRIMARY_PREFERRED', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'PRIMARY_PREFERRED';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(
ReadPreference.PRIMARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change read preference to SECONDARY_PREFERRED', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY_PREFERRED';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change read preference to NEAREST', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'NEAREST';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.NEAREST);
done();
})
.catch(done.fail);
});
});
it('should change read preference for GET', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
});
const query = new Parse.Query('MyObject');
query
.get(obj0.id)
.then(result => {
expect(result.get('boolKey')).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference for GET using API', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
});
request({
method: 'GET',
url: 'http://localhost:8378/1/classes/MyObject/' + obj0.id,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
const body = response.data;
expect(body.boolKey).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference for GET directly from API', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject/' +
obj0.id +
'?readPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.boolKey).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference for GET using API through the beforeFind overriding API option', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY_PREFERRED';
});
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject/' +
obj0.id +
'?readPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.boolKey).toBe(false);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change read preference for FIND using API through beforeFind trigger', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
});
request({
method: 'GET',
url: 'http://localhost:8378/1/classes/MyObject/',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.results.length).toEqual(2);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference for FIND directly from API', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject?readPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.results.length).toEqual(2);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change read preference for FIND using API through the beforeFind overriding API option', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY_PREFERRED';
});
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject/?readPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.results.length).toEqual(2);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change read preference for count', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject');
obj1.set('boolKey', true);
Parse.Object.saveAll([obj0, obj1]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject', req => {
req.readPreference = 'SECONDARY';
});
const query = new Parse.Query('MyObject');
query.equalTo('boolKey', false);
query
.count()
.then(result => {
expect(result).toBe(1);
let myObjectReadPreference = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject') >= 0) {
myObjectReadPreference = call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should find includes in same replica of readPreference by default', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject2', req => {
req.readPreference = 'SECONDARY';
});
const query = new Parse.Query('MyObject2');
query.equalTo('boolKey', false);
query.include('myObject1');
query.include('myObject1.myObject0');
query
.find()
.then(results => {
expect(results.length).toBe(1);
const firstResult = results[0];
expect(firstResult.get('boolKey')).toBe(false);
expect(firstResult.get('myObject1').get('boolKey')).toBe(true);
expect(
firstResult
.get('myObject1')
.get('myObject0')
.get('boolKey')
).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change includes read preference', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject2', req => {
req.readPreference = 'SECONDARY_PREFERRED';
req.includeReadPreference = 'SECONDARY';
});
const query = new Parse.Query('MyObject2');
query.equalTo('boolKey', false);
query.include('myObject1');
query.include('myObject1.myObject0');
query
.find()
.then(results => {
expect(results.length).toBe(1);
const firstResult = results[0];
expect(firstResult.get('boolKey')).toBe(false);
expect(firstResult.get('myObject1').get('boolKey')).toBe(true);
expect(
firstResult
.get('myObject1')
.get('myObject0')
.get('boolKey')
).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change includes read preference when finding through API', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject2/' +
obj2.id +
'?include=' +
JSON.stringify(['myObject1', 'myObject1.myObject0']) +
'&readPreference=SECONDARY_PREFERRED&includeReadPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
const firstResult = response.data;
expect(firstResult.boolKey).toBe(false);
expect(firstResult.myObject1.boolKey).toBe(true);
expect(firstResult.myObject1.myObject0.boolKey).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change includes read preference when getting through API', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject2?where=' +
JSON.stringify({ boolKey: false }) +
'&include=' +
JSON.stringify(['myObject1', 'myObject1.myObject0']) +
'&readPreference=SECONDARY_PREFERRED&includeReadPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.results.length).toBe(1);
const firstResult = response.data.results[0];
expect(firstResult.boolKey).toBe(false);
expect(firstResult.myObject1.boolKey).toBe(true);
expect(firstResult.myObject1.myObject0.boolKey).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should find subqueries in same replica of readPreference by default', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject2', req => {
req.readPreference = 'SECONDARY';
});
const query0 = new Parse.Query('MyObject0');
query0.equalTo('boolKey', false);
const query1 = new Parse.Query('MyObject1');
query1.matchesQuery('myObject0', query0);
const query2 = new Parse.Query('MyObject2');
query2.matchesQuery('myObject1', query1);
query2
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(ReadPreference.SECONDARY);
done();
})
.catch(done.fail);
});
});
it('should change subqueries read preference when using matchesQuery', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject2', req => {
req.readPreference = 'SECONDARY_PREFERRED';
req.subqueryReadPreference = 'SECONDARY';
});
const query0 = new Parse.Query('MyObject0');
query0.equalTo('boolKey', false);
const query1 = new Parse.Query('MyObject1');
query1.matchesQuery('myObject0', query0);
const query2 = new Parse.Query('MyObject2');
query2.matchesQuery('myObject1', query1);
query2
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change subqueries read preference when using doesNotMatchQuery', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject2', req => {
req.readPreference = 'SECONDARY_PREFERRED';
req.subqueryReadPreference = 'SECONDARY';
});
const query0 = new Parse.Query('MyObject0');
query0.equalTo('boolKey', false);
const query1 = new Parse.Query('MyObject1');
query1.doesNotMatchQuery('myObject0', query0);
const query2 = new Parse.Query('MyObject2');
query2.doesNotMatchQuery('myObject1', query1);
query2
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change subqueries read preference when using matchesKeyInQuery and doesNotMatchKeyInQuery', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
Parse.Cloud.beforeFind('MyObject2', req => {
req.readPreference = 'SECONDARY_PREFERRED';
req.subqueryReadPreference = 'SECONDARY';
});
const query0 = new Parse.Query('MyObject0');
query0.equalTo('boolKey', false);
const query1 = new Parse.Query('MyObject1');
query1.equalTo('boolKey', true);
const query2 = new Parse.Query('MyObject2');
query2.matchesKeyInQuery('boolKey', 'boolKey', query0);
query2.doesNotMatchKeyInQuery('boolKey', 'boolKey', query1);
query2
.find()
.then(results => {
expect(results.length).toBe(1);
expect(results[0].get('boolKey')).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
it('should change subqueries read preference when using matchesKeyInQuery and doesNotMatchKeyInQuery to find through API', done => {
const databaseAdapter = Config.get(Parse.applicationId).database.adapter;
const obj0 = new Parse.Object('MyObject0');
obj0.set('boolKey', false);
const obj1 = new Parse.Object('MyObject1');
obj1.set('boolKey', true);
obj1.set('myObject0', obj0);
const obj2 = new Parse.Object('MyObject2');
obj2.set('boolKey', false);
obj2.set('myObject1', obj1);
Parse.Object.saveAll([obj0, obj1, obj2]).then(() => {
spyOn(databaseAdapter.database.serverConfig, 'cursor').and.callThrough();
const whereString = JSON.stringify({
boolKey: {
$select: {
query: {
className: 'MyObject0',
where: { boolKey: false },
},
key: 'boolKey',
},
$dontSelect: {
query: {
className: 'MyObject1',
where: { boolKey: true },
},
key: 'boolKey',
},
},
});
request({
method: 'GET',
url:
'http://localhost:8378/1/classes/MyObject2/?where=' +
whereString +
'&readPreference=SECONDARY_PREFERRED&subqueryReadPreference=SECONDARY',
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-REST-API-Key': 'rest',
},
json: true,
})
.then(response => {
expect(response.data.results.length).toBe(1);
expect(response.data.results[0].boolKey).toBe(false);
let myObjectReadPreference0 = null;
let myObjectReadPreference1 = null;
let myObjectReadPreference2 = null;
databaseAdapter.database.serverConfig.cursor.calls
.all()
.forEach(call => {
if (call.args[0].indexOf('MyObject0') >= 0) {
myObjectReadPreference0 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject1') >= 0) {
myObjectReadPreference1 =
call.args[2].readPreference.preference;
}
if (call.args[0].indexOf('MyObject2') >= 0) {
myObjectReadPreference2 =
call.args[2].readPreference.preference;
}
});
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
expect(myObjectReadPreference2).toEqual(
ReadPreference.SECONDARY_PREFERRED
);
done();
})
.catch(done.fail);
});
});
});