Skip to content

Commit 8a7d63a

Browse files
committed
Add support for date range and marks filtering in recentEvents
1 parent 5eb4f34 commit 8a7d63a

3 files changed

Lines changed: 69 additions & 31 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ uploads
77
globalConfig.json
88
coverage
99
tls
10+
.history

src/models/eventsFactory.js

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,11 @@ class EventsFactory extends Factory {
149149
* @param {Number} limit - events count limitations
150150
* @param {Number} skip - certain number of documents to skip
151151
* @param {'BY_DATE' | 'BY_COUNT'} sort - events sort order
152-
* @param {EventsFilters} filters - marks by which events should be filtered
153-
* @param {String} search - Search query
152+
* @param {Object} filters - filter object
153+
* @param {Object.<string, boolean>} [filters.marks] - mark filters: e.g. { starred: true, ignored: false }
154+
* @param {string|number} [filters.dateFrom] - filter start date (ISO or timestamp)
155+
* @param {string|number} [filters.dateTo] - filter end date (ISO or timestamp)
156+
* @param {String} search - search query
154157
*
155158
* @return {RecentEventSchema[]}
156159
*/
@@ -165,9 +168,6 @@ class EventsFactory extends Factory {
165168
throw new Error('Search parameter must be a string');
166169
}
167170

168-
/**
169-
* Check if pattern is safe RegExp
170-
*/
171171
if (!safe(search)) {
172172
throw new Error('Invalid regular expression pattern');
173173
}
@@ -231,13 +231,41 @@ class EventsFactory extends Factory {
231231
}
232232
: {};
233233

234-
const matchFilter = filters
235-
? Object.fromEntries(
236-
Object
237-
.entries(filters)
238-
.map(([mark, exists]) => [`event.marks.${mark}`, { $exists: exists } ])
239-
)
240-
: {};
234+
const matchFilter = {
235+
...searchFilter,
236+
};
237+
238+
// Filter by marks (event.marks.{key})
239+
if (filters.marks && typeof filters.marks === 'object') {
240+
for (const [mark, exists] of Object.entries(filters.marks)) {
241+
matchFilter[`event.marks.${mark}`] = { $exists: exists };
242+
}
243+
}
244+
245+
// Filter by date (groupingTimestamp)
246+
if (filters.dateFrom || filters.dateTo) {
247+
matchFilter.groupingTimestamp = {};
248+
249+
if (filters.dateFrom) {
250+
const from = typeof filters.dateFrom === 'string'
251+
? Math.floor(new Date(filters.dateFrom).getTime() / 1000)
252+
: filters.dateFrom;
253+
254+
matchFilter.groupingTimestamp.$gte = from;
255+
}
256+
257+
if (filters.dateTo) {
258+
const to = typeof filters.dateTo === 'string'
259+
? Math.floor(new Date(filters.dateTo).getTime() / 1000)
260+
: filters.dateTo;
261+
262+
matchFilter.groupingTimestamp.$lte = to;
263+
}
264+
265+
if (Object.keys(matchFilter.groupingTimestamp).length === 0) {
266+
delete matchFilter.groupingTimestamp;
267+
}
268+
}
241269

242270
pipeline.push(
243271
{
@@ -252,10 +280,7 @@ class EventsFactory extends Factory {
252280
$unwind: '$event',
253281
},
254282
{
255-
$match: {
256-
...matchFilter,
257-
...searchFilter,
258-
},
283+
$match: matchFilter,
259284
},
260285
{ $skip: skip },
261286
{ $limit: limit },
@@ -272,17 +297,8 @@ class EventsFactory extends Factory {
272297
);
273298

274299
const cursor = this.getCollection(this.TYPES.DAILY_EVENTS).aggregate(pipeline);
275-
276300
const result = (await cursor.toArray()).shift();
277301

278-
/**
279-
* aggregation can return empty array so that
280-
* result can be undefined
281-
*
282-
* for that we check result existence
283-
*
284-
* extra field `projectId` needs to satisfy GraphQL query
285-
*/
286302
if (result && result.events) {
287303
result.events.forEach(event => {
288304
event.projectId = this.projectId;

src/typeDefs/project.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,32 @@ Events filters input type
1616
"""
1717
input EventsFiltersInput {
1818
"""
19-
If True, includes events with resolved mark to the output
19+
Filter events by marks (e.g. starred, resolved, ignored).
20+
Set to true to include only events that have the mark, or false to exclude those.
21+
Example: { starred: true, ignored: false }
2022
"""
21-
resolved: Boolean
23+
marks: MarksFilterInput
24+
2225
"""
23-
If True, includes events with starred mark to the output
26+
Include only events that occurred after this date (inclusive).
27+
Accepts ISO date string or Unix timestamp (in seconds).
2428
"""
25-
starred: Boolean
29+
dateFrom: Timestamp
30+
2631
"""
27-
If True, includes events with ignored mark to the output
32+
Include only events that occurred before this date (inclusive).
33+
Accepts ISO date string or Unix timestamp (in seconds).
2834
"""
35+
dateTo: Timestamp
36+
}
37+
38+
"""
39+
Allows filtering by specific event marks.
40+
Each field corresponds to event.marks.{name}.
41+
"""
42+
input MarksFilterInput {
43+
starred: Boolean
44+
resolved: Boolean
2945
ignored: Boolean
3046
}
3147
@@ -122,12 +138,17 @@ type Project {
122138
"Events sort order"
123139
sort: EventsSortOrder = lastRepetitionTime
124140
125-
"Event marks by which events should be sorted"
141+
"""
142+
Filters for narrowing down the event results:
143+
- By marks (e.g., starred, resolved)
144+
- By date range (dateFrom / dateTo)
145+
"""
126146
filters: EventsFiltersInput
127147
128148
"Search query"
129149
search: String
130150
): RecentEvents
151+
131152
"""
132153
Return events that occurred after a certain timestamp
133154
"""

0 commit comments

Comments
 (0)