Skip to content

Commit d1f77a9

Browse files
authored
Merge pull request #2053 from drew-gross/postgres-3
Continue with postgres support
2 parents 35ed09a + 726c866 commit d1f77a9

18 files changed

+408
-192
lines changed

2.3.0.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,6 @@ coll.aggregate([
7777
{$match: {count: {"$gt": 1}}},
7878
{$project: {id: "$uniqueIds", username: "$_id", _id : 0} },
7979
{$unwind: "$id" },
80-
{$out: '_duplicates'} // Save the list of duplicates to a new, "_duplicates collection. Remove this line to just output the list.
80+
{$out: '_duplicates'} // Save the list of duplicates to a new, "_duplicates" collection. Remove this line to just output the list.
8181
], {allowDiskUse:true})
8282
```

spec/MongoStorageAdapter.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ describe('MongoStorageAdapter', () => {
4949

5050
it('stores objectId in _id', done => {
5151
let adapter = new MongoStorageAdapter({ uri: databaseURI });
52-
adapter.createObject('Foo', {}, { objectId: 'abcde' })
52+
adapter.createObject('Foo', { fields: {} }, { objectId: 'abcde' })
5353
.then(() => adapter._rawFind('Foo', {}))
5454
.then(results => {
5555
expect(results.length).toEqual(1);

spec/ParseAPI.spec.js

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ describe('miscellaneous', function() {
3737
expect(obj2.id).toEqual(obj.id);
3838
done();
3939
},
40-
error: fail
40+
error: error => {
41+
fail(JSON.stringify(error));
42+
done();
43+
}
4144
});
4245
});
4346
});
@@ -48,8 +51,8 @@ describe('miscellaneous', function() {
4851
expect(data.getSessionToken()).not.toBeUndefined();
4952
expect(data.get('password')).toBeUndefined();
5053
done();
51-
}, function(err) {
52-
fail(err);
54+
}, error => {
55+
fail(JSON.stringify(error));
5356
done();
5457
});
5558
});
@@ -86,9 +89,8 @@ describe('miscellaneous', function() {
8689
});
8790

8891
it('ensure that email is uniquely indexed', done => {
89-
let numCreated = 0;
9092
let numFailed = 0;
91-
93+
let numCreated = 0;
9294
let user1 = new Parse.User();
9395
user1.setPassword('asdf');
9496
user1.setUsername('u1');
@@ -215,8 +217,9 @@ describe('miscellaneous', function() {
215217
expect(user.get('password')).toBeUndefined();
216218
expect(user.getSessionToken()).not.toBeUndefined();
217219
Parse.User.logOut().then(done);
218-
}, error: function(error) {
219-
fail(error);
220+
}, error: error => {
221+
fail(JSON.stringify(error));
222+
done();
220223
}
221224
});
222225
}, fail);
@@ -232,15 +235,14 @@ describe('miscellaneous', function() {
232235
expect(user.get('foo')).toEqual(1);
233236
user.increment('foo');
234237
return user.save();
235-
}).then(() => {
236-
Parse.User.logOut();
237-
return Parse.User.logIn('test', 'moon-y');
238-
}).then((user) => {
238+
}).then(() => Parse.User.logOut())
239+
.then(() => Parse.User.logIn('test', 'moon-y'))
240+
.then((user) => {
239241
expect(user.get('foo')).toEqual(2);
240242
Parse.User.logOut()
241243
.then(done);
242244
}, (error) => {
243-
fail(error);
245+
fail(JSON.stringify(error));
244246
done();
245247
});
246248
});

spec/ParseInstallation.spec.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ describe('Installations', () => {
2424
'deviceType': device
2525
};
2626
rest.create(config, auth.nobody(config), '_Installation', input)
27-
.then(() => config.database.adapter.find('_Installation', installationSchema, {}, {}))
27+
.then(() => database.adapter.find('_Installation', installationSchema, {}, {}))
2828
.then(results => {
2929
expect(results.length).toEqual(1);
3030
var obj = results[0];
@@ -42,7 +42,7 @@ describe('Installations', () => {
4242
'deviceType': device
4343
};
4444
rest.create(config, auth.nobody(config), '_Installation', input)
45-
.then(() => config.database.adapter.find('_Installation', installationSchema, {}, {}))
45+
.then(() => database.adapter.find('_Installation', installationSchema, {}, {}))
4646
.then(results => {
4747
expect(results.length).toEqual(1);
4848
var obj = results[0];
@@ -60,7 +60,7 @@ describe('Installations', () => {
6060
'deviceType': device
6161
};
6262
rest.create(config, auth.nobody(config), '_Installation', input)
63-
.then(() => config.database.adapter.find('_Installation', installationSchema, {}, {}))
63+
.then(() => database.adapter.find('_Installation', installationSchema, {}, {}))
6464
.then(results => {
6565
expect(results.length).toEqual(1);
6666
var obj = results[0];

spec/ParseUser.spec.js

Lines changed: 39 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
var request = require('request');
1111
var passwordCrypto = require('../src/password');
1212
var Config = require('../src/Config');
13+
const rp = require('request-promise');
1314

1415
function verifyACL(user) {
1516
const ACL = user.getACL();
@@ -2131,7 +2132,7 @@ describe('Parse.User testing', () => {
21312132
let database = new Config(Parse.applicationId).database;
21322133
database.create('_User', {
21332134
username: 'user',
2134-
password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
2135+
_hashed_password: '$2a$10$8/wZJyEuiEaobBBqzTG.jeY.XSFJd0rzaN//ososvEI4yLqI.4aie',
21352136
_auth_data_facebook: null
21362137
}, {}).then(() => {
21372138
return new Promise((resolve, reject) => {
@@ -2258,42 +2259,43 @@ describe('Parse.User testing', () => {
22582259
});
22592260

22602261
it('should fail to become user with expired token', (done) => {
2261-
Parse.User.signUp("auser", "somepass", null, {
2262-
success: function(user) {
2263-
request.get({
2264-
url: 'http://localhost:8378/1/classes/_Session',
2265-
json: true,
2266-
headers: {
2267-
'X-Parse-Application-Id': 'test',
2268-
'X-Parse-Master-Key': 'test',
2269-
},
2270-
}, (error, response, body) => {
2271-
var id = body.results[0].objectId;
2272-
var expiresAt = new Date((new Date()).setYear(2015));
2273-
var token = body.results[0].sessionToken;
2274-
request.put({
2275-
url: "http://localhost:8378/1/classes/_Session/" + id,
2276-
json: true,
2277-
headers: {
2278-
'X-Parse-Application-Id': 'test',
2279-
'X-Parse-Master-Key': 'test',
2280-
},
2281-
body: {
2282-
expiresAt: { __type: "Date", iso: expiresAt.toISOString() },
2283-
},
2284-
}, (error, response, body) => {
2285-
Parse.User.become(token)
2286-
.then(() => { fail("Should not have succeded"); })
2287-
.fail((err) => {
2288-
expect(err.code).toEqual(209);
2289-
expect(err.message).toEqual("Session token is expired.");
2290-
Parse.User.logOut() // Logout to prevent polluting CLI with messages
2291-
.then(done());
2292-
});
2293-
});
2294-
});
2295-
}
2296-
});
2262+
let token;
2263+
Parse.User.signUp("auser", "somepass", null)
2264+
.then(user => rp({
2265+
method: 'GET',
2266+
url: 'http://localhost:8378/1/classes/_Session',
2267+
json: true,
2268+
headers: {
2269+
'X-Parse-Application-Id': 'test',
2270+
'X-Parse-Master-Key': 'test',
2271+
},
2272+
}))
2273+
.then(body => {
2274+
var id = body.results[0].objectId;
2275+
var expiresAt = new Date((new Date()).setYear(2015));
2276+
token = body.results[0].sessionToken;
2277+
return rp({
2278+
method: 'PUT',
2279+
url: "http://localhost:8378/1/classes/_Session/" + id,
2280+
json: true,
2281+
headers: {
2282+
'X-Parse-Application-Id': 'test',
2283+
'X-Parse-Master-Key': 'test',
2284+
},
2285+
body: {
2286+
expiresAt: { __type: "Date", iso: expiresAt.toISOString() },
2287+
},
2288+
})
2289+
})
2290+
.then(() => Parse.User.become(token))
2291+
.then(() => {
2292+
fail("Should not have succeded")
2293+
done();
2294+
}, error => {
2295+
expect(error.code).toEqual(209);
2296+
expect(error.message).toEqual("Session token is expired.");
2297+
done();
2298+
})
22972299
});
22982300

22992301
it('should not create extraneous session tokens', (done) => {

spec/PointerPermissions.spec.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ describe('Pointer Permissions', () => {
3636
expect(res.length).toBe(1);
3737
expect(res[0].id).toBe(obj.id);
3838
done();
39-
}).catch((err) => {
40-
fail('Should not fail');
39+
}).catch(error => {
40+
fail(JSON.stringify(error));
4141
done();
4242
});
4343
});

spec/Schema.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ describe('SchemaController', () => {
693693
objectId: { type: 'String' },
694694
updatedAt: { type: 'Date' },
695695
createdAt: { type: 'Date' },
696-
ACL: { type: 'ACL' }
696+
ACL: { type: 'ACL' },
697697
};
698698
expect(dd(schema.data.NewClass, expectedSchema)).toEqual(undefined);
699699
done();

spec/helper.js

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ var ParseServer = require('../src/index').ParseServer;
1111
var path = require('path');
1212
var TestUtils = require('../src/index').TestUtils;
1313
var MongoStorageAdapter = require('../src/Adapters/Storage/Mongo/MongoStorageAdapter');
14-
1514
const GridStoreAdapter = require('../src/Adapters/Files/GridStoreAdapter').GridStoreAdapter;
1615
const PostgresStorageAdapter = require('../src/Adapters/Storage/Postgres/PostgresStorageAdapter');
1716

@@ -30,7 +29,6 @@ if (process.env.PARSE_SERVER_TEST_DB === 'postgres') {
3029
})
3130
}
3231

33-
3432
var port = 8378;
3533

3634
let gridStoreAdapter = new GridStoreAdapter(mongoURI);
@@ -142,6 +140,12 @@ beforeEach(done => {
142140
});
143141

144142
afterEach(function(done) {
143+
let afterLogOut = () => {
144+
if (Object.keys(openConnections).length > 0) {
145+
fail('There were open connections to the server left after the test finished');
146+
}
147+
done();
148+
};
145149
Parse.Cloud._removeAllHooks();
146150
databaseAdapter.getAllClasses()
147151
.then(allSchemas => {
@@ -159,16 +163,7 @@ afterEach(function(done) {
159163
});
160164
})
161165
.then(() => Parse.User.logOut())
162-
.then(() => {
163-
if (Object.keys(openConnections).length > 0) {
164-
fail('There were open connections to the server left after the test finished');
165-
}
166-
done();
167-
})
168-
.catch(error => {
169-
fail(JSON.stringify(error));
170-
done();
171-
});
166+
.then(afterLogOut, afterLogOut)
172167
});
173168

174169
var TestObject = Parse.Object.extend({

src/Adapters/Storage/Mongo/MongoCollection.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export default class MongoCollection {
5252
// If there is nothing that matches the query - does insert
5353
// Postgres Note: `INSERT ... ON CONFLICT UPDATE` that is available since 9.5.
5454
upsertOne(query, update) {
55-
return this._mongoCollection.update(query, update, { upsert: true });
55+
return this._mongoCollection.update(query, update, { upsert: true })
5656
}
5757

5858
updateOne(query, update) {

src/Adapters/Storage/Mongo/MongoSchemaCollection.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import MongoCollection from './MongoCollection';
32

43
function mongoFieldToParseSchemaField(type) {

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ const storageAdapterAllCollections = mongoAdapter => {
3434
});
3535
}
3636

37+
const convertParseSchemaToMongoSchema = ({...schema}) => {
38+
delete schema.fields._rperm;
39+
delete schema.fields._wperm;
40+
41+
if (schema.className === '_User') {
42+
// Legacy mongo adapter knows about the difference between password and _hashed_password.
43+
// Future database adapters will only know about _hashed_password.
44+
// Note: Parse Server will bring back password with injectDefaultSchema, so we don't need
45+
// to add _hashed_password back ever.
46+
delete schema.fields._hashed_password;
47+
}
48+
49+
return schema;
50+
}
51+
3752
export class MongoStorageAdapter {
3853
// Private
3954
_uri: string;
@@ -97,6 +112,7 @@ export class MongoStorageAdapter {
97112
}
98113

99114
createClass(className, schema) {
115+
schema = convertParseSchemaToMongoSchema(schema);
100116
return this._schemaCollection()
101117
.then(schemaCollection => schemaCollection.addSchema(className, schema.fields, schema.classLevelPermissions));
102118
}
@@ -185,13 +201,14 @@ export class MongoStorageAdapter {
185201
// undefined as the reason.
186202
getClass(className) {
187203
return this._schemaCollection()
188-
.then(schemasCollection => schemasCollection._fechOneSchemaFrom_SCHEMA(className));
204+
.then(schemasCollection => schemasCollection._fechOneSchemaFrom_SCHEMA(className))
189205
}
190206

191207
// TODO: As yet not particularly well specified. Creates an object. Maybe shouldn't even need the schema,
192208
// and should infer from the type. Or maybe does need the schema for validations. Or maybe needs
193209
// the schem only for the legacy mongo format. We'll figure that out later.
194210
createObject(className, schema, object) {
211+
schema = convertParseSchemaToMongoSchema(schema);
195212
const mongoObject = parseObjectToMongoObjectForCreate(className, object, schema);
196213
return this._adaptiveCollection(className)
197214
.then(collection => collection.insertOne(mongoObject))
@@ -208,6 +225,7 @@ export class MongoStorageAdapter {
208225
// If no objects match, reject with OBJECT_NOT_FOUND. If objects are found and deleted, resolve with undefined.
209226
// If there is some other error, reject with INTERNAL_SERVER_ERROR.
210227
deleteObjectsByQuery(className, schema, query) {
228+
schema = convertParseSchemaToMongoSchema(schema);
211229
return this._adaptiveCollection(className)
212230
.then(collection => {
213231
let mongoWhere = transformWhere(className, query, schema);
@@ -225,15 +243,17 @@ export class MongoStorageAdapter {
225243

226244
// Apply the update to all objects that match the given Parse Query.
227245
updateObjectsByQuery(className, schema, query, update) {
246+
schema = convertParseSchemaToMongoSchema(schema);
228247
const mongoUpdate = transformUpdate(className, update, schema);
229248
const mongoWhere = transformWhere(className, query, schema);
230249
return this._adaptiveCollection(className)
231250
.then(collection => collection.updateMany(mongoWhere, mongoUpdate));
232251
}
233252

234253
// Atomically finds and updates an object based on query.
235-
// Resolve with the updated object.
254+
// Return value not currently well specified.
236255
findOneAndUpdate(className, schema, query, update) {
256+
schema = convertParseSchemaToMongoSchema(schema);
237257
const mongoUpdate = transformUpdate(className, update, schema);
238258
const mongoWhere = transformWhere(className, query, schema);
239259
return this._adaptiveCollection(className)
@@ -243,6 +263,7 @@ export class MongoStorageAdapter {
243263

244264
// Hopefully we can get rid of this. It's only used for config and hooks.
245265
upsertOneObject(className, schema, query, update) {
266+
schema = convertParseSchemaToMongoSchema(schema);
246267
const mongoUpdate = transformUpdate(className, update, schema);
247268
const mongoWhere = transformWhere(className, query, schema);
248269
return this._adaptiveCollection(className)
@@ -251,11 +272,12 @@ export class MongoStorageAdapter {
251272

252273
// Executes a find. Accepts: className, query in Parse format, and { skip, limit, sort }.
253274
find(className, schema, query, { skip, limit, sort }) {
275+
schema = convertParseSchemaToMongoSchema(schema);
254276
let mongoWhere = transformWhere(className, query, schema);
255277
let mongoSort = _.mapKeys(sort, (value, fieldName) => transformKey(className, fieldName, schema));
256278
return this._adaptiveCollection(className)
257279
.then(collection => collection.find(mongoWhere, { skip, limit, sort: mongoSort }))
258-
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
280+
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)))
259281
}
260282

261283
// Create a unique index. Unique indexes on nullable fields are not allowed. Since we don't
@@ -264,6 +286,7 @@ export class MongoStorageAdapter {
264286
// Way of determining if a field is nullable. Undefined doesn't count against uniqueness,
265287
// which is why we use sparse indexes.
266288
ensureUniqueness(className, schema, fieldNames) {
289+
schema = convertParseSchemaToMongoSchema(schema);
267290
let indexCreationRequest = {};
268291
let mongoFieldNames = fieldNames.map(fieldName => transformKey(className, fieldName, schema));
269292
mongoFieldNames.forEach(fieldName => {
@@ -287,6 +310,7 @@ export class MongoStorageAdapter {
287310

288311
// Executs a count.
289312
count(className, schema, query) {
313+
schema = convertParseSchemaToMongoSchema(schema);
290314
return this._adaptiveCollection(className)
291315
.then(collection => collection.count(transformWhere(className, query, schema)));
292316
}

0 commit comments

Comments
 (0)