@@ -10,6 +10,7 @@ import { logWarn } from "../logger";
1010import {
1111 getUserMatchTechnologies ,
1212 MatchableJob ,
13+ MatchedJob ,
1314 scoreJobWithTechnologies ,
1415} from "../modules/jobs/jobMatch.service" ;
1516import { NotificationsService } from "../modules/notifications/notifications.service" ;
@@ -258,6 +259,29 @@ function getKeywordsArray(query: Request["query"]): string[] {
258259 . filter ( Boolean ) ;
259260}
260261
262+ function getMatchSort ( query : Request [ "query" ] ) : "asc" | "desc" | null {
263+ const value = firstQueryValue ( query . matchSort ) || firstQueryValue ( query . sort ) ;
264+ return value === "asc" || value === "desc" ? value : null ;
265+ }
266+
267+ function sortJobsByMatch < T > (
268+ jobs : T [ ] ,
269+ direction : "asc" | "desc" ,
270+ ) {
271+ return [ ...jobs ] . sort ( ( first , second ) => {
272+ const firstJob = first as { matchScore ?: number | null } ;
273+ const secondJob = second as { matchScore ?: number | null } ;
274+ const firstScore =
275+ typeof firstJob . matchScore === "number" ? firstJob . matchScore : 0 ;
276+ const secondScore =
277+ typeof secondJob . matchScore === "number" ? secondJob . matchScore : 0 ;
278+
279+ return direction === "desc"
280+ ? secondScore - firstScore
281+ : firstScore - secondScore ;
282+ } ) ;
283+ }
284+
261285async function legacyResolveIds (
262286 keywordsArray : string [ ] ,
263287) : Promise < { ids : string [ ] ; source : string } > {
@@ -294,14 +318,22 @@ async function enrichJobsWithProfileMatch(
294318 req : Request ,
295319 jobs : unknown [ ] ,
296320 technologies : MatchTechnology [ ] ,
321+ options : { notifyHighMatches ?: boolean } = { } ,
297322) {
298323 if ( technologies . length === 0 ) return jobs ;
299324
300325 const matchedJobs = jobs . map ( ( job ) =>
301326 scoreJobWithTechnologies ( job as MatchableJob , technologies ) ,
302327 ) ;
328+ if ( options . notifyHighMatches === false ) return matchedJobs ;
329+
330+ await notifyHighMatchJobs ( req , matchedJobs ) ;
331+ return matchedJobs ;
332+ }
333+
334+ async function notifyHighMatchJobs ( req : Request , matchedJobs : MatchedJob [ ] ) {
303335 const userId = req . session ?. userId ;
304- if ( ! userId ) return matchedJobs ;
336+ if ( ! userId ) return ;
305337
306338 const notifications = new NotificationsService ( ) ;
307339 await Promise . all (
@@ -317,8 +349,6 @@ async function enrichJobsWithProfileMatch(
317349 } ) ,
318350 ) ,
319351 ) ;
320-
321- return matchedJobs ;
322352}
323353
324354/**
@@ -339,6 +369,7 @@ jobsRoutes.get("/search", async (req: Request, res: Response) => {
339369 const keywordsArray = getKeywordsArray ( req . query ) ;
340370 const pagination = parsePagination ( req . query ) ;
341371 const hasFilters = hasStructuredFilters ( req . query ) ;
372+ const matchSort = getMatchSort ( req . query ) ;
342373 const matchTechnologies = await getCurrentUserMatchTechnologies ( req ) ;
343374
344375 let ids : string [ ] = [ ] ;
@@ -369,15 +400,30 @@ jobsRoutes.get("/search", async (req: Request, res: Response) => {
369400 const legacy = await legacyResolveIds ( keywordsArray ) ;
370401 const legacyJobs = await cacheGetJobsByIds ( legacy . ids ) ;
371402 const filteredJobs = filterJobs ( legacyJobs , req . query ) ;
372- const { data : pageJobs , pagination : meta } = paginate (
373- filteredJobs ,
374- pagination ,
375- ) ;
376- const jobs = await enrichJobsWithProfileMatch (
377- req ,
378- pageJobs ,
379- matchTechnologies ,
380- ) ;
403+ const { data : pageJobs , pagination : meta } = matchSort
404+ ? paginate (
405+ sortJobsByMatch (
406+ await enrichJobsWithProfileMatch (
407+ req ,
408+ filteredJobs ,
409+ matchTechnologies ,
410+ { notifyHighMatches : false } ,
411+ ) ,
412+ matchSort ,
413+ ) ,
414+ pagination ,
415+ )
416+ : paginate ( filteredJobs , pagination ) ;
417+ if ( matchSort ) {
418+ await notifyHighMatchJobs ( req , pageJobs as MatchedJob [ ] ) ;
419+ }
420+ const jobs = matchSort
421+ ? pageJobs
422+ : await enrichJobsWithProfileMatch (
423+ req ,
424+ pageJobs ,
425+ matchTechnologies ,
426+ ) ;
381427
382428 return res . json ( {
383429 total : meta . total ,
@@ -393,15 +439,30 @@ jobsRoutes.get("/search", async (req: Request, res: Response) => {
393439
394440 const indexedJobs = await cacheGetJobsByIds ( ids ) ;
395441 const filteredJobs = filterJobs ( indexedJobs , req . query ) ;
396- const { data : pageJobs , pagination : meta } = paginate (
397- filteredJobs ,
398- pagination ,
399- ) ;
400- const jobs = await enrichJobsWithProfileMatch (
401- req ,
402- pageJobs ,
403- matchTechnologies ,
404- ) ;
442+ const { data : pageJobs , pagination : meta } = matchSort
443+ ? paginate (
444+ sortJobsByMatch (
445+ await enrichJobsWithProfileMatch (
446+ req ,
447+ filteredJobs ,
448+ matchTechnologies ,
449+ { notifyHighMatches : false } ,
450+ ) ,
451+ matchSort ,
452+ ) ,
453+ pagination ,
454+ )
455+ : paginate ( filteredJobs , pagination ) ;
456+ if ( matchSort ) {
457+ await notifyHighMatchJobs ( req , pageJobs as MatchedJob [ ] ) ;
458+ }
459+ const jobs = matchSort
460+ ? pageJobs
461+ : await enrichJobsWithProfileMatch (
462+ req ,
463+ pageJobs ,
464+ matchTechnologies ,
465+ ) ;
405466
406467 return res . json ( {
407468 total : meta . total ,
@@ -419,6 +480,33 @@ jobsRoutes.get("/search", async (req: Request, res: Response) => {
419480 source = legacy . source ;
420481 }
421482
483+ if ( matchSort ) {
484+ const allJobs = await cacheGetJobsByIds ( ids ) ;
485+ const matchedJobs = await enrichJobsWithProfileMatch (
486+ req ,
487+ allJobs ,
488+ matchTechnologies ,
489+ { notifyHighMatches : false } ,
490+ ) ;
491+ const sortedJobs = sortJobsByMatch ( matchedJobs , matchSort ) ;
492+ const { data : jobs , pagination : meta } = paginate (
493+ sortedJobs ,
494+ pagination ,
495+ ) ;
496+ await notifyHighMatchJobs ( req , jobs as MatchedJob [ ] ) ;
497+
498+ return res . json ( {
499+ total : meta . total ,
500+ page : meta . page ,
501+ limit : meta . limit ,
502+ totalPages : meta . totalPages ,
503+ hasNext : meta . hasNext ,
504+ hasPrev : meta . hasPrev ,
505+ jobs,
506+ source : `${ source } :match_sorted_${ matchSort } ` ,
507+ } ) ;
508+ }
509+
422510 const { data : pageIds , pagination : meta } = paginate ( ids , pagination ) ;
423511 const pageJobs = await cacheGetJobsByIds ( pageIds ) ;
424512 const jobs = await enrichJobsWithProfileMatch (
0 commit comments