Skip to content

Commit 080610a

Browse files
authored
build: Release (#9836)
2 parents e3f5ae0 + a09f751 commit 080610a

File tree

5 files changed

+98
-56
lines changed

5 files changed

+98
-56
lines changed

changelogs/CHANGELOG_alpha.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## [8.2.3-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.2...8.2.3-alpha.1) (2025-07-13)
2+
3+
4+
### Bug Fixes
5+
6+
* MongoDB aggregation pipeline with `$dateSubtract` from `$$NOW` returns no results ([#9822](https://github.com/parse-community/parse-server/issues/9822)) ([847a274](https://github.com/parse-community/parse-server/commit/847a274cdb8c22f8e0fc249162e5e2c9e29a594a))
7+
18
## [8.2.2-alpha.1](https://github.com/parse-community/parse-server/compare/8.2.1...8.2.2-alpha.1) (2025-07-10)
29

310

package-lock.json

Lines changed: 42 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "parse-server",
3-
"version": "8.2.2",
3+
"version": "8.2.3-alpha.1",
44
"description": "An express module providing a Parse-compatible API server",
55
"main": "lib/index.js",
66
"repository": {
@@ -21,7 +21,7 @@
2121
"license": "Apache-2.0",
2222
"dependencies": {
2323
"@apollo/server": "4.12.1",
24-
"@babel/eslint-parser": "7.27.1",
24+
"@babel/eslint-parser": "7.28.0",
2525
"@graphql-tools/merge": "9.0.24",
2626
"@graphql-tools/schema": "10.0.23",
2727
"@graphql-tools/utils": "10.8.6",
@@ -32,7 +32,7 @@
3232
"cors": "2.8.5",
3333
"deepcopy": "2.1.0",
3434
"express": "5.1.0",
35-
"express-rate-limit": "7.5.0",
35+
"express-rate-limit": "7.5.1",
3636
"follow-redirects": "1.15.9",
3737
"graphql": "16.11.0",
3838
"graphql-list-fields": "2.0.4",
@@ -52,7 +52,7 @@
5252
"parse": "6.1.1",
5353
"path-to-regexp": "6.3.0",
5454
"pg-monitor": "3.0.0",
55-
"pg-promise": "11.13.0",
55+
"pg-promise": "11.14.0",
5656
"pluralize": "8.0.0",
5757
"punycode": "2.3.1",
5858
"rate-limit-redis": "4.2.0",

spec/ParseQuery.Aggregate.spec.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,36 @@ describe('Parse.Query Aggregate testing', () => {
439439
}
440440
);
441441

442+
it_id('3723671d-4100-4103-ad9c-60e4c22e20ff')(it_exclude_dbs(['postgres']))('matches expression with $dateSubtract from $$NOW', async () => {
443+
const obj1 = new TestObject({ date: new Date(new Date().getTime() - 1 * 24 * 60 * 60 * 1_000) }); // 1 day ago
444+
const obj2 = new TestObject({ date: new Date(new Date().getTime() - 2 * 24 * 60 * 60 * 1_000) }); // 3 days ago
445+
await Parse.Object.saveAll([obj1, obj2]);
446+
447+
const pipeline = [
448+
{
449+
$match: {
450+
$expr: {
451+
$gte: [
452+
'$date',
453+
{
454+
$dateSubtract: {
455+
startDate: '$$NOW',
456+
unit: 'day',
457+
amount: 2,
458+
},
459+
},
460+
],
461+
},
462+
},
463+
},
464+
];
465+
466+
const query = new Parse.Query('TestObject');
467+
const results = await query.aggregate(pipeline, { useMasterKey: true });
468+
expect(results.length).toBe(1);
469+
expect(new Date(results[0].date.iso)).toEqual(obj1.get('date'));
470+
});
471+
442472
it_only_db('postgres')(
443473
'can group by any date field (it does not work if you have dirty data)', // rows in your collection with non date data in the field that is supposed to be a date
444474
done => {

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -960,23 +960,28 @@ export class MongoStorageAdapter implements StorageAdapter {
960960
return pipeline;
961961
}
962962

963-
// This function will attempt to convert the provided value to a Date object. Since this is part
964-
// of an aggregation pipeline, the value can either be a string or it can be another object with
965-
// an operator in it (like $gt, $lt, etc). Because of this I felt it was easier to make this a
966-
// recursive method to traverse down to the "leaf node" which is going to be the string.
963+
/**
964+
* Recursively converts values to Date objects. Since the passed object is part of an aggregation
965+
* pipeline and can contain various logic operators (like $gt, $lt, etc), this function will
966+
* traverse the object and convert any strings that can be parsed as dates into Date objects.
967+
* @param {any} value The value to convert.
968+
* @returns {any} The original value if not convertible to Date, or a Date object if it is.
969+
*/
967970
_convertToDate(value: any): any {
968971
if (value instanceof Date) {
969972
return value;
970973
}
971974
if (typeof value === 'string') {
972-
return new Date(value);
975+
return isNaN(Date.parse(value)) ? value : new Date(value);
973976
}
974-
975-
const returnValue = {};
976-
for (const field in value) {
977-
returnValue[field] = this._convertToDate(value[field]);
977+
if (typeof value === 'object') {
978+
const returnValue = {};
979+
for (const field in value) {
980+
returnValue[field] = this._convertToDate(value[field]);
981+
}
982+
return returnValue;
978983
}
979-
return returnValue;
984+
return value;
980985
}
981986

982987
_parseReadPreference(readPreference: ?string): ?string {

0 commit comments

Comments
 (0)