Skip to content

Commit a4a7006

Browse files
author
Arthur Cinader
authored
Merge branch 'master' into greenkeeper/parse-server-s3-adapter-1.2.0
2 parents 6dd27df + c4d921e commit a4a7006

File tree

4 files changed

+113
-28
lines changed

4 files changed

+113
-28
lines changed

package.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@
2727
"lodash": "4.17.4",
2828
"lru-cache": "4.1.1",
2929
"mime": "1.3.6",
30-
"mongodb": "2.2.30",
30+
"mongodb": "2.2.31",
3131
"multer": "1.3.0",
3232
"parse": "1.10.0",
3333
"parse-server-fs-adapter": "1.0.1",
3434
"parse-server-push-adapter": "2.0.0",
3535
"parse-server-s3-adapter": "1.2.0",
3636
"parse-server-simple-mailgun-adapter": "1.0.0",
3737
"pg-promise": "6.3.1",
38-
"redis": "2.7.1",
38+
"redis": "2.8.0",
3939
"request": "2.81.0",
4040
"semver": "5.3.0",
4141
"tv4": "1.3.0",
@@ -45,20 +45,20 @@
4545
},
4646
"devDependencies": {
4747
"babel-cli": "6.24.1",
48-
"babel-core": "6.25.0",
48+
"babel-core": "6.26.0",
4949
"babel-eslint": "^7.1.1",
5050
"babel-plugin-syntax-flow": "6.18.0",
5151
"babel-plugin-transform-flow-strip-types": "6.22.0",
5252
"babel-preset-es2015": "6.24.1",
5353
"babel-preset-stage-0": "6.24.1",
54-
"babel-register": "6.24.1",
54+
"babel-register": "6.26.0",
5555
"bcrypt-nodejs": "0.0.3",
5656
"cross-env": "5.0.2",
5757
"deep-diff": "0.3.8",
5858
"eslint": "^4.4.1",
5959
"eslint-plugin-flowtype": "^2.25.0",
6060
"gaze": "1.1.2",
61-
"jasmine": "2.7.0",
61+
"jasmine": "2.8.0",
6262
"jasmine-spec-reporter": "^4.1.0",
6363
"mongodb-runner": "3.5.0",
6464
"nodemon": "1.11.0",
@@ -84,7 +84,7 @@
8484
"parse-server": "./bin/parse-server"
8585
},
8686
"optionalDependencies": {
87-
"bcrypt": "1.0.2",
87+
"bcrypt": "1.0.3",
8888
"uws": "^0.14.5"
8989
}
9090
}

spec/ParseQuery.spec.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,40 @@ describe('Parse.Query testing', () => {
289289
}, done.fail);
290290
});
291291

292+
it('nested containedIn string', (done) => {
293+
const sender1 = { group: ['A', 'B'] };
294+
const sender2 = { group: ['A', 'C'] };
295+
const sender3 = { group: ['B', 'C'] };
296+
const obj1 = new TestObject({ sender: sender1 });
297+
const obj2 = new TestObject({ sender: sender2 });
298+
const obj3 = new TestObject({ sender: sender3 });
299+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
300+
const query = new Parse.Query(TestObject);
301+
query.containedIn('sender.group', ['A']);
302+
return query.find();
303+
}).then((results) => {
304+
equal(results.length, 2);
305+
done();
306+
}, done.fail);
307+
});
308+
309+
it('nested containedIn number', (done) => {
310+
const sender1 = { group: [1, 2] };
311+
const sender2 = { group: [1, 3] };
312+
const sender3 = { group: [2, 3] };
313+
const obj1 = new TestObject({ sender: sender1 });
314+
const obj2 = new TestObject({ sender: sender2 });
315+
const obj3 = new TestObject({ sender: sender3 });
316+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
317+
const query = new Parse.Query(TestObject);
318+
query.containedIn('sender.group', [1]);
319+
return query.find();
320+
}).then((results) => {
321+
equal(results.length, 2);
322+
done();
323+
}, done.fail);
324+
});
325+
292326
it("containsAll number array queries", function(done) {
293327
var NumberSet = Parse.Object.extend({ className: "NumberSet" });
294328

@@ -1379,6 +1413,23 @@ describe('Parse.Query testing', () => {
13791413
});
13801414
});
13811415

1416+
it('nested contains', (done) => {
1417+
const sender1 = { group: ['A', 'B'] };
1418+
const sender2 = { group: ['A', 'C'] };
1419+
const sender3 = { group: ['B', 'C'] };
1420+
const obj1 = new TestObject({ sender: sender1 });
1421+
const obj2 = new TestObject({ sender: sender2 });
1422+
const obj3 = new TestObject({ sender: sender3 });
1423+
Parse.Object.saveAll([obj1, obj2, obj3]).then(() => {
1424+
const query = new Parse.Query(TestObject);
1425+
query.contains('sender.group', 'A');
1426+
return query.find();
1427+
}).then((results) => {
1428+
equal(results.length, 2);
1429+
done();
1430+
}, done.fail);
1431+
});
1432+
13821433
it("startsWith", function(done) {
13831434
Parse.Object.saveAll([new TestObject({myString: "zax" + someAscii + "qub"}),
13841435
new TestObject({myString: "start" + someAscii}),

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,25 @@ const handleDotFields = (object) => {
146146
return object;
147147
}
148148

149+
const transformDotFieldToComponents = (fieldName) => {
150+
return fieldName.split('.').map((cmpt, index) => {
151+
if (index === 0) {
152+
return `"${cmpt}"`;
153+
}
154+
return `'${cmpt}'`;
155+
});
156+
}
157+
158+
const transformDotField = (fieldName) => {
159+
if (fieldName.indexOf('.') === -1) {
160+
return `"${fieldName}"`;
161+
}
162+
const components = transformDotFieldToComponents(fieldName);
163+
let name = components.slice(0, components.length - 1).join('->');
164+
name += '->>' + components[components.length - 1];
165+
return name;
166+
}
167+
149168
const validateKeys = (object) => {
150169
if (typeof object == 'object') {
151170
for (const key in object) {
@@ -195,18 +214,26 @@ const buildWhereClause = ({ schema, query, index }) => {
195214
}
196215

197216
if (fieldName.indexOf('.') >= 0) {
198-
const components = fieldName.split('.').map((cmpt, index) => {
199-
if (index === 0) {
200-
return `"${cmpt}"`;
201-
}
202-
return `'${cmpt}'`;
203-
});
204-
let name = components.slice(0, components.length - 1).join('->');
205-
name += '->>' + components[components.length - 1];
217+
let name = transformDotField(fieldName);
206218
if (fieldValue === null) {
207219
patterns.push(`${name} IS NULL`);
208220
} else {
209-
patterns.push(`${name} = '${fieldValue}'`);
221+
if (fieldValue.$in) {
222+
const inPatterns = [];
223+
name = transformDotFieldToComponents(fieldName).join('->');
224+
fieldValue.$in.forEach((listElem) => {
225+
if (typeof listElem === 'string') {
226+
inPatterns.push(`"${listElem}"`);
227+
} else {
228+
inPatterns.push(`${listElem}`);
229+
}
230+
});
231+
patterns.push(`(${name})::jsonb @> '[${inPatterns.join(',')}]'::jsonb`);
232+
} else if (fieldValue.$regex) {
233+
// Handle later
234+
} else {
235+
patterns.push(`${name} = '${fieldValue}'`);
236+
}
210237
}
211238
} else if (fieldValue === null) {
212239
patterns.push(`$${index}:name IS NULL`);
@@ -298,6 +325,10 @@ const buildWhereClause = ({ schema, query, index }) => {
298325
values.push(fieldName, JSON.stringify(baseArray));
299326
index += 2;
300327
} else {
328+
// Handle Nested Dot Notation Above
329+
if (fieldName.indexOf('.') >= 0) {
330+
return;
331+
}
301332
const inPatterns = [];
302333
values.push(fieldName);
303334
baseArray.forEach((listElem, listIndex) => {
@@ -466,10 +497,11 @@ const buildWhereClause = ({ schema, query, index }) => {
466497
}
467498
}
468499

500+
const name = transformDotField(fieldName);
469501
regex = processRegexPattern(regex);
470502

471-
patterns.push(`$${index}:name ${operator} '$${index + 1}:raw'`);
472-
values.push(fieldName, regex);
503+
patterns.push(`$${index}:raw ${operator} '$${index + 1}:raw'`);
504+
values.push(name, regex);
473505
index += 2;
474506
}
475507

@@ -636,10 +668,12 @@ export class PostgresStorageAdapter {
636668
throw error;
637669
}
638670
}).then(() => {
639-
// Create the relation tables
640-
return Promise.all(relations.map((fieldName) => {
641-
return conn.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`});
642-
}));
671+
return conn.tx('create-relation-tables', t => {
672+
const queries = relations.map((fieldName) => {
673+
return t.none('CREATE TABLE IF NOT EXISTS $<joinTable:name> ("relatedId" varChar(120), "owningId" varChar(120), PRIMARY KEY("relatedId", "owningId") )', {joinTable: `_Join:${fieldName}:${className}`});
674+
});
675+
return t.batch(queries);
676+
});
643677
});
644678
}
645679

src/Controllers/DatabaseController.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ DatabaseController.prototype.update = function(className, query, update, {
259259
validateQuery(query);
260260
return schemaController.getOneSchema(className, true)
261261
.catch(error => {
262-
// If the schema doesn't exist, pretend it exists with no fields. This behaviour
262+
// If the schema doesn't exist, pretend it exists with no fields. This behavior
263263
// will likely need revisiting.
264264
if (error === undefined) {
265265
return { fields: {} };
@@ -449,7 +449,7 @@ DatabaseController.prototype.destroy = function(className, query, { acl } = {})
449449
validateQuery(query);
450450
return schemaController.getOneSchema(className)
451451
.catch(error => {
452-
// If the schema doesn't exist, pretend it exists with no fields. This behaviour
452+
// If the schema doesn't exist, pretend it exists with no fields. This behavior
453453
// will likely need revisiting.
454454
if (error === undefined) {
455455
return { fields: {} };
@@ -650,7 +650,7 @@ DatabaseController.prototype.reduceInRelation = function(className, query, schem
650650

651651
// remove the current queryKey as we don,t need it anymore
652652
delete query[key];
653-
// execute each query independnently to build the list of
653+
// execute each query independently to build the list of
654654
// $in / $nin
655655
const promises = queries.map((q) => {
656656
if (!q) {
@@ -783,11 +783,11 @@ DatabaseController.prototype.find = function(className, query, {
783783
return this.loadSchema()
784784
.then(schemaController => {
785785
//Allow volatile classes if querying with Master (for _PushStatus)
786-
//TODO: Move volatile classes concept into mongo adatper, postgres adapter shouldn't care
786+
//TODO: Move volatile classes concept into mongo adapter, postgres adapter shouldn't care
787787
//that api.parse.com breaks when _PushStatus exists in mongo.
788788
return schemaController.getOneSchema(className, isMaster)
789789
.catch(error => {
790-
// Behaviour for non-existent classes is kinda weird on Parse.com. Probably doesn't matter too much.
790+
// Behavior for non-existent classes is kinda weird on Parse.com. Probably doesn't matter too much.
791791
// For now, pretend the class exists but has no objects,
792792
if (error === undefined) {
793793
classExists = false;
@@ -797,7 +797,7 @@ DatabaseController.prototype.find = function(className, query, {
797797
})
798798
.then(schema => {
799799
// Parse.com treats queries on _created_at and _updated_at as if they were queries on createdAt and updatedAt,
800-
// so duplicate that behaviour here. If both are specified, the corrent behaviour to match Parse.com is to
800+
// so duplicate that behavior here. If both are specified, the correct behavior to match Parse.com is to
801801
// use the one that appears first in the sort list.
802802
if (sort._created_at) {
803803
sort.createdAt = sort._created_at;
@@ -925,7 +925,7 @@ DatabaseController.prototype.addPointerPermissions = function(schema, className,
925925
// the ACL should have exactly 1 user
926926
if (perms && perms[field] && perms[field].length > 0) {
927927
// No user set return undefined
928-
// If the length is > 1, that means we didn't dedup users correctly
928+
// If the length is > 1, that means we didn't de-dupe users correctly
929929
if (userACL.length != 1) {
930930
return;
931931
}

0 commit comments

Comments
 (0)