Skip to content

Commit cf64dd3

Browse files
acinaderflovilmart
authored andcommitted
Don't error when attempting to sort on an object field (#4806)
* add failing test to demonstrate that you can't sort on a field in an object. * Only validate the base of the field name. * fix test name * Only test sort for mongo. * pg order by nested object * level 2 test * Factor out operation to get a field's base name. Add comment. * tweak comment wording so it wont make my grammar teacher angry.
1 parent 923e2b8 commit cf64dd3

File tree

3 files changed

+101
-5
lines changed

3 files changed

+101
-5
lines changed

spec/ParseQuery.spec.js

+84
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,90 @@ describe('Parse.Query testing', () => {
15381538
});
15391539
});
15401540

1541+
it('can order on an object string field', function (done) {
1542+
const testSet = [
1543+
{ sortField: { value: "Z" } },
1544+
{ sortField: { value: "A" } },
1545+
{ sortField: { value: "M" } },
1546+
];
1547+
1548+
const objects = testSet.map(e => new Parse.Object('Test', e));
1549+
Parse.Object.saveAll(objects)
1550+
.then(() => new Parse.Query('Test').addDescending('sortField.value').first())
1551+
.then((result) => {
1552+
expect(result.get('sortField').value).toBe("Z");
1553+
return new Parse.Query('Test').addAscending('sortField.value').first()
1554+
})
1555+
.then((result) => {
1556+
expect(result.get('sortField').value).toBe("A");
1557+
done();
1558+
})
1559+
.catch(done.fail);
1560+
});
1561+
1562+
it('can order on an object string field (level 2)', function (done) {
1563+
const testSet = [
1564+
{ sortField: { value: { field: "Z" } } },
1565+
{ sortField: { value: { field: "A" } } },
1566+
{ sortField: { value: { field: "M" } } },
1567+
];
1568+
1569+
const objects = testSet.map(e => new Parse.Object('Test', e));
1570+
Parse.Object.saveAll(objects)
1571+
.then(() => new Parse.Query('Test').addDescending('sortField.value.field').first())
1572+
.then((result) => {
1573+
expect(result.get('sortField').value.field).toBe("Z");
1574+
return new Parse.Query('Test').addAscending('sortField.value.field').first()
1575+
})
1576+
.then((result) => {
1577+
expect(result.get('sortField').value.field).toBe("A");
1578+
done();
1579+
})
1580+
.catch(done.fail);
1581+
});
1582+
1583+
it('can order on an object number field', function (done) {
1584+
const testSet = [
1585+
{ sortField: { value: 10 } },
1586+
{ sortField: { value: 1 } },
1587+
{ sortField: { value: 5 } },
1588+
];
1589+
1590+
const objects = testSet.map(e => new Parse.Object('Test', e));
1591+
Parse.Object.saveAll(objects)
1592+
.then(() => new Parse.Query('Test').addDescending('sortField.value').first())
1593+
.then((result) => {
1594+
expect(result.get('sortField').value).toBe(10);
1595+
return new Parse.Query('Test').addAscending('sortField.value').first()
1596+
})
1597+
.then((result) => {
1598+
expect(result.get('sortField').value).toBe(1);
1599+
done();
1600+
})
1601+
.catch(done.fail);
1602+
});
1603+
1604+
it('can order on an object number field (level 2)', function (done) {
1605+
const testSet = [
1606+
{ sortField: { value: { field: 10 } } },
1607+
{ sortField: { value: { field: 1 } } },
1608+
{ sortField: { value: { field: 5 } } },
1609+
];
1610+
1611+
const objects = testSet.map(e => new Parse.Object('Test', e));
1612+
Parse.Object.saveAll(objects)
1613+
.then(() => new Parse.Query('Test').addDescending('sortField.value.field').first())
1614+
.then((result) => {
1615+
expect(result.get('sortField').value.field).toBe(10);
1616+
return new Parse.Query('Test').addAscending('sortField.value.field').first()
1617+
})
1618+
.then((result) => {
1619+
expect(result.get('sortField').value.field).toBe(1);
1620+
done();
1621+
})
1622+
.catch(done.fail);
1623+
});
1624+
15411625
it("order by ascending number then descending string", function(done) {
15421626
const strings = ["a", "b", "c", "d"];
15431627
const makeBoxedNumber = function(num, i) {

src/Adapters/Storage/Postgres/PostgresStorageAdapter.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1397,11 +1397,12 @@ export class PostgresStorageAdapter implements StorageAdapter {
13971397
if (sort) {
13981398
const sortCopy: any = sort;
13991399
const sorting = Object.keys(sort).map((key) => {
1400+
const transformKey = transformDotFieldToComponents(key).join('->');
14001401
// Using $idx pattern gives: non-integer constant in ORDER BY
14011402
if (sortCopy[key] === 1) {
1402-
return `"${key}" ASC`;
1403+
return `${transformKey} ASC`;
14031404
}
1404-
return `"${key}" DESC`;
1405+
return `${transformKey} DESC`;
14051406
}).join();
14061407
sortPattern = sort !== undefined && Object.keys(sort).length > 0 ? `ORDER BY ${sorting}` : '';
14071408
}

src/Controllers/DatabaseController.js

+14-3
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,16 @@ const untransformObjectACL = ({_rperm, _wperm, ...output}) => {
294294
return output;
295295
}
296296

297+
/**
298+
* When querying, the fieldName may be compound, extract the base fieldName
299+
* `temperature.celsius` becomes `temperature`
300+
* @param {string} fieldName that may be a compound field name
301+
* @returns {string} the basename of the field
302+
*/
303+
const getBaseFieldName = (fieldName: string): string => {
304+
return fieldName.split('.')[0]
305+
}
306+
297307
const relationSchema = { fields: { relatedId: { type: 'String' }, owningId: { type: 'String' } } };
298308

299309
class DatabaseController {
@@ -411,8 +421,8 @@ class DatabaseController {
411421
if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) {
412422
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name for update: ${fieldName}`);
413423
}
414-
fieldName = fieldName.split('.')[0];
415-
if (!SchemaController.fieldNameIsValid(fieldName) && !isSpecialUpdateKey(fieldName)) {
424+
const baseFieldName = getBaseFieldName(fieldName);
425+
if (!SchemaController.fieldNameIsValid(baseFieldName) && !isSpecialUpdateKey(baseFieldName)) {
416426
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name for update: ${fieldName}`);
417427
}
418428
});
@@ -900,7 +910,8 @@ class DatabaseController {
900910
if (fieldName.match(/^authData\.([a-zA-Z0-9_]+)\.id$/)) {
901911
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Cannot sort by ${fieldName}`);
902912
}
903-
if (!SchemaController.fieldNameIsValid(fieldName)) {
913+
const baseFieldName = getBaseFieldName(fieldName);
914+
if (!SchemaController.fieldNameIsValid(baseFieldName)) {
904915
throw new Parse.Error(Parse.Error.INVALID_KEY_NAME, `Invalid field name: ${fieldName}.`);
905916
}
906917
});

0 commit comments

Comments
 (0)