Files
kami-parse-server/spec/ParseQuery.Aggregate.spec.js
Florent Vilmart d83a0b6808 Use Prettier JS (#5017)
* Adds prettier

* Run lint before tests
2018-09-01 13:58:06 -04:00

1222 lines
36 KiB
JavaScript

'use strict';
const Parse = require('parse/node');
const rp = require('request-promise');
const masterKeyHeaders = {
'X-Parse-Application-Id': 'test',
'X-Parse-Rest-API-Key': 'test',
'X-Parse-Master-Key': 'test',
};
const masterKeyOptions = {
headers: masterKeyHeaders,
json: true,
};
const PointerObject = Parse.Object.extend({
className: 'PointerObject',
});
const loadTestData = () => {
const data1 = {
score: 10,
name: 'foo',
sender: { group: 'A' },
views: 900,
size: ['S', 'M'],
};
const data2 = {
score: 10,
name: 'foo',
sender: { group: 'A' },
views: 800,
size: ['M', 'L'],
};
const data3 = {
score: 10,
name: 'bar',
sender: { group: 'B' },
views: 700,
size: ['S'],
};
const data4 = {
score: 20,
name: 'dpl',
sender: { group: 'B' },
views: 700,
size: ['S'],
};
const obj1 = new TestObject(data1);
const obj2 = new TestObject(data2);
const obj3 = new TestObject(data3);
const obj4 = new TestObject(data4);
return Parse.Object.saveAll([obj1, obj2, obj3, obj4]);
};
describe('Parse.Query Aggregate testing', () => {
beforeEach(done => {
loadTestData().then(done, done);
});
it('should only query aggregate with master key', done => {
Parse._request('GET', `aggregate/someClass`, {}).then(
() => {},
error => {
expect(error.message).toEqual('unauthorized: master key is required');
done();
}
);
});
it('invalid query invalid key', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
unknown: {},
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
expect(error.error.code).toEqual(Parse.Error.INVALID_QUERY);
done();
});
});
it('invalid query group _id', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { _id: null },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
expect(error.error.code).toEqual(Parse.Error.INVALID_QUERY);
done();
});
});
it('invalid query group objectId required', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: {},
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options).catch(error => {
expect(error.error.code).toEqual(Parse.Error.INVALID_QUERY);
done();
});
});
it('group by field', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: '$name' },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(3);
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[1].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[2].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).not.toBe(undefined);
expect(resp.results[1].objectId).not.toBe(undefined);
expect(resp.results[2].objectId).not.toBe(undefined);
done();
})
.catch(done.fail);
});
it('group by pipeline operator', async () => {
const options = Object.assign({}, masterKeyOptions, {
body: {
pipeline: {
group: { objectId: '$name' },
},
},
});
const resp = await rp.get(
Parse.serverURL + '/aggregate/TestObject',
options
);
expect(resp.results.length).toBe(3);
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[1].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[2].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).not.toBe(undefined);
expect(resp.results[1].objectId).not.toBe(undefined);
expect(resp.results[2].objectId).not.toBe(undefined);
});
it('group by empty object', done => {
const obj = new TestObject();
const pipeline = [
{
group: { objectId: {} },
},
];
obj
.save()
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results[0].objectId).toEqual(null);
done();
});
});
it('group by empty string', done => {
const obj = new TestObject();
const pipeline = [
{
group: { objectId: '' },
},
];
obj
.save()
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results[0].objectId).toEqual(null);
done();
});
});
it('group by empty array', done => {
const obj = new TestObject();
const pipeline = [
{
group: { objectId: [] },
},
];
obj
.save()
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results[0].objectId).toEqual(null);
done();
});
});
it('group by date object', done => {
const obj1 = new TestObject();
const obj2 = new TestObject();
const obj3 = new TestObject();
const pipeline = [
{
group: {
objectId: {
day: { $dayOfMonth: '$_updated_at' },
month: { $month: '$_created_at' },
year: { $year: '$_created_at' },
},
count: { $sum: 1 },
},
},
];
Parse.Object.saveAll([obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
const createdAt = new Date(obj1.createdAt);
expect(results[0].objectId.day).toEqual(createdAt.getUTCDate());
expect(results[0].objectId.month).toEqual(createdAt.getMonth() + 1);
expect(results[0].objectId.year).toEqual(createdAt.getUTCFullYear());
done();
});
});
it('group by date object transform', done => {
const obj1 = new TestObject();
const obj2 = new TestObject();
const obj3 = new TestObject();
const pipeline = [
{
group: {
objectId: {
day: { $dayOfMonth: '$updatedAt' },
month: { $month: '$createdAt' },
year: { $year: '$createdAt' },
},
count: { $sum: 1 },
},
},
];
Parse.Object.saveAll([obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
const createdAt = new Date(obj1.createdAt);
expect(results[0].objectId.day).toEqual(createdAt.getUTCDate());
expect(results[0].objectId.month).toEqual(createdAt.getMonth() + 1);
expect(results[0].objectId.year).toEqual(createdAt.getUTCFullYear());
done();
});
});
it_exclude_dbs(['postgres'])('group and multiply transform', done => {
const obj1 = new TestObject({ name: 'item a', quantity: 2, price: 10 });
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
const pipeline = [
{
group: {
objectId: null,
total: { $sum: { $multiply: ['$quantity', '$price'] } },
},
},
];
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(1);
expect(results[0].total).toEqual(45);
done();
});
});
it_exclude_dbs(['postgres'])('project and multiply transform', done => {
const obj1 = new TestObject({ name: 'item a', quantity: 2, price: 10 });
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
const pipeline = [
{
match: { quantity: { $exists: true } },
},
{
project: {
name: 1,
total: { $multiply: ['$quantity', '$price'] },
},
},
];
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(2);
if (results[0].name === 'item a') {
expect(results[0].total).toEqual(20);
expect(results[1].total).toEqual(25);
} else {
expect(results[0].total).toEqual(25);
expect(results[1].total).toEqual(20);
}
done();
});
});
it_exclude_dbs(['postgres'])('project without objectId transform', done => {
const obj1 = new TestObject({ name: 'item a', quantity: 2, price: 10 });
const obj2 = new TestObject({ name: 'item b', quantity: 5, price: 5 });
const pipeline = [
{
match: { quantity: { $exists: true } },
},
{
project: {
objectId: 0,
total: { $multiply: ['$quantity', '$price'] },
},
},
{
sort: { total: 1 },
},
];
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(2);
expect(results[0].total).toEqual(20);
expect(results[0].objectId).toEqual(undefined);
expect(results[1].total).toEqual(25);
expect(results[1].objectId).toEqual(undefined);
done();
});
});
it_exclude_dbs(['postgres'])('project updatedAt only transform', done => {
const pipeline = [
{
project: { objectId: 0, updatedAt: 1 },
},
];
const query = new Parse.Query(TestObject);
query.aggregate(pipeline).then(results => {
expect(results.length).toEqual(4);
for (let i = 0; i < results.length; i++) {
const item = results[i];
expect(item.hasOwnProperty('updatedAt')).toEqual(true);
expect(item.hasOwnProperty('objectId')).toEqual(false);
}
done();
});
});
it_exclude_dbs(['postgres'])(
'cannot group by date field (excluding createdAt and updatedAt)',
done => {
const obj1 = new TestObject({ dateField: new Date(1990, 11, 1) });
const obj2 = new TestObject({ dateField: new Date(1990, 5, 1) });
const obj3 = new TestObject({ dateField: new Date(1990, 11, 1) });
const pipeline = [
{
group: {
objectId: {
day: { $dayOfMonth: '$dateField' },
month: { $month: '$dateField' },
year: { $year: '$dateField' },
},
count: { $sum: 1 },
},
},
];
Parse.Object.saveAll([obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(done.fail)
.catch(error => {
expect(error.code).toEqual(Parse.Error.INVALID_QUERY);
done();
});
}
);
it('group by 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 });
const pipeline = [{ group: { objectId: '$pointer' } }];
Parse.Object.saveAll([pointer1, pointer2, obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(3);
expect(results.some(result => result.objectId === pointer1.id)).toEqual(
true
);
expect(results.some(result => result.objectId === pointer2.id)).toEqual(
true
);
expect(results.some(result => result.objectId === null)).toEqual(true);
done();
});
});
it('group sum query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, total: { $sum: '$score' } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).toBe(null);
expect(resp.results[0].total).toBe(50);
done();
})
.catch(done.fail);
});
it('group count query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, total: { $sum: 1 } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).toBe(null);
expect(resp.results[0].total).toBe(4);
done();
})
.catch(done.fail);
});
it('group min query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, minScore: { $min: '$score' } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).toBe(null);
expect(resp.results[0].minScore).toBe(10);
done();
})
.catch(done.fail);
});
it('group max query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, maxScore: { $max: '$score' } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).toBe(null);
expect(resp.results[0].maxScore).toBe(20);
done();
})
.catch(done.fail);
});
it('group avg query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, avgScore: { $avg: '$score' } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0].hasOwnProperty('objectId')).toBe(true);
expect(resp.results[0].objectId).toBe(null);
expect(resp.results[0].avgScore).toBe(12.5);
done();
})
.catch(done.fail);
});
it('limit query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
limit: 2,
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(2);
done();
})
.catch(done.fail);
});
it('sort ascending query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
sort: { name: 1 },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(4);
expect(resp.results[0].name).toBe('bar');
expect(resp.results[1].name).toBe('dpl');
expect(resp.results[2].name).toBe('foo');
expect(resp.results[3].name).toBe('foo');
done();
})
.catch(done.fail);
});
it('sort decending query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
sort: { name: -1 },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(4);
expect(resp.results[0].name).toBe('foo');
expect(resp.results[1].name).toBe('foo');
expect(resp.results[2].name).toBe('dpl');
expect(resp.results[3].name).toBe('bar');
done();
})
.catch(done.fail);
});
it('skip query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
skip: 2,
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(2);
done();
})
.catch(done.fail);
});
it('match comparison date query', done => {
const today = new Date();
const yesterday = new Date();
const tomorrow = new Date();
yesterday.setDate(today.getDate() - 1);
tomorrow.setDate(today.getDate() + 1);
const obj1 = new TestObject({ dateField: yesterday });
const obj2 = new TestObject({ dateField: today });
const obj3 = new TestObject({ dateField: tomorrow });
const pipeline = [{ match: { dateField: { $lt: tomorrow } } }];
Parse.Object.saveAll([obj1, obj2, obj3])
.then(() => {
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toBe(2);
done();
});
});
it('match comparison query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 15 } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(1);
expect(resp.results[0].score).toBe(20);
done();
})
.catch(done.fail);
});
it('match multiple comparison query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 5, $lt: 15 } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(3);
expect(resp.results[0].score).toBe(10);
expect(resp.results[1].score).toBe(10);
expect(resp.results[2].score).toBe(10);
done();
})
.catch(done.fail);
});
it('match complex comparison query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 5, $lt: 15 }, views: { $gt: 850, $lt: 1000 } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(1);
expect(resp.results[0].score).toBe(10);
expect(resp.results[0].views).toBe(900);
done();
})
.catch(done.fail);
});
it('match comparison and equality query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: { score: { $gt: 5, $lt: 15 }, views: 900 },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(1);
expect(resp.results[0].score).toBe(10);
expect(resp.results[0].views).toBe(900);
done();
})
.catch(done.fail);
});
it('match $or query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: {
$or: [
{ score: { $gt: 15, $lt: 25 } },
{ views: { $gt: 750, $lt: 850 } },
],
},
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(2);
// Match score { $gt: 15, $lt: 25 }
expect(resp.results.some(result => result.score === 20)).toEqual(true);
expect(resp.results.some(result => result.views === 700)).toEqual(true);
// Match view { $gt: 750, $lt: 850 }
expect(resp.results.some(result => result.score === 10)).toEqual(true);
expect(resp.results.some(result => result.views === 800)).toEqual(true);
done();
})
.catch(done.fail);
});
it('match objectId query', done => {
const obj1 = new TestObject();
const obj2 = new TestObject();
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const pipeline = [{ match: { objectId: obj1.id } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(1);
expect(results[0].objectId).toEqual(obj1.id);
done();
});
});
it('match field query', done => {
const obj1 = new TestObject({ name: 'TestObject1' });
const obj2 = new TestObject({ name: 'TestObject2' });
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const pipeline = [{ match: { name: 'TestObject1' } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(1);
expect(results[0].objectId).toEqual(obj1.id);
done();
});
});
it('match pointer query', done => {
const pointer1 = new PointerObject();
const pointer2 = new PointerObject();
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 pipeline = [{ match: { pointer: pointer1.id } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(2);
expect(results[0].pointer.objectId).toEqual(pointer1.id);
expect(results[1].pointer.objectId).toEqual(pointer1.id);
expect(results.some(result => result.objectId === obj1.id)).toEqual(
true
);
expect(results.some(result => result.objectId === obj3.id)).toEqual(
true
);
done();
});
});
it_exclude_dbs(['postgres'])('match exists query', done => {
const pipeline = [{ match: { score: { $exists: true } } }];
const query = new Parse.Query(TestObject);
query.aggregate(pipeline).then(results => {
expect(results.length).toEqual(4);
done();
});
});
it('match date query - createdAt', done => {
const obj1 = new TestObject();
const obj2 = new TestObject();
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const now = new Date();
const today = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate()
);
const pipeline = [{ match: { createdAt: { $gte: today } } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
// Four objects were created initially, we added two more.
expect(results.length).toEqual(6);
done();
});
});
it('match date query - updatedAt', done => {
const obj1 = new TestObject();
const obj2 = new TestObject();
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const now = new Date();
const today = new Date(
now.getFullYear(),
now.getMonth(),
now.getDate()
);
const pipeline = [{ match: { updatedAt: { $gte: today } } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
// Four objects were added initially, we added two more.
expect(results.length).toEqual(6);
done();
});
});
it('match date query - empty', done => {
const obj1 = new TestObject();
const obj2 = new TestObject();
Parse.Object.saveAll([obj1, obj2])
.then(() => {
const now = new Date();
const future = new Date(
now.getFullYear(),
now.getMonth() + 1,
now.getDate()
);
const pipeline = [{ match: { createdAt: future } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(0);
done();
});
});
it_exclude_dbs(['postgres'])('match pointer with operator query', done => {
const pointer = new PointerObject();
const obj1 = new TestObject({ pointer });
const obj2 = new TestObject({ pointer });
const obj3 = new TestObject();
Parse.Object.saveAll([pointer, obj1, obj2, obj3])
.then(() => {
const pipeline = [{ match: { pointer: { $exists: true } } }];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(2);
expect(results[0].pointer.objectId).toEqual(pointer.id);
expect(results[1].pointer.objectId).toEqual(pointer.id);
expect(results.some(result => result.objectId === obj1.id)).toEqual(
true
);
expect(results.some(result => result.objectId === obj2.id)).toEqual(
true
);
done();
});
});
it('project query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
project: { name: 1 },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
resp.results.forEach(result => {
expect(result.objectId).not.toBe(undefined);
expect(result.name).not.toBe(undefined);
expect(result.sender).toBe(undefined);
expect(result.size).toBe(undefined);
expect(result.score).toBe(undefined);
});
done();
})
.catch(done.fail);
});
it('multiple project query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
project: { name: 1, score: 1, sender: 1 },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
resp.results.forEach(result => {
expect(result.objectId).not.toBe(undefined);
expect(result.name).not.toBe(undefined);
expect(result.score).not.toBe(undefined);
expect(result.sender).not.toBe(undefined);
expect(result.size).toBe(undefined);
});
done();
})
.catch(done.fail);
});
it('project pointer query', done => {
const pointer = new PointerObject();
const obj = new TestObject({ pointer, name: 'hello' });
obj
.save()
.then(() => {
const pipeline = [
{ match: { objectId: obj.id } },
{ project: { pointer: 1, name: 1, createdAt: 1 } },
];
const query = new Parse.Query(TestObject);
return query.aggregate(pipeline);
})
.then(results => {
expect(results.length).toEqual(1);
expect(results[0].name).toEqual('hello');
expect(results[0].createdAt).not.toBe(undefined);
expect(results[0].pointer.objectId).toEqual(pointer.id);
done();
});
});
it('project with group query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
project: { score: 1 },
group: { objectId: '$score', score: { $sum: '$score' } },
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(2);
resp.results.forEach(result => {
expect(result.hasOwnProperty('objectId')).toBe(true);
expect(result.name).toBe(undefined);
expect(result.sender).toBe(undefined);
expect(result.size).toBe(undefined);
expect(result.score).not.toBe(undefined);
if (result.objectId === 10) {
expect(result.score).toBe(30);
}
if (result.objectId === 20) {
expect(result.score).toBe(20);
}
});
done();
})
.catch(done.fail);
});
it('class does not exist return empty', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, total: { $sum: '$score' } },
},
});
rp.get(Parse.serverURL + '/aggregate/UnknownClass', options)
.then(resp => {
expect(resp.results.length).toBe(0);
done();
})
.catch(done.fail);
});
it('field does not exist return empty', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
group: { objectId: null, total: { $sum: '$unknownfield' } },
},
});
rp.get(Parse.serverURL + '/aggregate/UnknownClass', options)
.then(resp => {
expect(resp.results.length).toBe(0);
done();
})
.catch(done.fail);
});
it('distinct query', done => {
const options = Object.assign({}, masterKeyOptions, {
body: { distinct: 'score' },
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(2);
expect(resp.results.includes(10)).toBe(true);
expect(resp.results.includes(20)).toBe(true);
done();
})
.catch(done.fail);
});
it('distinct query with where', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
distinct: 'score',
where: {
name: 'bar',
},
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0]).toBe(10);
done();
})
.catch(done.fail);
});
it('distinct query with where string', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
distinct: 'score',
where: JSON.stringify({ name: 'bar' }),
},
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results[0]).toBe(10);
done();
})
.catch(done.fail);
});
it('distinct nested', done => {
const options = Object.assign({}, masterKeyOptions, {
body: { distinct: 'sender.group' },
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(2);
expect(resp.results.includes('A')).toBe(true);
expect(resp.results.includes('B')).toBe(true);
done();
})
.catch(done.fail);
});
it('distinct pointer', done => {
const pointer1 = new PointerObject();
const pointer2 = new PointerObject();
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' },
});
rp.get(Parse.serverURL + '/aggregate/UnknownClass', options)
.then(resp => {
expect(resp.results.length).toBe(0);
done();
})
.catch(done.fail);
});
it('distinct field does not exist return empty', done => {
const options = Object.assign({}, masterKeyOptions, {
body: { distinct: 'unknown' },
});
const obj = new TestObject();
obj
.save()
.then(() => {
return rp.get(Parse.serverURL + '/aggregate/TestObject', options);
})
.then(resp => {
expect(resp.results.length).toBe(0);
done();
})
.catch(done.fail);
});
it('distinct array', done => {
const options = Object.assign({}, masterKeyOptions, {
body: { distinct: 'size' },
});
rp.get(Parse.serverURL + '/aggregate/TestObject', options)
.then(resp => {
expect(resp.results.length).toBe(3);
expect(resp.results.includes('S')).toBe(true);
expect(resp.results.includes('M')).toBe(true);
expect(resp.results.includes('L')).toBe(true);
done();
})
.catch(done.fail);
});
it('distinct null field', done => {
const options = Object.assign({}, masterKeyOptions, {
body: { distinct: 'distinctField' },
});
const user1 = new Parse.User();
user1.setUsername('distinct_1');
user1.setPassword('password');
user1.set('distinctField', 'one');
const user2 = new Parse.User();
user2.setUsername('distinct_2');
user2.setPassword('password');
user2.set('distinctField', null);
user1
.signUp()
.then(() => {
return user2.signUp();
})
.then(() => {
return rp.get(Parse.serverURL + '/aggregate/_User', options);
})
.then(resp => {
expect(resp.results.length).toEqual(1);
expect(resp.results).toEqual(['one']);
done();
})
.catch(done.fail);
});
it('does not return sensitive hidden properties', done => {
const options = Object.assign({}, masterKeyOptions, {
body: {
match: {
score: {
$gt: 5,
},
},
},
});
const username = 'leaky_user';
const score = 10;
const user = new Parse.User();
user.setUsername(username);
user.setPassword('password');
user.set('score', score);
user
.signUp()
.then(function() {
return rp.get(Parse.serverURL + '/aggregate/_User', options);
})
.then(function(resp) {
expect(resp.results.length).toBe(1);
const result = resp.results[0];
// verify server-side keys are not present...
expect(result._hashed_password).toBe(undefined);
expect(result._wperm).toBe(undefined);
expect(result._rperm).toBe(undefined);
expect(result._acl).toBe(undefined);
expect(result._created_at).toBe(undefined);
expect(result._updated_at).toBe(undefined);
// verify createdAt, updatedAt and others are present
expect(result.createdAt).not.toBe(undefined);
expect(result.updatedAt).not.toBe(undefined);
expect(result.objectId).not.toBe(undefined);
expect(result.username).toBe(username);
expect(result.score).toBe(score);
done();
})
.catch(function(err) {
fail(err);
});
});
it_exclude_dbs(['postgres'])(
'aggregate allow multiple of same stage',
done => {
const pointer1 = new TestObject({ value: 1 });
const pointer2 = new TestObject({ value: 2 });
const pointer3 = new TestObject({ value: 3 });
const obj1 = new TestObject({ pointer: pointer1, name: 'Hello' });
const obj2 = new TestObject({ pointer: pointer2, name: 'Hello' });
const obj3 = new TestObject({ pointer: pointer3, name: 'World' });
const options = Object.assign({}, masterKeyOptions, {
body: [
{
match: { name: 'Hello' },
},
{
// Transform className$objectId to objectId and store in new field tempPointer
project: {
tempPointer: { $substr: ['$_p_pointer', 11, -1] }, // Remove TestObject$
},
},
{
// Left Join, replace objectId stored in tempPointer with an actual object
lookup: {
from: 'test_TestObject',
localField: 'tempPointer',
foreignField: '_id',
as: 'tempPointer',
},
},
{
// lookup returns an array, Deconstructs an array field to objects
unwind: {
path: '$tempPointer',
},
},
{
match: { 'tempPointer.value': 2 },
},
],
});
Parse.Object.saveAll([pointer1, pointer2, pointer3, obj1, obj2, obj3])
.then(() => {
return rp.get(Parse.serverURL + '/aggregate/TestObject', options);
})
.then(resp => {
expect(resp.results.length).toEqual(1);
expect(resp.results[0].tempPointer.value).toEqual(2);
done();
});
}
);
});