Skip to content

Commit eced63c

Browse files
github-actions[bot]pavelzotikovneSpecc
authored
Feature: Add search field for mongo queries (#474) (#477)
* Feature: Add search field for mongo queries * Bump version up to 1.1.15 * add search in comment * Update eventsFactory.js * Update project.js * Update project.ts * rm unused * fix eslint --------- Co-authored-by: Pavel Zotikov <pavelzotikov@gmail.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Peter Savchenko <specc.dev@gmail.com>
1 parent 500a01b commit eced63c

File tree

5 files changed

+86
-66
lines changed

5 files changed

+86
-66
lines changed

.eslintrc.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,13 @@ module.exports = {
1111
'require-jsdoc': 'warn',
1212
'no-shadow': 'warn',
1313
'no-unused-expressions': 'warn'
14-
}
14+
},
15+
overrides: [
16+
{
17+
files: ['*.js'],
18+
rules: {
19+
'@typescript-eslint/explicit-function-return-type': 'off'
20+
}
21+
}
22+
]
1523
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "hawk.api",
3-
"version": "1.1.14",
3+
"version": "1.1.15",
44
"main": "index.ts",
55
"license": "UNLICENSED",
66
"scripts": {

src/models/eventsFactory.js

Lines changed: 63 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -149,15 +149,23 @@ class EventsFactory extends Factory {
149149
* @param {Number} skip - certain number of documents to skip
150150
* @param {'BY_DATE' | 'BY_COUNT'} sort - events sort order
151151
* @param {EventsFilters} filters - marks by which events should be filtered
152+
* @param {String} search - Search query
152153
*
153154
* @return {RecentEventSchema[]}
154155
*/
155156
async findRecent(
156157
limit = 10,
157158
skip = 0,
158159
sort = 'BY_DATE',
159-
filters = {}
160+
filters = {},
161+
search = ''
160162
) {
163+
if (typeof search !== 'string') {
164+
throw new Error('Search parameter must be a string');
165+
}
166+
167+
const escapedSearch = search.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
168+
161169
limit = this.validateLimit(limit);
162170

163171
switch (sort) {
@@ -184,71 +192,64 @@ class EventsFactory extends Factory {
184192
},
185193
];
186194

187-
/**
188-
* If some events should be omitted, use alternative pipeline
189-
*/
190-
if (Object.values(filters).length > 0) {
191-
pipeline.push(
192-
/**
193-
* Lookup events object for each daily event
194-
*/
195-
{
196-
$lookup: {
197-
from: 'events:' + this.projectId,
198-
localField: 'groupHash',
199-
foreignField: 'groupHash',
200-
as: 'event',
195+
const searchFilter = search.trim().length > 0
196+
? {
197+
$or: [
198+
{
199+
'event.payload.title': {
200+
$regex: escapedSearch,
201+
$options: 'i',
202+
},
201203
},
202-
},
203-
{
204-
$unwind: '$event',
205-
},
206-
/**
207-
* Match filters
208-
*/
209-
{
210-
$match: {
211-
...Object.fromEntries(
212-
Object
213-
.entries(filters)
214-
.map(([mark, exists]) => [`event.marks.${mark}`, { $exists: exists } ])
215-
),
204+
{
205+
'event.payload.backtrace.file': {
206+
$regex: escapedSearch,
207+
$options: 'i',
208+
},
216209
},
210+
],
211+
}
212+
: {};
213+
214+
const matchFilter = filters
215+
? Object.fromEntries(
216+
Object
217+
.entries(filters)
218+
.map(([mark, exists]) => [`event.marks.${mark}`, { $exists: exists } ])
219+
)
220+
: {};
221+
222+
pipeline.push(
223+
{
224+
$lookup: {
225+
from: 'events:' + this.projectId,
226+
localField: 'groupHash',
227+
foreignField: 'groupHash',
228+
as: 'event',
217229
},
218-
{ $skip: skip },
219-
{ $limit: limit },
220-
{
221-
$group: {
222-
_id: null,
223-
dailyInfo: { $push: '$$ROOT' },
224-
events: { $push: '$event' },
225-
},
230+
},
231+
{
232+
$unwind: '$event',
233+
},
234+
{
235+
$match: {
236+
...matchFilter,
237+
...searchFilter,
226238
},
227-
{
228-
$unset: 'dailyInfo.event',
229-
}
230-
);
231-
} else {
232-
pipeline.push(
233-
{ $skip: skip },
234-
{ $limit: limit },
235-
{
236-
$group: {
237-
_id: null,
238-
groupHash: { $addToSet: '$groupHash' },
239-
dailyInfo: { $push: '$$ROOT' },
240-
},
239+
},
240+
{ $skip: skip },
241+
{ $limit: limit },
242+
{
243+
$group: {
244+
_id: null,
245+
dailyInfo: { $push: '$$ROOT' },
246+
events: { $push: '$event' },
241247
},
242-
{
243-
$lookup: {
244-
from: 'events:' + this.projectId,
245-
localField: 'groupHash',
246-
foreignField: 'groupHash',
247-
as: 'events',
248-
},
249-
}
250-
);
251-
}
248+
},
249+
{
250+
$unset: 'dailyInfo.event',
251+
}
252+
);
252253

253254
const cursor = this.getCollection(this.TYPES.DAILY_EVENTS).aggregate(pipeline);
254255

@@ -316,7 +317,7 @@ class EventsFactory extends Factory {
316317
});
317318

318319
/**
319-
* Group events using 'groupByTimestamp:NNNNNNNN' key
320+
* Group events using 'groupingTimestamp:NNNNNNNN' key
320321
* @type {ProjectChartItem[]}
321322
*/
322323
const groupedData = groupBy('groupingTimestamp')(dailyEvents);

src/resolvers/project.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const ProjectModel = require('../models/project').default;
1111
const EVENTS_GROUP_HASH_INDEX_NAME = 'groupHashUnique';
1212
const REPETITIONS_GROUP_HASH_INDEX_NAME = 'groupHash_hashed';
1313
const REPETITIONS_USER_ID_INDEX_NAME = 'userId';
14+
const MAX_SEARCH_QUERY_LENGTH = 50;
1415

1516
/**
1617
* See all types and fields here {@see ../typeDefs/project.graphql}
@@ -304,13 +305,20 @@ module.exports = {
304305
* @param {Number} skip - certain number of documents to skip
305306
* @param {'BY_DATE' | 'BY_COUNT'} sort - events sort order
306307
* @param {EventsFilters} filters - marks by which events should be filtered
308+
* @param {String} search - search query
307309
*
308310
* @return {Promise<RecentEventSchema[]>}
309311
*/
310-
async recentEvents(project, { limit, skip, sort, filters }) {
312+
async recentEvents(project, { limit, skip, sort, filters, search }) {
313+
if (search) {
314+
if (search.length > MAX_SEARCH_QUERY_LENGTH) {
315+
search = search.slice(0, MAX_SEARCH_QUERY_LENGTH);
316+
}
317+
}
318+
311319
const factory = new EventsFactory(project._id);
312320

313-
return factory.findRecent(limit, skip, sort, filters);
321+
return factory.findRecent(limit, skip, sort, filters, search);
314322
},
315323

316324
/**

src/typeDefs/project.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ type Project {
124124
125125
"Event marks by which events should be sorted"
126126
filters: EventsFiltersInput
127+
128+
"Search query"
129+
search: String
127130
): RecentEvents
128131
"""
129132
Return events that occurred after a certain timestamp

0 commit comments

Comments
 (0)