11import { Injectable } from "@nestjs/common" ;
22import {
3- ShortOrgEntity ,
43 ShortOrg ,
54 Repository ,
65 PaginatedData ,
@@ -56,6 +55,7 @@ import { ConfigService } from "@nestjs/config";
5655import axios from "axios" ;
5756import { Auth0Service } from "src/auth0/auth0.service" ;
5857import { ImportOrgJobsiteInput } from "./dto/import-organization-jobsites.input" ;
58+ import { SearchOrganizationsInput } from "./dto/search-organizations.input" ;
5959
6060@Injectable ( )
6161export class OrganizationsService {
@@ -109,7 +109,8 @@ export class OrganizationsService {
109109 classification: [(structured_jobpost)-[:HAS_CLASSIFICATION]->(classification) | classification.name ][0],
110110 commitment: [(structured_jobpost)-[:HAS_COMMITMENT]->(commitment) | commitment.name ][0],
111111 locationType: [(structured_jobpost)-[:HAS_LOCATION_TYPE]->(locationType) | locationType.name ][0],
112- timestamp: CASE WHEN structured_jobpost.publishedTimestamp IS NULL THEN structured_jobpost.firstSeenTimestamp ELSE structured_jobpost.publishedTimestamp END
112+ timestamp: CASE WHEN structured_jobpost.publishedTimestamp IS NULL THEN structured_jobpost.firstSeenTimestamp ELSE structured_jobpost.publishedTimestamp END,
113+ tags: [(organization)-[:HAS_JOBSITE|HAS_JOBPOST|HAS_STRUCTURED_JOBPOST|HAS_TAG*4]->(tag: Tag)-[:HAS_TAG_DESIGNATION]->(:AllowedDesignation|DefaultDesignation) | tag.name ]
113114 }
114115 ],
115116 projects: [
@@ -242,9 +243,16 @@ export class OrganizationsService {
242243 }
243244
244245 const orgFilters = ( org : OrgDetailsResult ) : boolean => {
245- const { headcountEstimate, jobCount, projectCount, location, name } =
246- toShortOrg ( org ) ;
247- const { fundingRounds, investors, community, aliases } = org ;
246+ const [ jobCount , projectCount ] = [ org . jobs . length , org . projects . length ] ;
247+ const {
248+ fundingRounds,
249+ investors,
250+ community,
251+ aliases,
252+ headcountEstimate,
253+ location,
254+ name,
255+ } = org ;
248256 const isValidSearchResult =
249257 name . match ( query ) || aliases . some ( alias => alias . match ( query ) ) ;
250258 return (
@@ -275,11 +283,10 @@ export class OrganizationsService {
275283 const filtered = results . filter ( orgFilters ) ;
276284
277285 const getSortParam = ( org : OrgDetailsResult ) : number | null => {
278- const shortOrg = toShortOrg ( org ) ;
279286 const lastJob = sort ( org . jobs ) . desc ( x => x . timestamp ) [ 0 ] ;
280287 switch ( orderBy ) {
281288 case "recentFundingDate" :
282- return shortOrg ? .lastFundingDate ?? 0 ;
289+ return org . lastFundingDate ( ) ?? 0 ;
283290 case "recentJobDate" :
284291 return lastJob ?. timestamp ?? 0 ;
285292 case "headcountEstimate" :
@@ -302,16 +309,14 @@ export class OrganizationsService {
302309 if ( ! order || order === "desc" ) {
303310 final = naturalSort < OrgDetailsResult > ( filtered ) . by ( [
304311 {
305- desc : x =>
306- params . orderBy ? getSortParam ( x ) : toShortOrg ( x ) . lastFundingDate ,
312+ desc : x => ( params . orderBy ? getSortParam ( x ) : x . lastFundingDate ( ) ) ,
307313 } ,
308314 { asc : x => x . name } ,
309315 ] ) ;
310316 } else {
311317 final = naturalSort < OrgDetailsResult > ( filtered ) . by ( [
312318 {
313- asc : x =>
314- params . orderBy ? getSortParam ( x ) : toShortOrg ( x ) . lastFundingDate ,
319+ asc : x => ( params . orderBy ? getSortParam ( x ) : x . lastFundingDate ( ) ) ,
315320 } ,
316321 { asc : x => x . name } ,
317322 ] ) ;
@@ -320,7 +325,7 @@ export class OrganizationsService {
320325 return paginate < ShortOrg > (
321326 page ,
322327 limit ,
323- final . map ( x => new ShortOrgEntity ( toShortOrg ( x ) ) . getProperties ( ) ) ,
328+ final . map ( x => toShortOrg ( x ) ) ,
324329 ) ;
325330 }
326331
@@ -370,7 +375,7 @@ export class OrganizationsService {
370375 now <= job . featureEndDate ,
371376 ) ,
372377 )
373- . map ( x => new ShortOrgEntity ( toShortOrg ( x ) ) . getProperties ( ) ) ,
378+ . map ( x => toShortOrg ( x ) ) ,
374379 } ;
375380 } catch ( err ) {
376381 Sentry . withScope ( scope => {
@@ -795,9 +800,7 @@ export class OrganizationsService {
795800
796801 async getAll ( ) : Promise < ShortOrg [ ] > {
797802 try {
798- return ( await this . getOrgListResults ( ) ) . map ( org =>
799- new ShortOrgEntity ( toShortOrg ( org ) ) . getProperties ( ) ,
800- ) ;
803+ return ( await this . getOrgListResults ( ) ) . map ( org => toShortOrg ( org ) ) ;
801804 } catch ( err ) {
802805 Sentry . withScope ( scope => {
803806 scope . setTags ( {
@@ -811,18 +814,75 @@ export class OrganizationsService {
811814 }
812815 }
813816
814- async searchOrganizations ( query : string ) : Promise < ShortOrg [ ] > {
815- const parsedQuery = new RegExp ( query , "gi" ) ;
817+ async searchOrganizations (
818+ params : SearchOrganizationsInput ,
819+ community : string | undefined ,
820+ ) : Promise < PaginatedData < ShortOrg > > {
816821 try {
817- const all = await this . getAll ( ) ;
818- return all . filter ( x => x . name . match ( parsedQuery ) ) ;
822+ const {
823+ locations : locationFilterList ,
824+ investors : investorFilterList ,
825+ fundingRounds : fundingRoundFilterList ,
826+ tags : tagFilterList ,
827+ page : page = 1 ,
828+ limit : limit = 20 ,
829+ } = params ;
830+
831+ const communityFilterList = community ? [ community ] : null ;
832+
833+ const all = await this . getOrgListResults ( ) ;
834+
835+ const orgFilters = ( org : OrgDetailsResult ) : boolean => {
836+ const { fundingRounds, investors, community, location } = org ;
837+ const tags = org . jobs . flatMap ( x => x . tags ) ;
838+ return (
839+ ( ! locationFilterList ||
840+ locationFilterList . includes ( slugify ( location ) ) ) &&
841+ ( ! investorFilterList ||
842+ investors . filter ( investor =>
843+ investorFilterList . includes ( slugify ( investor . name ) ) ,
844+ ) . length > 0 ) &&
845+ ( ! communityFilterList ||
846+ community . filter ( community =>
847+ communityFilterList . includes ( slugify ( community ) ) ,
848+ ) . length > 0 ) &&
849+ ( ! fundingRoundFilterList ||
850+ fundingRoundFilterList . includes (
851+ slugify (
852+ sort < FundingRound > ( fundingRounds ) . desc ( x => x . date ) [ 0 ]
853+ ?. roundName ,
854+ ) ,
855+ ) ) &&
856+ ( ! tagFilterList ||
857+ tags . filter ( tag => tagFilterList . includes ( slugify ( tag ) ) ) . length > 0 )
858+ ) ;
859+ } ;
860+
861+ const filtered = all . filter ( orgFilters ) . map ( toShortOrg ) ;
862+
863+ const naturalSort = createNewSortInstance ( {
864+ comparer : new Intl . Collator ( undefined , {
865+ numeric : true ,
866+ sensitivity : "base" ,
867+ } ) . compare ,
868+ inPlaceSorting : true ,
869+ } ) ;
870+
871+ const sorted = naturalSort < ShortOrg > ( filtered ) . by ( [
872+ {
873+ desc : x => x . lastFundingDate ,
874+ } ,
875+ { asc : x => x . name } ,
876+ ] ) ;
877+
878+ return paginate < ShortOrg > ( page , limit , sorted ) ;
819879 } catch ( err ) {
820880 Sentry . withScope ( scope => {
821881 scope . setTags ( {
822882 action : "db-call" ,
823883 source : "organizations.service" ,
824884 } ) ;
825- scope . setExtra ( "input" , query ) ;
885+ scope . setExtra ( "input" , params ) ;
826886 Sentry . captureException ( err ) ;
827887 } ) ;
828888 this . logger . error (
0 commit comments