Skip to content

Commit

Permalink
Postgres adapter (parse-community#2012)
Browse files Browse the repository at this point in the history
* Remove adaptiveCollection

* Remove an adaptiveCollection use

* Remove an adaptiveCollection

* make adaptiveCollection private

* Remove collection from mongoadapter

* Move schema collection usage into mongo adapter

* stop relying on mongo format for removing join tables

* reduce usage of schemaCollection

* remove uses of _collection

* Move CLP setting into mongo adapter

* remove all uses of schemaCollection

* make schemaCollection private

* remove transform from schemaCollection

* rename some stuff

* Tweak paramaters and stuff

* reorder some params

* reorder find() arguments

* finishsh touching up argument order

* Accept a database adapter as a parameter

* First passing test with postgres!

* Actually use the provided className

* index on unique-indexes: c454180 Revert "Log objects rather than JSON stringified objects (parse-community#1922)"

* Start dealing with test shittyness

* Make specific server config for tests async

* Fix email validation

* Fix broken cloud code

* Save callback to variable

* undo

* Fix tests

* Setup travis

* fix travis maybe

* try removing db user

* indentation?

* remove postgres version setting

* sudo maybe?

* use postgres username

* fix check for _PushStatus

* excludes

* remove db=mongo

* allow postgres to fail

* Fix allow failure

* postgres 9.4

* Remove mongo implementations and fix test

* Fix test leaving behind connections
  • Loading branch information
drew-gross authored Jun 12, 2016
1 parent d559cb2 commit 5518edc
Show file tree
Hide file tree
Showing 20 changed files with 499 additions and 318 deletions.
11 changes: 11 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ language: node_js
node_js:
- '4.3'
- '6.1'
services:
- postgresql
addons:
postgresql: '9.4'
before_script:
- psql -c 'create database parse_server_postgres_adapter_test_database;' -U postgres
env:
global:
- COVERAGE_OPTION='./node_modules/babel-istanbul/lib/cli.js cover -x **/spec/**'
matrix:
- PARSE_SERVER_TEST_DB=postgres
- MONGODB_VERSION=2.6.11
- MONGODB_VERSION=3.0.8
- MONGODB_VERSION=3.2.6
matrix:
fast_finish: true,
allow_failures:
- env: PARSE_SERVER_TEST_DB=postgres
branches:
only:
- master
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"parse-server-push-adapter": "^1.0.0",
"parse-server-s3-adapter": "^1.0.1",
"parse-server-simple-mailgun-adapter": "^1.0.0",
"pg-promise": "^4.4.0",
"redis": "^2.5.0-1",
"request": "^2.65.0",
"request-promise": "^3.0.0",
Expand Down
16 changes: 8 additions & 8 deletions spec/MongoStorageAdapter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const databaseURI = 'mongodb://localhost:27017/parseServerMongoAdapterTestDataba
describe('MongoStorageAdapter', () => {
beforeEach(done => {
new MongoStorageAdapter({ uri: databaseURI })
.deleteAllSchemas()
.deleteAllClasses()
.then(done, fail);
});

Expand Down Expand Up @@ -49,7 +49,7 @@ describe('MongoStorageAdapter', () => {

it('stores objectId in _id', done => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
adapter.createObject('Foo', { objectId: 'abcde' }, { fields: { objectId: 'String' } })
adapter.createObject('Foo', {}, { objectId: 'abcde' })
.then(() => adapter._rawFind('Foo', {}))
.then(results => {
expect(results.length).toEqual(1);
Expand All @@ -70,10 +70,10 @@ describe('MongoStorageAdapter', () => {
}
};
let adapter = new MongoStorageAdapter({ uri: databaseURI });
adapter.createObject('APointerDarkly', obj, { fields: {
adapter.createObject('APointerDarkly', { fields: {
objectId: { type: 'String' },
aPointer: { type: 'Pointer', targetClass: 'JustThePointer' },
}})
}}, obj)
.then(() => adapter._rawFind('APointerDarkly', {}))
.then(results => {
expect(results.length).toEqual(1);
Expand All @@ -90,7 +90,7 @@ describe('MongoStorageAdapter', () => {
let adapter = new MongoStorageAdapter({ uri: databaseURI });
let schema = { fields : { subdoc: { type: 'Object' } } };
let obj = { subdoc: {foo: 'bar', wu: 'tan'} };
adapter.createObject('MyClass', obj, schema)
adapter.createObject('MyClass', schema, obj)
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
expect(results.length).toEqual(1);
Expand All @@ -99,7 +99,7 @@ describe('MongoStorageAdapter', () => {
expect(mob.subdoc.foo).toBe('bar');
expect(mob.subdoc.wu).toBe('tan');
let obj = { 'subdoc.wu': 'clan' };
return adapter.findOneAndUpdate('MyClass', {}, schema, obj);
return adapter.findOneAndUpdate('MyClass', schema, {}, obj);
})
.then(() => adapter._rawFind('MyClass', {}))
.then(results => {
Expand Down Expand Up @@ -127,15 +127,15 @@ describe('MongoStorageAdapter', () => {
object: { type: 'Object' },
date: { type: 'Date' },
} };
adapter.createObject('MyClass', obj, schema)
adapter.createObject('MyClass', schema, obj)
.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, {});
return adapter.find('MyClass', schema, {}, {});
})
.then(results => {
expect(results.length).toEqual(1);
Expand Down
4 changes: 2 additions & 2 deletions spec/OAuth.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -284,9 +284,9 @@ describe('OAuth', function() {
"Expiration should be cleared");
// make sure the auth data is properly deleted
var config = new Config(Parse.applicationId);
config.database.adapter.find('_User', { objectId: model.id }, {
config.database.adapter.find('_User', {
fields: Object.assign({}, defaultColumns._Default, defaultColumns._Installation),
}, {})
}, { objectId: model.id }, {})
.then(res => {
expect(res.length).toBe(1);
expect(res[0]._auth_data_myoauth).toBeUndefined();
Expand Down
118 changes: 51 additions & 67 deletions spec/ParseAPI.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ describe('miscellaneous', function() {
expect(typeof obj.id).toBe('string');
expect(typeof obj.createdAt.toGMTString()).toBe('string');
done();
}, function(err) { console.log(err); });
}, error => {
fail(JSON.stringify(error));
done();
});
});

it('get a TestObject', function(done) {
Expand Down Expand Up @@ -122,81 +125,63 @@ describe('miscellaneous', function() {
});

it('ensure that if people already have duplicate users, they can still sign up new users', done => {
reconfigureServer({})
let config = new Config('test');
// Remove existing data to clear out unique index
.then(TestUtils.destroyAllDataPermanently)
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.createObject('_User', requiredUserFields, { objectId: 'x', username: 'u' }))
.then(() => config.database.adapter.createObject('_User', requiredUserFields, { objectId: 'y', username: 'u' }))
// Create a new server to try to recreate the unique indexes
.then(reconfigureServer)
.catch(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('zxcv');
// Sign up with new email still works
return user.signUp().catch(fail);
})
.then(() => {
let adapter = new MongoStorageAdapter({
uri: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase',
collectionPrefix: 'test_',
});
adapter.createObject('_User', { objectId: 'x', username: 'u' }, requiredUserFields)
.then(() => adapter.createObject('_User', { objectId: 'y', username: 'u' }, requiredUserFields))
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('zxcv');
return user.signUp();
})
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('u');
user.signUp()
.catch(error => {
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
}, () => {
fail('destroyAllDataPermanently failed')
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('u');
// sign up with duplicate username doens't
return user.signUp()
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.USERNAME_TAKEN);
done();
});
})
});

it('ensure that if people already have duplicate emails, they can still sign up new users', done => {
reconfigureServer({})
// Wipe out existing database with unique index so we can create a duplicate user
.then(TestUtils.destroyAllDataPermanently)
let config = new Config('test');
// Remove existing data to clear out unique index
TestUtils.destroyAllDataPermanently()
.then(() => config.database.adapter.createObject('_User', requiredUserFields, { objectId: 'x', email: '[email protected]' }))
.then(() => config.database.adapter.createObject('_User', requiredUserFields, { objectId: 'y', email: '[email protected]' }))
.then(reconfigureServer)
.catch(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('qqq');
user.setEmail('[email protected]');
return user.signUp().catch(fail);
})
.then(() => {
let adapter = new MongoStorageAdapter({
uri: 'mongodb://localhost:27017/parseServerMongoAdapterTestDatabase',
collectionPrefix: 'test_',
});
adapter.createObject('_User', { objectId: 'x', email: '[email protected]' }, requiredUserFields)
.then(() => adapter.createObject('_User', { objectId: 'y', email: '[email protected]' }, requiredUserFields))
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('qqq');
user.setEmail('[email protected]');
return user.signUp();
})
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('www');
user.setEmail('[email protected]');
user.signUp()
.catch(error => {
expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
done();
});
})
.catch(error => {
fail(JSON.stringify(error));
done();
});
let user = new Parse.User();
user.setPassword('asdf');
user.setUsername('www');
user.setEmail('[email protected]');
return user.signUp()
})
.catch(error => {
expect(error.code).toEqual(Parse.Error.EMAIL_TAKEN);
done();
});
});

it('ensure that if you try to sign up a user with a unique username and email, but duplicates in some other field that has a uniqueness constraint, you get a regular duplicate value error', done => {
let config = new Config('test');
config.database.adapter.ensureUniqueness('_User', ['randomField'], requiredUserFields)
config.database.adapter.ensureUniqueness('_User', requiredUserFields, ['randomField'])
.then(() => {
let user = new Parse.User();
user.setPassword('asdf');
Expand Down Expand Up @@ -228,8 +213,7 @@ describe('miscellaneous', function() {
expect(typeof user.id).toEqual('string');
expect(user.get('password')).toBeUndefined();
expect(user.getSessionToken()).not.toBeUndefined();
Parse.User.logOut();
done();
Parse.User.logOut().then(done);
}, error: function(error) {
fail(error);
}
Expand Down Expand Up @@ -366,7 +350,7 @@ describe('miscellaneous', function() {
return obj.save();
}).then(() => {
let config = new Config(appId);
return config.database.adapter.find('TestObject', {}, { fields: {} }, {});
return config.database.adapter.find('TestObject', { fields: {} }, {}, {});
}).then((results) => {
expect(results.length).toEqual(1);
expect(results[0]['foo']).toEqual('bar');
Expand Down
42 changes: 23 additions & 19 deletions spec/ParseGlobalConfig.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ let Config = require('../src/Config');
describe('a GlobalConfig', () => {
beforeEach(done => {
let config = new Config('test');
config.database.adapter.adaptiveCollection('_GlobalConfig')
.then(coll => coll.upsertOne({ '_id': 1 }, { $set: { params: { companies: ['US', 'DK'] } } }))
.then(() => { done(); });
config.database.adapter.upsertOneObject(
'_GlobalConfig',
{ fields: {} },
{ objectId: 1 },
{ params: { companies: ['US', 'DK'] } }
).then(done);
});

it('can be retrieved', (done) => {
Expand Down Expand Up @@ -90,22 +93,23 @@ describe('a GlobalConfig', () => {

it('failed getting config when it is missing', (done) => {
let config = new Config('test');
config.database.adapter.adaptiveCollection('_GlobalConfig')
.then(coll => coll.deleteOne({ '_id': 1 }))
.then(() => {
request.get({
url : 'http://localhost:8378/1/config',
json : true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key' : 'test'
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(200);
expect(body.params).toEqual({});
done();
});
config.database.adapter.deleteObjectsByQuery(
'_GlobalConfig',
{ fields: { params: { __type: 'String' } } },
{ objectId: 1 }
).then(() => {
request.get({
url : 'http://localhost:8378/1/config',
json : true,
headers: {
'X-Parse-Application-Id': 'test',
'X-Parse-Master-Key' : 'test'
}
}, (error, response, body) => {
expect(response.statusCode).toEqual(200);
expect(body.params).toEqual({});
done();
});
});
});

});
2 changes: 1 addition & 1 deletion spec/ParseHooks.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ Parse.Hooks = require("../src/cloud-code/Parse.Hooks");

var port = 12345;
var hookServerURL = "http://localhost:"+port;
let AppCache = require('../src/cache').AppCache;

var app = express();
app.use(bodyParser.json({ 'type': '*/*' }))
app.listen(12345);
let AppCache = require('../src/cache').AppCache;

describe('Hooks', () => {

Expand Down
Loading

0 comments on commit 5518edc

Please sign in to comment.