Support pointer in distinct query (#4471)
* Support pointer in distinct query * extract transform pointer string
This commit is contained in:
@@ -392,6 +392,23 @@ describe('Parse.Query Aggregate testing', () => {
|
||||
}).catch(done.fail);
|
||||
});
|
||||
|
||||
it('distinct pointer', (done) => {
|
||||
const pointer1 = new TestObject();
|
||||
const pointer2 = new TestObject();
|
||||
const obj1 = new TestObject({ pointer: pointer1 });
|
||||
const obj2 = new TestObject({ pointer: pointer2 });
|
||||
const obj3 = new TestObject({ pointer: pointer1 });
|
||||
Parse.Object.saveAll([pointer1, pointer2, obj1, obj2, obj3]).then(() => {
|
||||
const query = new Parse.Query(TestObject);
|
||||
return query.distinct('pointer');
|
||||
}).then((results) => {
|
||||
expect(results.length).toEqual(2);
|
||||
expect(results.some(result => result.objectId === pointer1.id)).toEqual(true);
|
||||
expect(results.some(result => result.objectId === pointer2.id)).toEqual(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('distinct class does not exist return empty', (done) => {
|
||||
const options = Object.assign({}, masterKeyOptions, {
|
||||
body: { distinct: 'unknown' }
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
transformKey,
|
||||
transformWhere,
|
||||
transformUpdate,
|
||||
transformPointerString,
|
||||
} from './MongoTransform';
|
||||
import Parse from 'parse/node';
|
||||
import _ from 'lodash';
|
||||
@@ -483,9 +484,19 @@ export class MongoStorageAdapter {
|
||||
|
||||
distinct(className, schema, query, fieldName) {
|
||||
schema = convertParseSchemaToMongoSchema(schema);
|
||||
const isPointerField = schema.fields[fieldName] && schema.fields[fieldName].type === 'Pointer';
|
||||
if (isPointerField) {
|
||||
fieldName = `_p_${fieldName}`
|
||||
}
|
||||
return this._adaptiveCollection(className)
|
||||
.then(collection => collection.distinct(fieldName, transformWhere(className, query, schema)))
|
||||
.then(objects => objects.map(object => mongoObjectToParseObject(className, object, schema)));
|
||||
.then(objects => objects.map(object => {
|
||||
if (isPointerField) {
|
||||
const field = fieldName.substring(3);
|
||||
return transformPointerString(schema, field, object);
|
||||
}
|
||||
return mongoObjectToParseObject(className, object, schema);
|
||||
}));
|
||||
}
|
||||
|
||||
aggregate(className, schema, pipeline, readPreference) {
|
||||
|
||||
@@ -1014,6 +1014,18 @@ const nestedMongoObjectToNestedParseObject = mongoObject => {
|
||||
}
|
||||
}
|
||||
|
||||
const transformPointerString = (schema, field, pointerString) => {
|
||||
const objData = pointerString.split('$');
|
||||
if (objData[0] !== schema.fields[field].targetClass) {
|
||||
throw 'pointer to incorrect className';
|
||||
}
|
||||
return {
|
||||
__type: 'Pointer',
|
||||
className: objData[0],
|
||||
objectId: objData[1]
|
||||
};
|
||||
}
|
||||
|
||||
// Converts from a mongo-format object to a REST-format object.
|
||||
// Does not strip out anything based on a lack of authentication.
|
||||
const mongoObjectToParseObject = (className, mongoObject, schema) => {
|
||||
@@ -1126,15 +1138,7 @@ const mongoObjectToParseObject = (className, mongoObject, schema) => {
|
||||
if (mongoObject[key] === null) {
|
||||
break;
|
||||
}
|
||||
var objData = mongoObject[key].split('$');
|
||||
if (objData[0] !== schema.fields[newKey].targetClass) {
|
||||
throw 'pointer to incorrect className';
|
||||
}
|
||||
restObject[newKey] = {
|
||||
__type: 'Pointer',
|
||||
className: objData[0],
|
||||
objectId: objData[1]
|
||||
};
|
||||
restObject[newKey] = transformPointerString(schema, newKey, mongoObject[key]);
|
||||
break;
|
||||
} else if (key[0] == '_' && key != '__type') {
|
||||
throw ('bad key in untransform: ' + key);
|
||||
@@ -1345,4 +1349,5 @@ module.exports = {
|
||||
mongoObjectToParseObject,
|
||||
relativeTimeToDate,
|
||||
transformConstraint,
|
||||
transformPointerString,
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import sql from './sql';
|
||||
const PostgresRelationDoesNotExistError = '42P01';
|
||||
const PostgresDuplicateRelationError = '42P07';
|
||||
const PostgresDuplicateColumnError = '42701';
|
||||
const PostgresMissingColumnError = '42703';
|
||||
const PostgresDuplicateObjectError = '42710';
|
||||
const PostgresUniqueIndexViolationError = '23505';
|
||||
const PostgresTransactionAbortedError = '25P02';
|
||||
@@ -1438,21 +1439,37 @@ export class PostgresStorageAdapter {
|
||||
const isArrayField = schema.fields
|
||||
&& schema.fields[fieldName]
|
||||
&& schema.fields[fieldName].type === 'Array';
|
||||
const isPointerField = schema.fields
|
||||
&& schema.fields[fieldName]
|
||||
&& schema.fields[fieldName].type === 'Pointer';
|
||||
const values = [field, column, className];
|
||||
const where = buildWhereClause({ schema, query, index: 4 });
|
||||
values.push(...where.values);
|
||||
|
||||
const wherePattern = where.pattern.length > 0 ? `WHERE ${where.pattern}` : '';
|
||||
let qs = `SELECT DISTINCT ON ($1:raw) $2:raw FROM $3:name ${wherePattern}`;
|
||||
if (isArrayField) {
|
||||
qs = `SELECT distinct jsonb_array_elements($1:raw) as $2:raw FROM $3:name ${wherePattern}`;
|
||||
}
|
||||
const transformer = isArrayField ? 'jsonb_array_elements' : 'ON';
|
||||
const qs = `SELECT DISTINCT ${transformer}($1:raw) $2:raw FROM $3:name ${wherePattern}`;
|
||||
debug(qs, values);
|
||||
return this._client.any(qs, values)
|
||||
.catch(() => [])
|
||||
.catch((error) => {
|
||||
if (error.code === PostgresMissingColumnError) {
|
||||
return [];
|
||||
}
|
||||
throw error;
|
||||
})
|
||||
.then((results) => {
|
||||
if (fieldName.indexOf('.') === -1) {
|
||||
return results.map(object => object[field]);
|
||||
results = results.filter((object) => object[field] !== null);
|
||||
return results.map(object => {
|
||||
if (!isPointerField) {
|
||||
return object[field];
|
||||
}
|
||||
return {
|
||||
__type: 'Pointer',
|
||||
className: schema.fields[fieldName].targetClass,
|
||||
objectId: object[field]
|
||||
};
|
||||
});
|
||||
}
|
||||
const child = fieldName.split('.')[1];
|
||||
return results.map(object => object[column][child]);
|
||||
|
||||
Reference in New Issue
Block a user