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
This commit is contained in:
committed by
GitHub
parent
893f1d376e
commit
afa74d655d
@@ -41,16 +41,12 @@ describe('GridFSBucket and GridStore interop', () => {
|
||||
expect(gfsResult.toString('utf8')).toBe(twoMegabytesFile);
|
||||
});
|
||||
|
||||
it(
|
||||
'properly deletes a file from GridFS',
|
||||
async () => {
|
||||
it('properly deletes a file from GridFS', async () => {
|
||||
const gfsAdapter = new GridFSBucketAdapter(databaseURI);
|
||||
await gfsAdapter.createFile('myFileName', 'a simple file');
|
||||
await gfsAdapter.deleteFile('myFileName');
|
||||
await expectMissingFile(gfsAdapter, 'myFileName');
|
||||
},
|
||||
1000000
|
||||
);
|
||||
}, 1000000);
|
||||
|
||||
it('properly overrides files', async () => {
|
||||
const gfsAdapter = new GridFSBucketAdapter(databaseURI);
|
||||
|
||||
@@ -108,7 +108,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -124,8 +126,50 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
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 => {
|
||||
@@ -147,7 +191,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(true);
|
||||
|
||||
@@ -163,7 +209,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -189,7 +236,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(true);
|
||||
|
||||
@@ -205,7 +254,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -231,7 +281,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(true);
|
||||
|
||||
@@ -247,7 +299,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -269,7 +322,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -287,7 +342,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -309,7 +365,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -327,7 +385,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -349,7 +408,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -365,7 +426,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
expect(myObjectReadPreference).toEqual(ReadPreference.NEAREST);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -386,7 +448,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
|
||||
const query = new Parse.Query('MyObject');
|
||||
|
||||
query.get(obj0.id).then(result => {
|
||||
query
|
||||
.get(obj0.id)
|
||||
.then(result => {
|
||||
expect(result.get('boolKey')).toBe(false);
|
||||
|
||||
let myObjectReadPreference = null;
|
||||
@@ -401,7 +465,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -428,7 +493,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
'X-Parse-REST-API-Key': 'rest',
|
||||
},
|
||||
json: true,
|
||||
}).then(response => {
|
||||
})
|
||||
.then(response => {
|
||||
const body = response.data;
|
||||
expect(body.boolKey).toBe(false);
|
||||
|
||||
@@ -444,8 +510,233 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
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 => {
|
||||
@@ -466,7 +757,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query = new Parse.Query('MyObject');
|
||||
query.equalTo('boolKey', false);
|
||||
|
||||
query.count().then(result => {
|
||||
query
|
||||
.count()
|
||||
.then(result => {
|
||||
expect(result).toBe(1);
|
||||
|
||||
let myObjectReadPreference = null;
|
||||
@@ -481,11 +774,12 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
expect(myObjectReadPreference).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
it('should find includes in primary by default', done => {
|
||||
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');
|
||||
@@ -509,7 +803,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
query.include('myObject1');
|
||||
query.include('myObject1.myObject0');
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
const firstResult = results[0];
|
||||
expect(firstResult.get('boolKey')).toBe(false);
|
||||
@@ -528,24 +824,26 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
.all()
|
||||
.forEach(call => {
|
||||
if (call.args[0].indexOf('MyObject0') >= 0) {
|
||||
myObjectReadPreference0 = true;
|
||||
expect(call.args[2].readPreference).toBe(null);
|
||||
myObjectReadPreference0 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject1') >= 0) {
|
||||
myObjectReadPreference1 = true;
|
||||
expect(call.args[2].readPreference).toBe(null);
|
||||
myObjectReadPreference1 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject2') >= 0) {
|
||||
myObjectReadPreference2 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference2 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
});
|
||||
|
||||
expect(myObjectReadPreference0).toBe(true);
|
||||
expect(myObjectReadPreference1).toBe(true);
|
||||
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
|
||||
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
|
||||
expect(myObjectReadPreference2).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -574,7 +872,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
query.include('myObject1');
|
||||
query.include('myObject1.myObject0');
|
||||
|
||||
query.find().then(results => {
|
||||
query
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
const firstResult = results[0];
|
||||
expect(firstResult.get('boolKey')).toBe(false);
|
||||
@@ -593,13 +893,16 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
.all()
|
||||
.forEach(call => {
|
||||
if (call.args[0].indexOf('MyObject0') >= 0) {
|
||||
myObjectReadPreference0 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference0 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject1') >= 0) {
|
||||
myObjectReadPreference1 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference1 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject2') >= 0) {
|
||||
myObjectReadPreference2 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference2 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -610,11 +913,147 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
it('should find subqueries in primary by default', done => {
|
||||
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');
|
||||
@@ -642,7 +1081,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query2 = new Parse.Query('MyObject2');
|
||||
query2.matchesQuery('myObject1', query1);
|
||||
|
||||
query2.find().then(results => {
|
||||
query2
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -653,24 +1094,26 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
.all()
|
||||
.forEach(call => {
|
||||
if (call.args[0].indexOf('MyObject0') >= 0) {
|
||||
myObjectReadPreference0 = true;
|
||||
expect(call.args[2].readPreference).toBe(null);
|
||||
myObjectReadPreference0 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject1') >= 0) {
|
||||
myObjectReadPreference1 = true;
|
||||
expect(call.args[2].readPreference).toBe(null);
|
||||
myObjectReadPreference1 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject2') >= 0) {
|
||||
myObjectReadPreference2 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference2 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
});
|
||||
|
||||
expect(myObjectReadPreference0).toBe(true);
|
||||
expect(myObjectReadPreference1).toBe(true);
|
||||
expect(myObjectReadPreference0).toEqual(ReadPreference.SECONDARY);
|
||||
expect(myObjectReadPreference1).toEqual(ReadPreference.SECONDARY);
|
||||
expect(myObjectReadPreference2).toEqual(ReadPreference.SECONDARY);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -703,7 +1146,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query2 = new Parse.Query('MyObject2');
|
||||
query2.matchesQuery('myObject1', query1);
|
||||
|
||||
query2.find().then(results => {
|
||||
query2
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -714,13 +1159,16 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
.all()
|
||||
.forEach(call => {
|
||||
if (call.args[0].indexOf('MyObject0') >= 0) {
|
||||
myObjectReadPreference0 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference0 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject1') >= 0) {
|
||||
myObjectReadPreference1 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference1 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject2') >= 0) {
|
||||
myObjectReadPreference2 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference2 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -731,7 +1179,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -764,7 +1213,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
const query2 = new Parse.Query('MyObject2');
|
||||
query2.doesNotMatchQuery('myObject1', query1);
|
||||
|
||||
query2.find().then(results => {
|
||||
query2
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -775,13 +1226,16 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
.all()
|
||||
.forEach(call => {
|
||||
if (call.args[0].indexOf('MyObject0') >= 0) {
|
||||
myObjectReadPreference0 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference0 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject1') >= 0) {
|
||||
myObjectReadPreference1 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference1 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject2') >= 0) {
|
||||
myObjectReadPreference2 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference2 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -792,7 +1246,8 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
.catch(done.fail);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -826,7 +1281,9 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
query2.matchesKeyInQuery('boolKey', 'boolKey', query0);
|
||||
query2.doesNotMatchKeyInQuery('boolKey', 'boolKey', query1);
|
||||
|
||||
query2.find().then(results => {
|
||||
query2
|
||||
.find()
|
||||
.then(results => {
|
||||
expect(results.length).toBe(1);
|
||||
expect(results[0].get('boolKey')).toBe(false);
|
||||
|
||||
@@ -837,13 +1294,16 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
.all()
|
||||
.forEach(call => {
|
||||
if (call.args[0].indexOf('MyObject0') >= 0) {
|
||||
myObjectReadPreference0 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference0 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject1') >= 0) {
|
||||
myObjectReadPreference1 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference1 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
if (call.args[0].indexOf('MyObject2') >= 0) {
|
||||
myObjectReadPreference2 = call.args[2].readPreference.preference;
|
||||
myObjectReadPreference2 =
|
||||
call.args[2].readPreference.preference;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -854,7 +1314,90 @@ describe_only_db('mongo')('Read preference option', () => {
|
||||
);
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -926,6 +926,9 @@ export class MongoStorageAdapter implements StorageAdapter {
|
||||
}
|
||||
|
||||
_parseReadPreference(readPreference: ?string): ?string {
|
||||
if (readPreference) {
|
||||
readPreference = readPreference.toUpperCase();
|
||||
}
|
||||
switch (readPreference) {
|
||||
case 'PRIMARY':
|
||||
readPreference = ReadPreference.PRIMARY;
|
||||
|
||||
@@ -14,6 +14,9 @@ const AlwaysSelectedKeys = ['objectId', 'createdAt', 'updatedAt', 'ACL'];
|
||||
// include
|
||||
// keys
|
||||
// redirectClassNameForKey
|
||||
// readPreference
|
||||
// includeReadPreference
|
||||
// subqueryReadPreference
|
||||
function RestQuery(
|
||||
config,
|
||||
auth,
|
||||
@@ -362,6 +365,8 @@ RestQuery.prototype.replaceInQuery = function() {
|
||||
if (this.restOptions.subqueryReadPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.subqueryReadPreference;
|
||||
additionalOptions.subqueryReadPreference = this.restOptions.subqueryReadPreference;
|
||||
} else if (this.restOptions.readPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.readPreference;
|
||||
}
|
||||
|
||||
var subquery = new RestQuery(
|
||||
@@ -421,6 +426,8 @@ RestQuery.prototype.replaceNotInQuery = function() {
|
||||
if (this.restOptions.subqueryReadPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.subqueryReadPreference;
|
||||
additionalOptions.subqueryReadPreference = this.restOptions.subqueryReadPreference;
|
||||
} else if (this.restOptions.readPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.readPreference;
|
||||
}
|
||||
|
||||
var subquery = new RestQuery(
|
||||
@@ -484,6 +491,8 @@ RestQuery.prototype.replaceSelect = function() {
|
||||
if (this.restOptions.subqueryReadPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.subqueryReadPreference;
|
||||
additionalOptions.subqueryReadPreference = this.restOptions.subqueryReadPreference;
|
||||
} else if (this.restOptions.readPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.readPreference;
|
||||
}
|
||||
|
||||
var subquery = new RestQuery(
|
||||
@@ -545,6 +554,8 @@ RestQuery.prototype.replaceDontSelect = function() {
|
||||
if (this.restOptions.subqueryReadPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.subqueryReadPreference;
|
||||
additionalOptions.subqueryReadPreference = this.restOptions.subqueryReadPreference;
|
||||
} else if (this.restOptions.readPreference) {
|
||||
additionalOptions.readPreference = this.restOptions.readPreference;
|
||||
}
|
||||
|
||||
var subquery = new RestQuery(
|
||||
@@ -809,6 +820,8 @@ function includePath(config, auth, response, path, restOptions = {}) {
|
||||
includeRestOptions.readPreference = restOptions.includeReadPreference;
|
||||
includeRestOptions.includeReadPreference =
|
||||
restOptions.includeReadPreference;
|
||||
} else if (restOptions.readPreference) {
|
||||
includeRestOptions.readPreference = restOptions.readPreference;
|
||||
}
|
||||
|
||||
const queryPromises = Object.keys(pointersHash).map(className => {
|
||||
|
||||
@@ -3,7 +3,13 @@ import rest from '../rest';
|
||||
import _ from 'lodash';
|
||||
import Parse from 'parse/node';
|
||||
|
||||
const ALLOWED_GET_QUERY_KEYS = ['keys', 'include'];
|
||||
const ALLOWED_GET_QUERY_KEYS = [
|
||||
'keys',
|
||||
'include',
|
||||
'readPreference',
|
||||
'includeReadPreference',
|
||||
'subqueryReadPreference',
|
||||
];
|
||||
|
||||
export class ClassesRouter extends PromiseRouter {
|
||||
className(req) {
|
||||
@@ -57,12 +63,21 @@ export class ClassesRouter extends PromiseRouter {
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof body.keys == 'string') {
|
||||
if (typeof body.keys === 'string') {
|
||||
options.keys = body.keys;
|
||||
}
|
||||
if (body.include) {
|
||||
options.include = String(body.include);
|
||||
}
|
||||
if (typeof body.readPreference === 'string') {
|
||||
options.readPreference = body.readPreference;
|
||||
}
|
||||
if (typeof body.includeReadPreference === 'string') {
|
||||
options.includeReadPreference = body.includeReadPreference;
|
||||
}
|
||||
if (typeof body.subqueryReadPreference === 'string') {
|
||||
options.subqueryReadPreference = body.subqueryReadPreference;
|
||||
}
|
||||
|
||||
return rest
|
||||
.get(
|
||||
@@ -154,6 +169,9 @@ export class ClassesRouter extends PromiseRouter {
|
||||
'includeAll',
|
||||
'redirectClassNameForKey',
|
||||
'where',
|
||||
'readPreference',
|
||||
'includeReadPreference',
|
||||
'subqueryReadPreference',
|
||||
];
|
||||
|
||||
for (const key of Object.keys(body)) {
|
||||
@@ -188,6 +206,15 @@ export class ClassesRouter extends PromiseRouter {
|
||||
if (body.includeAll) {
|
||||
options.includeAll = true;
|
||||
}
|
||||
if (typeof body.readPreference === 'string') {
|
||||
options.readPreference = body.readPreference;
|
||||
}
|
||||
if (typeof body.includeReadPreference === 'string') {
|
||||
options.includeReadPreference = body.includeReadPreference;
|
||||
}
|
||||
if (typeof body.subqueryReadPreference === 'string') {
|
||||
options.subqueryReadPreference = body.subqueryReadPreference;
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
|
||||
16
src/vendor/mongodbUrl.js
vendored
16
src/vendor/mongodbUrl.js
vendored
@@ -101,7 +101,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
|
||||
code === 10 /*\n*/ ||
|
||||
code === 12 /*\f*/ ||
|
||||
code === 160 /*\u00A0*/ ||
|
||||
code === 65279 /*\uFEFF*/;
|
||||
code === 65279; /*\uFEFF*/
|
||||
if (start === -1) {
|
||||
if (isWs) continue;
|
||||
lastPos = start = i;
|
||||
@@ -193,7 +193,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
|
||||
// how the browser resolves relative URLs.
|
||||
if (slashesDenoteHost || proto || /^\/\/[^@\/]+@[^@\/]+/.test(rest)) {
|
||||
var slashes =
|
||||
rest.charCodeAt(0) === 47 /*/*/ && rest.charCodeAt(1) === 47 /*/*/;
|
||||
rest.charCodeAt(0) === 47 /*/*/ && rest.charCodeAt(1) === 47; /*/*/
|
||||
if (slashes && !(proto && hostlessProtocol[proto])) {
|
||||
rest = rest.slice(2);
|
||||
this.slashes = true;
|
||||
@@ -285,7 +285,7 @@ Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
|
||||
// assume that it's an IPv6 address.
|
||||
var ipv6Hostname =
|
||||
hostname.charCodeAt(0) === 91 /*[*/ &&
|
||||
hostname.charCodeAt(hostname.length - 1) === 93 /*]*/;
|
||||
hostname.charCodeAt(hostname.length - 1) === 93; /*]*/
|
||||
|
||||
// validate a little.
|
||||
if (!ipv6Hostname) {
|
||||
@@ -868,11 +868,11 @@ Url.prototype.resolveObject = function(relative) {
|
||||
|
||||
// put the host back
|
||||
if (psychotic) {
|
||||
result.hostname = result.host = isAbsolute
|
||||
? ''
|
||||
: srcPath.length
|
||||
? srcPath.shift()
|
||||
: '';
|
||||
if (isAbsolute) {
|
||||
result.hostname = result.host = '';
|
||||
} else {
|
||||
result.hostname = result.host = srcPath.length ? srcPath.shift() : '';
|
||||
}
|
||||
//occasionally the auth can get stuck only in host
|
||||
//this especially happens in cases like
|
||||
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
|
||||
|
||||
Reference in New Issue
Block a user