@@ -197,13 +197,35 @@ export type CacheJobIndexFilters = {
197197 country ?: string ;
198198 state ?: string ;
199199 city ?: string ;
200- type ?: string ;
201- model ?: string ;
200+ type ?: string | string [ ] ;
201+ model ?: string | string [ ] ;
202202 contract ?: string ;
203203} ;
204204
205- export function cacheJobIndexKeys ( filters : CacheJobIndexFilters ) : string [ ] {
206- const entries : Array < [ string , string | undefined ] > = [
205+ function filterValues ( value : string | string [ ] | undefined ) : string [ ] {
206+ const values = Array . isArray ( value ) ? value : [ value ] ;
207+
208+ return values
209+ . flatMap ( ( item ) => item ?. split ( "," ) ?? [ ] )
210+ . map ( ( item ) => item . trim ( ) )
211+ . filter ( Boolean ) ;
212+ }
213+
214+ function cacheJobIndexKey ( kind : string , value : string ) : string {
215+ const normalized =
216+ kind === "level"
217+ ? normalizeLevelIndexValue ( value )
218+ : normalizeIndexValue ( value ) ;
219+
220+ if ( ! normalized || normalized === "todos" || normalized === "all" ) {
221+ return "" ;
222+ }
223+
224+ return `scraper:jobs:${ kind } :${ normalized } ` ;
225+ }
226+
227+ function cacheJobIndexKeyGroups ( filters : CacheJobIndexFilters ) : string [ ] [ ] {
228+ const entries : Array < [ string , string | string [ ] | undefined ] > = [
207229 [ "level" , filters . level ] ,
208230 [ "location" , filters . location ] ,
209231 [ "continent" , filters . continent ] ,
@@ -215,52 +237,64 @@ export function cacheJobIndexKeys(filters: CacheJobIndexFilters): string[] {
215237 ] ;
216238
217239 return entries
218- . map ( ( [ kind , value ] ) => {
219- const normalized =
220- kind === "level"
221- ? normalizeLevelIndexValue ( value ?? "" )
222- : normalizeIndexValue ( value ?? "" ) ;
223- if ( ! normalized || normalized === "todos" || normalized === "all" ) {
224- return "" ;
225- }
226- return `scraper:jobs:${ kind } :${ normalized } ` ;
227- } )
228- . filter ( Boolean ) ;
240+ . map ( ( [ kind , value ] ) =>
241+ filterValues ( value )
242+ . map ( ( item ) => cacheJobIndexKey ( kind , item ) )
243+ . filter ( Boolean ) ,
244+ )
245+ . filter ( ( group ) => group . length > 0 ) ;
246+ }
247+
248+ export function cacheJobIndexKeys ( filters : CacheJobIndexFilters ) : string [ ] {
249+ return cacheJobIndexKeyGroups ( filters ) . flatMap ( ( group ) => group ) ;
229250}
230251
231252export async function cacheSearchJobIds (
232253 filters : CacheJobIndexFilters ,
233254) : Promise < string [ ] > {
234255 const client = await getCache ( ) ;
235256 const keywordKeys = keywordSearchKeys ( filters . keywords ?? [ ] ) ;
236- const filterKeys = cacheJobIndexKeys ( filters ) ;
257+ const tempKeys : string [ ] = [ ] ;
237258
238- if ( keywordKeys . length === 0 && filterKeys . length === 0 ) {
239- return await client . sMembers ( "scraper:jobs:index" ) ;
240- }
259+ const filterKeys = await Promise . all (
260+ cacheJobIndexKeyGroups ( filters ) . map ( async ( group ) => {
261+ if ( group . length === 1 ) return group [ 0 ] ;
241262
242- if ( keywordKeys . length === 0 ) {
243- if ( filterKeys . length === 1 ) return await client . sMembers ( filterKeys [ 0 ] ) ;
244- return ( await client . sendCommand ( [ "SINTER" , ...filterKeys ] ) ) as string [ ] ;
245- }
263+ const tempKey = `scraper:jobs:filter:${ randomUUID ( ) } ` ;
264+ tempKeys . push ( tempKey ) ;
265+ await client . sendCommand ( [ "SUNIONSTORE" , tempKey , ...group ] ) ;
266+ await client . expire ( tempKey , 30 ) ;
267+ return tempKey ;
268+ } ) ,
269+ ) ;
246270
247- if ( keywordKeys . length === 1 ) {
248- const keys = [ keywordKeys [ 0 ] , ...filterKeys ] ;
249- if ( keys . length === 1 ) return await client . sMembers ( keys [ 0 ] ) ;
250- return ( await client . sendCommand ( [ "SINTER" , ...keys ] ) ) as string [ ] ;
251- }
271+ try {
272+ if ( keywordKeys . length === 0 && filterKeys . length === 0 ) {
273+ return await client . sMembers ( "scraper:jobs:index" ) ;
274+ }
252275
253- const tempKey = `scraper:jobs:search:${ randomUUID ( ) } ` ;
276+ if ( keywordKeys . length === 0 ) {
277+ if ( filterKeys . length === 1 ) return await client . sMembers ( filterKeys [ 0 ] ) ;
278+ return ( await client . sendCommand ( [ "SINTER" , ...filterKeys ] ) ) as string [ ] ;
279+ }
280+
281+ if ( keywordKeys . length === 1 ) {
282+ const keys = [ keywordKeys [ 0 ] , ...filterKeys ] ;
283+ if ( keys . length === 1 ) return await client . sMembers ( keys [ 0 ] ) ;
284+ return ( await client . sendCommand ( [ "SINTER" , ...keys ] ) ) as string [ ] ;
285+ }
286+
287+ const tempKey = `scraper:jobs:search:${ randomUUID ( ) } ` ;
288+ tempKeys . push ( tempKey ) ;
254289
255- try {
256290 await client . sendCommand ( [ "SUNIONSTORE" , tempKey , ...keywordKeys ] ) ;
257291 await client . expire ( tempKey , 30 ) ;
258292
259293 const keys = [ tempKey , ...filterKeys ] ;
260294 if ( keys . length === 1 ) return await client . sMembers ( keys [ 0 ] ) ;
261295 return ( await client . sendCommand ( [ "SINTER" , ...keys ] ) ) as string [ ] ;
262296 } finally {
263- await client . del ( tempKey ) ;
297+ await Promise . all ( tempKeys . map ( ( key ) => client . del ( key ) ) ) ;
264298 }
265299}
266300
0 commit comments