Remove mongoFind and mostly remove adaptiveCollection (#1924)

* Use adapter.count

* use adapter.upsertOneObject

* Use adapter.deleteObjectsByQuery

* Use adapter.find

* use adapter.find

* Update tests to avoid mongoFind

* Fix a test to not use mongoFind

* Fix a test to not use mongoFind

* remove some mongoFind

* Remove some mongoFind

* Remove some mongoFind

* Remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* remove more mongoFind

* Restore update ios device token with duplicate device token to original

* remove a mongoFind

* remove a mongoFind

* formatting

* formatting

* remove a mongoFind

* remove a mongoFind

* remove a mongoFind

* kill mongoFind

* Fix tests

* Fix tests

* fix syntax

* Fix test
This commit is contained in:
Drew
2016-05-28 09:25:09 -07:00
committed by Florent Vilmart
parent 17374eff8d
commit cd525802a6
7 changed files with 349 additions and 259 deletions

View File

@@ -2,8 +2,17 @@
const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter'); const MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
const MongoClient = require('mongodb').MongoClient; const MongoClient = require('mongodb').MongoClient;
const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase';
// These tests are specific to the mongo storage adapter + mongo storage format
// and will eventually be moved into their own repo
describe('MongoStorageAdapter', () => { describe('MongoStorageAdapter', () => {
beforeEach(done => {
new MongoStorageAdapter({ uri: databaseURI })
.deleteAllSchemas()
.then(done, fail);
});
it('auto-escapes symbols in auth information', () => { it('auto-escapes symbols in auth information', () => {
spyOn(MongoClient, 'connect').and.returnValue(Promise.resolve(null)); spyOn(MongoClient, 'connect').and.returnValue(Promise.resolve(null));
new MongoStorageAdapter({ new MongoStorageAdapter({
@@ -37,4 +46,110 @@ describe('MongoStorageAdapter', () => {
jasmine.any(Object) jasmine.any(Object)
); );
}); });
it('stores objectId in _id', done => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
adapter.createObject('Foo', { objectId: 'abcde' }, { fields: { objectId: 'String' } })
.then(() => adapter._rawFind('Foo', {}))
.then(results => {
expect(results.length).toEqual(1);
var obj = results[0];
expect(typeof obj._id).toEqual('string');
expect(obj.objectId).toBeUndefined();
done();
});
});
it('stores pointers with a _p_ prefix', (done) => {
let obj = {
objectId: 'bar',
aPointer: {
__type: 'Pointer',
className: 'JustThePointer',
objectId: 'qwerty'
}
};
let adapter = new MongoStorageAdapter({ uri: databaseURI });
adapter.createObject('APointerDarkly', obj, { fields: {
objectId: { type: 'String' },
aPointer: { type: 'Pointer', targetClass: 'JustThePointer' },
}})
.then(() => adapter._rawFind('APointerDarkly', {}))
.then(results => {
expect(results.length).toEqual(1);
let output = results[0];
expect(typeof output._id).toEqual('string');
expect(typeof output._p_aPointer).toEqual('string');
expect(output._p_aPointer).toEqual('JustThePointer$qwerty');
expect(output.aPointer).toBeUndefined();
done();
});
});
it('handles object and subdocument', done => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
let schema = { fields : { subdoc: { type: 'Object' } } };
let obj = { subdoc: {foo: 'bar', wu: 'tan'} };
adapter.createObject('MyClass', obj, schema)
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('tan');
let obj = { 'subdoc.wu': 'clan' };
return adapter.findOneAndUpdate('MyClass', {}, schema, obj);
})
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('clan');
done();
});
});
it('handles array, object, date', (done) => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
let obj = {
array: [1, 2, 3],
object: {foo: 'bar'},
date: {
__type: 'Date',
iso: '2016-05-26T20:55:01.154Z',
},
};
let schema = { fields: {
array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
} };
adapter.createObject('MyClass', obj, schema)
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date instanceof Date).toBe(true);
return adapter.find('MyClass', {}, schema, {});
})
.then(results => {
expect(results.length).toEqual(1);
let mob = results[0];
expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object');
expect(mob.date.__type).toBe('Date');
expect(mob.date.iso).toBe('2016-05-26T20:55:01.154Z');
done();
})
.catch(error => {
console.log(error);
fail();
done();
});
});
}); });

View File

@@ -1,6 +1,7 @@
var OAuth = require("../src/authDataManager/OAuth1Client"); var OAuth = require("../src/authDataManager/OAuth1Client");
var request = require('request'); var request = require('request');
var Config = require("../src/Config"); var Config = require("../src/Config");
var defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
describe('OAuth', function() { describe('OAuth', function() {
@@ -283,9 +284,10 @@ describe('OAuth', function() {
"Expiration should be cleared"); "Expiration should be cleared");
// make sure the auth data is properly deleted // make sure the auth data is properly deleted
var config = new Config(Parse.applicationId); var config = new Config(Parse.applicationId);
config.database.mongoFind('_User', { config.database.adapter.find('_User', { objectId: model.id }, {
_id: model.id fields: Object.assign({}, defaultColumns._Default, defaultColumns._Installation),
}).then((res) => { }, {})
.then(res => {
expect(res.length).toBe(1); expect(res.length).toBe(1);
expect(res[0]._auth_data_myoauth).toBeUndefined(); expect(res[0]._auth_data_myoauth).toBeUndefined();
expect(res[0]._auth_data_myoauth).not.toBeNull(); expect(res[0]._auth_data_myoauth).not.toBeNull();

View File

@@ -203,7 +203,7 @@ describe('miscellaneous', function() {
return obj.save(); return obj.save();
}).then(() => { }).then(() => {
var db = DatabaseAdapter.getDatabaseConnection(appId, 'test_'); var db = DatabaseAdapter.getDatabaseConnection(appId, 'test_');
return db.mongoFind('TestObject', {}, {}); return db.adapter.find('TestObject', {}, { fields: {} }, {});
}).then((results) => { }).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar'); expect(results[0]['foo']).toEqual('bar');

View File

@@ -11,9 +11,11 @@ var rest = require('../src/rest');
var config = new Config('test'); var config = new Config('test');
let database = DatabaseAdapter.getDatabaseConnection('test', 'test_'); let database = DatabaseAdapter.getDatabaseConnection('test', 'test_');
let defaultColumns = require('../src/Controllers/SchemaController').defaultColumns;
const installationSchema = { fields: Object.assign({}, defaultColumns._Default, defaultColumns._Installation) };
describe('Installations', () => { describe('Installations', () => {
it('creates an android installation with ids', (done) => { it('creates an android installation with ids', (done) => {
var installId = '12345678-abcd-abcd-abcd-123456789abc'; var installId = '12345678-abcd-abcd-abcd-123456789abc';
var device = 'android'; var device = 'android';
@@ -22,9 +24,8 @@ describe('Installations', () => {
'deviceType': device 'deviceType': device
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(obj.installationId).toEqual(installId); expect(obj.installationId).toEqual(installId);
@@ -41,9 +42,8 @@ describe('Installations', () => {
'deviceType': device 'deviceType': device
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(obj.deviceToken).toEqual(t); expect(obj.deviceToken).toEqual(t);
@@ -60,9 +60,8 @@ describe('Installations', () => {
'deviceType': device 'deviceType': device
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(obj.installationId).toEqual(installId); expect(obj.installationId).toEqual(installId);
@@ -80,9 +79,8 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(obj.installationId).toEqual(installId); expect(obj.installationId).toEqual(installId);
@@ -104,9 +102,8 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(obj.deviceToken).toEqual(t); expect(obj.deviceToken).toEqual(t);
@@ -203,9 +200,8 @@ describe('Installations', () => {
'custom': 'allowed' 'custom': 'allowed'
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(obj.custom).toEqual('allowed'); expect(obj.custom).toEqual('allowed');
@@ -228,18 +224,17 @@ describe('Installations', () => {
var firstObject; var firstObject;
var secondObject; var secondObject;
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
firstObject = results[0]; firstObject = results[0];
delete input.deviceToken; delete input.deviceToken;
delete input.channels; delete input.channels;
input['foo'] = 'bar'; input['foo'] = 'bar';
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', {}, {}); .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
secondObject = results[0]; secondObject = results[0];
expect(firstObject._id).toEqual(secondObject._id); expect(firstObject._id).toEqual(secondObject._id);
@@ -268,15 +263,14 @@ describe('Installations', () => {
var firstObject; var firstObject;
var secondObject; var secondObject;
rest.create(config, auth.nobody(config), '_Installation', input1) rest.create(config, auth.nobody(config), '_Installation', input1)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
firstObject = results[0]; firstObject = results[0];
return rest.create(config, auth.nobody(config), '_Installation', input2); return rest.create(config, auth.nobody(config), '_Installation', input2);
}).then(() => { })
return database.mongoFind('_Installation', {}, {}); .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(2); expect(results.length).toEqual(2);
if (results[0]['_id'] == firstObject._id) { if (results[0]['_id'] == firstObject._id) {
secondObject = results[1]; secondObject = results[1];
@@ -284,9 +278,9 @@ describe('Installations', () => {
secondObject = results[0]; secondObject = results[0];
} }
return rest.create(config, auth.nobody(config), '_Installation', input3); return rest.create(config, auth.nobody(config), '_Installation', input3);
}).then(() => { })
return database.mongoFind('_Installation', {}, {}); .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0]['_id']).toEqual(secondObject._id); expect(results[0]['_id']).toEqual(secondObject._id);
done(); done();
@@ -310,17 +304,14 @@ describe('Installations', () => {
}).then(() => { }).then(() => {
input.installationId = installId3; input.installationId = installId3;
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', .then(() => database.adapter.find('_Installation', {installationId: installId1}, installationSchema, {}))
{installationId: installId1}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
return database.mongoFind('_Installation', return database.adapter.find('_Installation', {installationId: installId2}, installationSchema, {});
{installationId: installId2}, {}); }).then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
return database.mongoFind('_Installation', return database.adapter.find('_Installation', {installationId: installId3}, installationSchema, {});
{installationId: installId3}, {});
}).then((results) => { }).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
done(); done();
@@ -329,29 +320,31 @@ describe('Installations', () => {
it('updating with new channels', (done) => { it('updating with new channels', (done) => {
var input = { var input = {
'installationId': '12345678-abcd-abcd-abcd-123456789abc', installationId: '12345678-abcd-abcd-abcd-123456789abc',
'deviceType': 'android', deviceType: 'android',
'channels': ['foo', 'bar'] channels: ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var id = results[0]['_id']; var id = results[0].objectId;
var update = { var update = {
'channels': ['baz'] 'channels': ['baz']
}; };
return rest.update(config, auth.nobody(config), return rest.update(config, auth.nobody(config), '_Installation', id, update);
'_Installation', id, update); })
}).then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].channels.length).toEqual(1); expect(results[0].channels.length).toEqual(1);
expect(results[0].channels[0]).toEqual('baz'); expect(results[0].channels[0]).toEqual('baz');
done(); done();
}).catch((error) => { console.log(error); }); }).catch(error => {
console.log(error);
fail();
done();
});
}); });
it('update android fails with new installation id', (done) => { it('update android fails with new installation id', (done) => {
@@ -363,15 +356,11 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = { 'installationId': installId2 };
'installationId': installId2 return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
};
return rest.update(config, auth.nobody(config), '_Installation',
results[0]['_id'], input);
}).then(() => { }).then(() => {
fail('Updating the installation should have failed.'); fail('Updating the installation should have failed.');
done(); done();
@@ -390,15 +379,11 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = { 'deviceToken': b };
'deviceToken': b return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
};
return rest.update(config, auth.nobody(config), '_Installation',
results[0]['_id'], input);
}).then(() => { }).then(() => {
fail('Updating the installation should have failed.'); fail('Updating the installation should have failed.');
}).catch((error) => { }).catch((error) => {
@@ -418,20 +403,18 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'installationId': installId, 'installationId': installId,
'deviceToken': u, 'deviceToken': u,
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
results[0]['_id'], input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].deviceToken).toEqual(u); expect(results[0].deviceToken).toEqual(u);
done(); done();
@@ -446,15 +429,13 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
results[0]['_id'], input);
}).then(() => { }).then(() => {
fail('Should not have been able to update Installation.'); fail('Should not have been able to update Installation.');
done(); done();
@@ -472,18 +453,16 @@ describe('Installations', () => {
'channels': ['foo', 'bar'] 'channels': ['foo', 'bar']
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'custom': 'allowed' 'custom': 'allowed'
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
results[0]['_id'], input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0]['custom']).toEqual('allowed'); expect(results[0]['custom']).toEqual('allowed');
done(); done();
@@ -502,40 +481,36 @@ describe('Installations', () => {
var firstObject; var firstObject;
var secondObject; var secondObject;
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => {
input = { input = {
'installationId': installId2, 'installationId': installId2,
'deviceType': 'android' 'deviceType': 'android'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', .then(() => database.adapter.find('_Installation', {installationId: installId1}, installationSchema, {}))
{installationId: installId1}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1);
firstObject = results[0]; firstObject = results[0];
return database.mongoFind('_Installation', expect(results.length).toEqual(1);
{installationId: installId2}, {}); return database.adapter.find('_Installation', {installationId: installId2}, installationSchema, {});
}).then((results) => { }).then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
secondObject = results[0]; secondObject = results[0];
// Update second installation to conflict with first installation // Update second installation to conflict with first installation
input = { input = {
'objectId': secondObject._id, 'objectId': secondObject.objectId,
'deviceToken': t 'deviceToken': t
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', secondObject.objectId, input);
secondObject._id, input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {objectId: firstObject.objectId}, installationSchema, {}))
.then(results => {
// The first object should have been deleted // The first object should have been deleted
return database.mongoFind('_Installation', {_id: firstObject._id}, {});
}).then((results) => {
expect(results.length).toEqual(0); expect(results.length).toEqual(0);
done(); done();
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
}); });
it('update ios device token with duplicate device token', (done) => { it('update ios device token with duplicate device token', (done) => {
var installId1 = '11111111-abcd-abcd-abcd-123456789abc'; var installId1 = '11111111-abcd-abcd-abcd-123456789abc';
var installId2 = '22222222-abcd-abcd-abcd-123456789abc'; var installId2 = '22222222-abcd-abcd-abcd-123456789abc';
@@ -554,15 +529,14 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', .then(() => database.adapter.find('_Installation', {installationId: installId1}, installationSchema, {}))
{installationId: installId1}, {}); .then((results) => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
firstObject = results[0]; firstObject = results[0];
return database.mongoFind('_Installation', return database.adapter.find('_Installation', {installationId: installId2}, installationSchema, {});
{installationId: installId2}, {}); })
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
secondObject = results[0]; secondObject = results[0];
// Update second installation to conflict with first installation id // Update second installation to conflict with first installation id
@@ -570,12 +544,11 @@ describe('Installations', () => {
'installationId': installId2, 'installationId': installId2,
'deviceToken': t 'deviceToken': t
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', secondObject.objectId, input);
secondObject._id, input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {objectId: firstObject.objectId}, installationSchema, {}))
.then(results => {
// The first object should have been deleted // The first object should have been deleted
return database.mongoFind('_Installation', {_id: firstObject._id}, {});
}).then((results) => {
expect(results.length).toEqual(0); expect(results.length).toEqual(0);
done(); done();
}).catch((error) => { console.log(error); }); }).catch((error) => { console.log(error); });
@@ -596,9 +569,9 @@ describe('Installations', () => {
input.installationId = installId2; input.installationId = installId2;
input.appIdentifier = 'bar'; input.appIdentifier = 'bar';
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', {}, {}); .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
}).then((results) => { .then(results => {
// The first object should have been deleted during merge // The first object should have been deleted during merge
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId2); expect(results[0].installationId).toEqual(installId2);
@@ -614,19 +587,17 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'deviceToken': t, 'deviceToken': t,
'channels': [] 'channels': []
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
results[0]['_id'], input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
@@ -649,21 +620,19 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', .then(() => database.adapter.find('_Installation', { deviceToken: t }, installationSchema, {}))
{deviceToken: t}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'deviceToken': t, 'deviceToken': t,
'installationId': installId, 'installationId': installId,
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
results[0]['_id'], input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
@@ -686,10 +655,9 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', .then(() => database.adapter.find('_Installation', { deviceToken: t }, installationSchema, {}))
{deviceToken: t}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'deviceToken': t, 'deviceToken': t,
@@ -700,11 +668,10 @@ describe('Installations', () => {
'amount': 1 'amount': 1
} }
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', results[0].objectId, input);
results[0]['_id'], input); })
}).then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
@@ -724,9 +691,8 @@ describe('Installations', () => {
var installObj; var installObj;
var tokenObj; var tokenObj;
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
installObj = results[0]; installObj = results[0];
input = { input = {
@@ -734,9 +700,9 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', {deviceToken: t}, {}); .then(() => database.adapter.find('_Installation', { deviceToken: t }, installationSchema, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
tokenObj = results[0]; tokenObj = results[0];
input = { input = {
@@ -744,11 +710,10 @@ describe('Installations', () => {
'deviceToken': t, 'deviceToken': t,
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', installObj.objectId, input);
installObj._id, input); })
}).then(() => { .then(() => database.adapter.find('_Installation', { objectId: tokenObj.objectId }, installationSchema, {}))
return database.mongoFind('_Installation', {_id: tokenObj._id}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
@@ -766,9 +731,8 @@ describe('Installations', () => {
var installObj; var installObj;
var tokenObj; var tokenObj;
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
installObj = results[0]; installObj = results[0];
input = { input = {
@@ -776,9 +740,9 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', {deviceToken: t}, {}); .then(() => database.adapter.find('_Installation', { deviceToken: t }, installationSchema, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
tokenObj = results[0]; tokenObj = results[0];
input = { input = {
@@ -790,11 +754,10 @@ describe('Installations', () => {
'amount': 1 'amount': 1
} }
}; };
return rest.update(config, auth.nobody(config), '_Installation', return rest.update(config, auth.nobody(config), '_Installation', installObj.objectId, input);
installObj._id, input); })
}).then(() => { .then(() => database.adapter.find('_Installation', { objectId: tokenObj.objectId }, installationSchema, {}))
return database.mongoFind('_Installation', {_id: tokenObj._id}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
@@ -821,9 +784,8 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
rest.create(config, auth.nobody(config), '_Installation', input) rest.create(config, auth.nobody(config), '_Installation', input)
.then(() => { .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
return database.mongoFind('_Installation', {}, {}); .then(results => {
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
input = { input = {
'installationId': installId, 'installationId': installId,
@@ -831,13 +793,18 @@ describe('Installations', () => {
'deviceType': 'ios' 'deviceType': 'ios'
}; };
return rest.create(config, auth.nobody(config), '_Installation', input); return rest.create(config, auth.nobody(config), '_Installation', input);
}).then(() => { })
return database.mongoFind('_Installation', {}, {}); .then(() => database.adapter.find('_Installation', {}, installationSchema, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
expect(results[0].deviceToken).toEqual(t); expect(results[0].deviceToken).toEqual(t);
expect(results[0].installationId).toEqual(installId); expect(results[0].installationId).toEqual(installId);
done(); done();
})
.catch(error => {
console.log(error);
fail();
done();
}); });
}); });

View File

@@ -1,3 +1,4 @@
"use strict";
// These tests check the "create" / "update" functionality of the REST API. // These tests check the "create" / "update" functionality of the REST API.
var auth = require('../src/Auth'); var auth = require('../src/Auth');
var cache = require('../src/cache'); var cache = require('../src/cache');
@@ -11,65 +12,69 @@ var config = new Config('test');
var database = DatabaseAdapter.getDatabaseConnection('test', 'test_'); var database = DatabaseAdapter.getDatabaseConnection('test', 'test_');
describe('rest create', () => { describe('rest create', () => {
it('handles _id', (done) => { it('handles _id', done => {
rest.create(config, auth.nobody(config), 'Foo', {}).then(() => { rest.create(config, auth.nobody(config), 'Foo', {})
return database.mongoFind('Foo', {}); .then(() => database.adapter.find('Foo', {}, { fields: {} }, {}))
}).then((results) => { .then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var obj = results[0]; var obj = results[0];
expect(typeof obj._id).toEqual('string'); expect(typeof obj.objectId).toEqual('string');
expect(obj.objectId).toBeUndefined(); expect(obj._id).toBeUndefined();
done(); done();
}); });
}); });
it('handles array, object, date', (done) => { it('handles array, object, date', (done) => {
let now = new Date();
var obj = { var obj = {
array: [1, 2, 3], array: [1, 2, 3],
object: {foo: 'bar'}, object: {foo: 'bar'},
date: Parse._encode(new Date()), date: Parse._encode(now),
}; };
rest.create(config, auth.nobody(config), 'MyClass', obj).then(() => { rest.create(config, auth.nobody(config), 'MyClass', obj)
return database.mongoFind('MyClass', {}, {}); .then(() => database.adapter.find('MyClass', {}, { fields: {
}).then((results) => { array: { type: 'Array' },
object: { type: 'Object' },
date: { type: 'Date' },
} }, {}))
.then(results => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var mob = results[0]; var mob = results[0];
expect(mob.array instanceof Array).toBe(true); expect(mob.array instanceof Array).toBe(true);
expect(typeof mob.object).toBe('object'); expect(typeof mob.object).toBe('object');
expect(mob.date instanceof Date).toBe(true); expect(mob.date.__type).toBe('Date');
expect(new Date(mob.date.iso).getTime()).toBe(now.getTime());
done(); done();
}); });
}); });
it('handles object and subdocument', (done) => { it('handles object and subdocument', done => {
var obj = { let obj = { subdoc: {foo: 'bar', wu: 'tan'} };
subdoc: {foo: 'bar', wu: 'tan'}, rest.create(config, auth.nobody(config), 'MyClass', obj)
}; .then(() => database.adapter.find('MyClass', {}, { fields: {} }, {}))
rest.create(config, auth.nobody(config), 'MyClass', obj).then(() => { .then(results => {
return database.mongoFind('MyClass', {}, {});
}).then((results) => {
expect(results.length).toEqual(1); expect(results.length).toEqual(1);
var mob = results[0]; let mob = results[0];
expect(typeof mob.subdoc).toBe('object'); expect(typeof mob.subdoc).toBe('object');
expect(mob.subdoc.foo).toBe('bar'); expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('tan'); expect(mob.subdoc.wu).toBe('tan');
expect(typeof mob._id).toEqual('string'); expect(typeof mob.objectId).toEqual('string');
let obj = { 'subdoc.wu': 'clan' };
var obj = { return rest.update(config, auth.nobody(config), 'MyClass', mob.objectId, obj)
'subdoc.wu': 'clan', })
}; .then(() => database.adapter.find('MyClass', {}, { fields: {} }, {}))
.then(results => {
rest.update(config, auth.nobody(config), 'MyClass', mob._id, obj).then(() => { expect(results.length).toEqual(1);
return database.mongoFind('MyClass', {}, {}); let mob = results[0];
}).then((results) => { expect(typeof mob.subdoc).toBe('object');
expect(results.length).toEqual(1); expect(mob.subdoc.foo).toBe('bar');
var mob = results[0]; expect(mob.subdoc.wu).toBe('clan');
expect(typeof mob.subdoc).toBe('object'); done();
expect(mob.subdoc.foo).toBe('bar'); })
expect(mob.subdoc.wu).toBe('clan'); .catch(error => {
done(); console.log(error);
}); fail();
done();
}); });
}); });
@@ -240,8 +245,8 @@ describe('rest create', () => {
}); });
}); });
it('stores pointers with a _p_ prefix', (done) => { it('stores pointers', done => {
var obj = { let obj = {
foo: 'bar', foo: 'bar',
aPointer: { aPointer: {
__type: 'Pointer', __type: 'Pointer',
@@ -250,17 +255,23 @@ describe('rest create', () => {
} }
}; };
rest.create(config, auth.nobody(config), 'APointerDarkly', obj) rest.create(config, auth.nobody(config), 'APointerDarkly', obj)
.then((r) => { .then(() => database.adapter.find('APointerDarkly', {}, { fields: {
return database.mongoFind('APointerDarkly', {}); foo: { type: 'String' },
}).then((results) => { aPointer: { type: 'Pointer', targetClass: 'JustThePointer' },
expect(results.length).toEqual(1); }}, {}))
var output = results[0]; .then(results => {
expect(typeof output._id).toEqual('string'); expect(results.length).toEqual(1);
expect(typeof output._p_aPointer).toEqual('string'); let output = results[0];
expect(output._p_aPointer).toEqual('JustThePointer$qwerty'); expect(typeof output.foo).toEqual('string');
expect(output.aPointer).toBeUndefined(); expect(typeof output._p_aPointer).toEqual('undefined');
done(); expect(output._p_aPointer).toBeUndefined();
expect(output.aPointer).toEqual({
__type: 'Pointer',
className: 'JustThePointer',
objectId: 'qwerty'
}); });
done();
});
}); });
it("cannot set objectId", (done) => { it("cannot set objectId", (done) => {

View File

@@ -236,6 +236,11 @@ export class MongoStorageAdapter {
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema))); .then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
} }
// Used in tests
_rawFind(className, query) {
return this.adaptiveCollection(className).then(collection => collection.find(query));
}
// Executs a count. // Executs a count.
count(className, query, schema) { count(className, query, schema) {
return this.adaptiveCollection(className) return this.adaptiveCollection(className)

View File

@@ -305,15 +305,13 @@ DatabaseController.prototype.handleRelationUpdates = function(className, objectI
// Adds a relation. // Adds a relation.
// Returns a promise that resolves successfully iff the add was successful. // Returns a promise that resolves successfully iff the add was successful.
const relationSchema = { fields: { relatedId: { type: 'String' }, owningId: { type: 'String' } } };
DatabaseController.prototype.addRelation = function(key, fromClassName, fromId, toId) { DatabaseController.prototype.addRelation = function(key, fromClassName, fromId, toId) {
let doc = { let doc = {
relatedId: toId, relatedId: toId,
owningId : fromId owningId : fromId
}; };
let className = `_Join:${key}:${fromClassName}`; return this.adapter.upsertOneObject(`_Join:${key}:${fromClassName}`, doc, relationSchema, doc);
return this.adapter.adaptiveCollection(className).then((coll) => {
return coll.upsertOne(doc, doc);
});
}; };
// Removes a relation. // Removes a relation.
@@ -324,9 +322,13 @@ DatabaseController.prototype.removeRelation = function(key, fromClassName, fromI
relatedId: toId, relatedId: toId,
owningId: fromId owningId: fromId
}; };
let className = `_Join:${key}:${fromClassName}`; return this.adapter.deleteObjectsByQuery(`_Join:${key}:${fromClassName}`, doc, relationSchema)
return this.adapter.adaptiveCollection(className).then(coll => { .catch(error => {
return coll.deleteOne(doc); // We don't care if they try to delete a non-existent relation.
if (error.code == Parse.Error.OBJECT_NOT_FOUND) {
return;
}
throw error;
}); });
}; };
@@ -415,15 +417,6 @@ DatabaseController.prototype.canAddField = function(schema, className, object, a
return Promise.resolve(); return Promise.resolve();
} }
// Runs a mongo query on the database.
// This should only be used for testing - use 'find' for normal code
// to avoid Mongo-format dependencies.
// Returns a promise that resolves to a list of items.
DatabaseController.prototype.mongoFind = function(className, query, options = {}) {
return this.adapter.adaptiveCollection(className)
.then(collection => collection.find(query, options));
};
// Deletes everything in the database matching the current collectionPrefix // Deletes everything in the database matching the current collectionPrefix
// Won't delete collections in the system namespace // Won't delete collections in the system namespace
// Returns a promise. // Returns a promise.
@@ -449,17 +442,15 @@ function keysForQuery(query) {
// Returns a promise for a list of related ids given an owning id. // Returns a promise for a list of related ids given an owning id.
// className here is the owning className. // className here is the owning className.
DatabaseController.prototype.relatedIds = function(className, key, owningId) { DatabaseController.prototype.relatedIds = function(className, key, owningId) {
return this.adapter.adaptiveCollection(joinTableName(className, key)) return this.adapter.find(joinTableName(className, key), { owningId }, relationSchema, {})
.then(coll => coll.find({owningId : owningId})) .then(results => results.map(result => result.relatedId));
.then(results => results.map(r => r.relatedId));
}; };
// Returns a promise for a list of owning ids given some related ids. // Returns a promise for a list of owning ids given some related ids.
// className here is the owning className. // className here is the owning className.
DatabaseController.prototype.owningIds = function(className, key, relatedIds) { DatabaseController.prototype.owningIds = function(className, key, relatedIds) {
return this.adapter.adaptiveCollection(joinTableName(className, key)) return this.adapter.find(joinTableName(className, key), { relatedId: { '$in': relatedIds } }, relationSchema, {})
.then(coll => coll.find({ relatedId: { '$in': relatedIds } })) .then(results => results.map(result => result.owningId));
.then(results => results.map(r => r.owningId));
}; };
// Modifies query so that it no longer has $in on relation fields, or // Modifies query so that it no longer has $in on relation fields, or
@@ -702,8 +693,7 @@ DatabaseController.prototype.deleteSchema = function(className) {
if (!exist) { if (!exist) {
return Promise.resolve(); return Promise.resolve();
} }
return this.adapter.adaptiveCollection(className) return this.adapter.count(className)
.then(collection => collection.count())
.then(count => { .then(count => {
if (count > 0) { if (count > 0) {
throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`); throw new Parse.Error(255, `Class ${className} is not empty, contains ${count} objects, cannot drop schema.`);