Skip to content

Commit 6143988

Browse files
authored
Support pointer in distinct query (#4471)
* Support pointer in distinct query * extract transform pointer string
1 parent 7d773a5 commit 6143988

File tree

4 files changed

+66
-16
lines changed

4 files changed

+66
-16
lines changed

spec/ParseQuery.Aggregate.spec.js

+17
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,23 @@ describe('Parse.Query Aggregate testing', () => {
392392
}).catch(done.fail);
393393
});
394394

395+
it('distinct pointer', (done) => {
396+
const pointer1 = new TestObject();
397+
const pointer2 = new TestObject();
398+
const obj1 = new TestObject({ pointer: pointer1 });
399+
const obj2 = new TestObject({ pointer: pointer2 });
400+
const obj3 = new TestObject({ pointer: pointer1 });
401+
Parse.Object.saveAll([pointer1, pointer2, obj1, obj2, obj3]).then(() => {
402+
const query = new Parse.Query(TestObject);
403+
return query.distinct('pointer');
404+
}).then((results) => {
405+
expect(results.length).toEqual(2);
406+
expect(results.some(result => result.objectId === pointer1.id)).toEqual(true);
407+
expect(results.some(result => result.objectId === pointer2.id)).toEqual(true);
408+
done();
409+
});
410+
});
411+
395412
it('distinct class does not exist return empty', (done) => {
396413
const options = Object.assign({}, masterKeyOptions, {
397414
body: { distinct: 'unknown' }

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
transformKey,
1111
transformWhere,
1212
transformUpdate,
13+
transformPointerString,
1314
} from './MongoTransform';
1415
import Parse from 'parse/node';
1516
import _ from 'lodash';
@@ -483,9 +484,19 @@ export class MongoStorageAdapter {
483484

484485
distinct(className, schema, query, fieldName) {
485486
schema = convertParseSchemaToMongoSchema(schema);
487+
const isPointerField = schema.fields[fieldName] && schema.fields[fieldName].type === 'Pointer';
488+
if (isPointerField) {
489+
fieldName = `_p_${fieldName}`
490+
}
486491
return this._adaptiveCollection(className)
487492
.then(collection => collection.distinct(fieldName, transformWhere(className, query, schema)))
488-
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
493+
.then(objects => objects.map(object => {
494+
if (isPointerField) {
495+
const field = fieldName.substring(3);
496+
return transformPointerString(schema, field, object);
497+
}
498+
return mongoObjectToParseObject(className, object, schema);
499+
}));
489500
}
490501

491502
aggregate(className, schema, pipeline, readPreference) {

src/Adapters/Storage/Mongo/MongoTransform.js

+14-9
Original file line numberDiff line numberDiff line change
@@ -1014,6 +1014,18 @@ const nestedMongoObjectToNestedParseObject = mongoObject => {
10141014
}
10151015
}
10161016

1017+
const transformPointerString = (schema, field, pointerString) => {
1018+
const objData = pointerString.split('$');
1019+
if (objData[0] !== schema.fields[field].targetClass) {
1020+
throw 'pointer to incorrect className';
1021+
}
1022+
return {
1023+
__type: 'Pointer',
1024+
className: objData[0],
1025+
objectId: objData[1]
1026+
};
1027+
}
1028+
10171029
// Converts from a mongo-format object to a REST-format object.
10181030
// Does not strip out anything based on a lack of authentication.
10191031
const mongoObjectToParseObject = (className, mongoObject, schema) => {
@@ -1126,15 +1138,7 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
11261138
if (mongoObject[key] === null) {
11271139
break;
11281140
}
1129-
var objData = mongoObject[key].split('$');
1130-
if (objData[0] !== schema.fields[newKey].targetClass) {
1131-
throw 'pointer to incorrect className';
1132-
}
1133-
restObject[newKey] = {
1134-
__type: 'Pointer',
1135-
className: objData[0],
1136-
objectId: objData[1]
1137-
};
1141+
restObject[newKey] = transformPointerString(schema, newKey, mongoObject[key]);
11381142
break;
11391143
} else if (key[0] == '_' && key != '__type') {
11401144
throw ('bad key in untransform: ' + key);
@@ -1345,4 +1349,5 @@ module.exports = {
13451349
mongoObjectToParseObject,
13461350
relativeTimeToDate,
13471351
transformConstraint,
1352+
transformPointerString,
13481353
};

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

+23-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import sql from './sql';
66
const PostgresRelationDoesNotExistError = '42P01';
77
const PostgresDuplicateRelationError = '42P07';
88
const PostgresDuplicateColumnError = '42701';
9+
const PostgresMissingColumnError = '42703';
910
const PostgresDuplicateObjectError = '42710';
1011
const PostgresUniqueIndexViolationError = '23505';
1112
const PostgresTransactionAbortedError = '25P02';
@@ -1438,21 +1439,37 @@ export class PostgresStorageAdapter {
14381439
const isArrayField = schema.fields
14391440
&& schema.fields[fieldName]
14401441
&& schema.fields[fieldName].type === 'Array';
1442+
const isPointerField = schema.fields
1443+
&& schema.fields[fieldName]
1444+
&& schema.fields[fieldName].type === 'Pointer';
14411445
const values = [field, column, className];
14421446
const where = buildWhereClause({ schema, query, index: 4 });
14431447
values.push(...where.values);
14441448

14451449
const wherePattern = where.pattern.length > 0 ? `WHERE ${where.pattern}` : '';
1446-
let qs = `SELECT DISTINCT ON ($1:raw) $2:raw FROM $3:name ${wherePattern}`;
1447-
if (isArrayField) {
1448-
qs = `SELECT distinct jsonb_array_elements($1:raw) as $2:raw FROM $3:name ${wherePattern}`;
1449-
}
1450+
const transformer = isArrayField ? 'jsonb_array_elements' : 'ON';
1451+
const qs = `SELECT DISTINCT ${transformer}($1:raw) $2:raw FROM $3:name ${wherePattern}`;
14501452
debug(qs, values);
14511453
return this._client.any(qs, values)
1452-
.catch(() => [])
1454+
.catch((error) => {
1455+
if (error.code === PostgresMissingColumnError) {
1456+
return [];
1457+
}
1458+
throw error;
1459+
})
14531460
.then((results) => {
14541461
if (fieldName.indexOf('.') === -1) {
1455-
return results.map(object => object[field]);
1462+
results = results.filter((object) => object[field] !== null);
1463+
return results.map(object => {
1464+
if (!isPointerField) {
1465+
return object[field];
1466+
}
1467+
return {
1468+
__type: 'Pointer',
1469+
className: schema.fields[fieldName].targetClass,
1470+
objectId: object[field]
1471+
};
1472+
});
14561473
}
14571474
const child = fieldName.split('.')[1];
14581475
return results.map(object => object[column][child]);

0 commit comments

Comments
 (0)