@@ -9,7 +9,17 @@ import { lineString as turfLineString } from '@turf/helpers';
99
1010import { saveAndUpdateAllNodes , saveAllNodesToCache } from '../../nodes/NodeCollectionUtils' ;
1111
12- import { recreateCache } from '../dbToCache' ;
12+ import {
13+ recreateCache ,
14+ loadAndSaveDataSourcesToCache ,
15+ loadAndSaveAgenciesToCache ,
16+ loadAndSaveServicesToCache ,
17+ loadAndSaveScenariosToCache ,
18+ loadAndSaveLinesToCache ,
19+ loadAndSaveLinesByIdsToCache ,
20+ loadAndSaveNodesToCache ,
21+ loadAndSavePathsToCache
22+ } from '../dbToCache' ;
1323import { EventManagerMock } from 'chaire-lib-common/lib/test' ;
1424import transitLinesDbQueries from '../../../models/db/transitLines.db.queries' ;
1525import transitNodesDbQueries from '../../../models/db/transitNodes.db.queries' ;
@@ -19,6 +29,7 @@ import transitAgenciesDbQueries from '../../../models/db/transitAgencies.db.quer
1929import transitServicesDbQueries from '../../../models/db/transitServices.db.queries' ;
2030import dataSourcesDbQueries from 'chaire-lib-backend/lib/models/db/dataSources.db.queries' ;
2131import placesDbQueries from '../../../models/db/places.db.queries' ;
32+ import Line from 'transition-common/lib/services/line/Line' ;
2233
2334//serviceLocator.socketEventManager = new EventEmitter();
2435
@@ -167,7 +178,6 @@ const lineAttributes = {
167178 category : 'C+' as const ,
168179 allow_same_line_transfers : false ,
169180 color : '#ffffff' ,
170- description : null ,
171181 is_autonomous : false ,
172182 scheduleByServiceId : { } ,
173183 data : {
@@ -302,6 +312,274 @@ jest.mock('../../../models/capnpCache/transitPaths.cache.queries', () => {
302312 }
303313} ) ;
304314
315+ describe ( 'loadAndSaveDataSourcesToCache' , ( ) => {
316+ beforeEach ( ( ) => {
317+ jest . clearAllMocks ( ) ;
318+ } ) ;
319+
320+ test . each ( [
321+ { cachePathDirectory : undefined , expectedPath : undefined } ,
322+ { cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
323+ ] ) ( 'should load and save data sources to cache with cachePathDirectory=$cachePathDirectory' , async ( { cachePathDirectory, expectedPath } ) => {
324+ await loadAndSaveDataSourcesToCache ( { cachePathDirectory } ) ;
325+ expect ( mockedDataSourceDbCollection ) . toHaveBeenCalledTimes ( 1 ) ;
326+ expect ( mockedDsToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
327+ _features : [ expect . objectContaining ( { _attributes : expect . objectContaining ( dataSourceAttributes ) } ) ]
328+ } ) , expectedPath ) ;
329+ expect ( mockedDsToCache ) . toHaveBeenCalledTimes ( 1 ) ;
330+ } ) ;
331+ } ) ;
332+
333+ describe ( 'loadAndSaveAgenciesToCache' , ( ) => {
334+ beforeEach ( ( ) => {
335+ jest . clearAllMocks ( ) ;
336+ } ) ;
337+
338+ test . each ( [
339+ { cachePathDirectory : undefined , expectedPath : undefined } ,
340+ { cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
341+ ] ) ( 'should load and save agencies to cache with cachePathDirectory=$cachePathDirectory' , async ( { cachePathDirectory, expectedPath } ) => {
342+ await loadAndSaveAgenciesToCache ( cachePathDirectory !== undefined ? { cachePathDirectory } : undefined ) ;
343+ expect ( mockedAgencyDbCollection ) . toHaveBeenCalledTimes ( 1 ) ;
344+ expect ( mockedAgToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
345+ _features : [ expect . objectContaining ( { _attributes : expect . objectContaining ( agencyAttributes ) } ) ]
346+ } ) , expectedPath ) ;
347+ expect ( mockedAgToCache ) . toHaveBeenCalledTimes ( 1 ) ;
348+ } ) ;
349+ } ) ;
350+
351+ describe ( 'loadAndSaveServicesToCache' , ( ) => {
352+ beforeEach ( ( ) => {
353+ jest . clearAllMocks ( ) ;
354+ } ) ;
355+
356+ test . each ( [
357+ { cachePathDirectory : undefined , expectedPath : undefined } ,
358+ { cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
359+ ] ) ( 'should load and save services to cache with cachePathDirectory=$cachePathDirectory' , async ( { cachePathDirectory, expectedPath } ) => {
360+ await loadAndSaveServicesToCache ( cachePathDirectory !== undefined ? { cachePathDirectory } : undefined ) ;
361+ expect ( mockedServiceDbCollection ) . toHaveBeenCalledTimes ( 1 ) ;
362+ expect ( mockedServiceToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
363+ _features : [ expect . objectContaining ( { _attributes : expect . objectContaining ( serviceAttributes ) } ) ]
364+ } ) , expectedPath ) ;
365+ expect ( mockedServiceToCache ) . toHaveBeenCalledTimes ( 1 ) ;
366+ } ) ;
367+ } ) ;
368+
369+ describe ( 'loadAndSaveScenariosToCache' , ( ) => {
370+ beforeEach ( ( ) => {
371+ jest . clearAllMocks ( ) ;
372+ } ) ;
373+
374+ test . each ( [
375+ { cachePathDirectory : undefined , expectedPath : undefined } ,
376+ { cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
377+ ] ) ( 'should load and save scenarios to cache with cachePathDirectory=$cachePathDirectory' , async ( { cachePathDirectory, expectedPath } ) => {
378+ await loadAndSaveScenariosToCache ( cachePathDirectory !== undefined ? { cachePathDirectory } : undefined ) ;
379+ expect ( mockedScenarioDbCollection ) . toHaveBeenCalledTimes ( 1 ) ;
380+ expect ( mockedScenariosToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
381+ _features : [ expect . objectContaining ( { _attributes : expect . objectContaining ( scenarioAttributes ) } ) ]
382+ } ) , expectedPath ) ;
383+ expect ( mockedScenariosToCache ) . toHaveBeenCalledTimes ( 1 ) ;
384+ } ) ;
385+ } ) ;
386+
387+ describe ( 'loadAndSaveLinesToCache' , ( ) => {
388+ beforeEach ( ( ) => {
389+ jest . clearAllMocks ( ) ;
390+ } ) ;
391+
392+ test . each ( [
393+ { saveIndividualLines : false } ,
394+ { saveIndividualLines : true }
395+ ] ) ( 'should load and save lines collection to cache with saveIndividualLines=$saveIndividualLines' , async ( { saveIndividualLines } ) => {
396+ await loadAndSaveLinesToCache ( { saveIndividualLines } ) ;
397+ // collection should be called with empty parameters
398+ expect ( mockedLineDbCollection ) . toHaveBeenCalledWith ( ) ;
399+ expect ( mockedLinesToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
400+ _features : [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ]
401+ } ) , undefined ) ;
402+ expect ( mockedLinesToCache ) . toHaveBeenCalledTimes ( 1 ) ;
403+ if ( ! saveIndividualLines ) {
404+ expect ( mockedLinesWithSchedules ) . not . toHaveBeenCalled ( ) ;
405+ expect ( mockedObjectsToCache ) . not . toHaveBeenCalled ( ) ;
406+ } else {
407+ expect ( mockedLinesWithSchedules ) . toHaveBeenCalledWith ( [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ] ) ;
408+ expect ( mockedObjectsToCache ) . toHaveBeenCalledWith (
409+ [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ] ,
410+ undefined
411+ ) ;
412+ }
413+ } ) ;
414+
415+ test . each ( [
416+ { saveIndividualLines : false , cachePathDirectory : undefined , expectedPath : undefined } ,
417+ { saveIndividualLines : true , cachePathDirectory : undefined , expectedPath : undefined } ,
418+ { saveIndividualLines : true , cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
419+ ] ) ( 'should load and save lines with cachePathDirectory and saveIndividualLines=$saveIndividualLines' , async ( { saveIndividualLines, cachePathDirectory, expectedPath } ) => {
420+ const params : any = { saveIndividualLines } ;
421+ if ( cachePathDirectory !== undefined ) {
422+ params . cachePathDirectory = cachePathDirectory ;
423+ }
424+ await loadAndSaveLinesToCache ( params ) ;
425+ // collection should be called with empty parameters
426+ expect ( mockedLineDbCollection ) . toHaveBeenCalledWith ( ) ;
427+ expect ( mockedLinesToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
428+ _features : [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ]
429+ } ) , expectedPath ) ;
430+ if ( saveIndividualLines ) {
431+ expect ( mockedObjectsToCache ) . toHaveBeenCalledWith (
432+ [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ] ,
433+ expectedPath
434+ ) ;
435+ } else {
436+ expect ( mockedObjectsToCache ) . not . toHaveBeenCalled ( ) ;
437+ }
438+ } ) ;
439+
440+ test ( 'should save lines in chunks when collection is large' , async ( ) => {
441+ // Prepare test data with many lines
442+ const lineIds = Array . from ( { length : 250 } , ( ) => uuidV4 ( ) ) ;
443+ const linesAttributes = lineIds . map ( ( lineId ) => ( { ...lineAttributes , id : lineId } ) ) ;
444+ const lines = linesAttributes . map ( ( attributes ) => new Line ( attributes , false ) ) ;
445+ mockedLineDbCollection . mockResolvedValueOnce ( linesAttributes ) ;
446+
447+ // Save with individual lines
448+ await loadAndSaveLinesToCache ( { saveIndividualLines : true } ) ;
449+ expect ( mockedLineDbCollection ) . toHaveBeenCalledWith ( ) ;
450+ // Should be called 3 times: 100 + 100 + 50
451+ expect ( mockedLinesWithSchedules ) . toHaveBeenCalledTimes ( 3 ) ;
452+ // Verify the calls were made with correct chunks (100 + 100 + 50)
453+ expect ( mockedLinesWithSchedules ) . toHaveBeenNthCalledWith ( 1 , lines . slice ( 0 , 100 ) ) ;
454+ expect ( mockedLinesWithSchedules ) . toHaveBeenNthCalledWith ( 2 , lines . slice ( 100 , 200 ) ) ;
455+ expect ( mockedLinesWithSchedules ) . toHaveBeenNthCalledWith ( 3 , lines . slice ( 200 , 250 ) ) ;
456+ expect ( mockedObjectsToCache ) . toHaveBeenCalledTimes ( 3 ) ;
457+ } ) ;
458+ } ) ;
459+
460+ describe ( 'loadAndSaveLinesByIdsToCache' , ( ) => {
461+ beforeEach ( ( ) => {
462+ jest . clearAllMocks ( ) ;
463+ } ) ;
464+
465+ test . each ( [
466+ { cachePathDirectory : undefined , expectedPath : undefined } ,
467+ { cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
468+ ] ) ( 'should load and save specific lines by IDs to cache with cachePathDirectory=$cachePathDirectory' , async ( { cachePathDirectory, expectedPath } ) => {
469+ const lineIds = [ uuidV4 ( ) , uuidV4 ( ) ] ;
470+ const params : any = { lineIds } ;
471+ if ( cachePathDirectory !== undefined ) {
472+ params . cachePathDirectory = cachePathDirectory ;
473+ }
474+ await loadAndSaveLinesByIdsToCache ( params ) ;
475+ expect ( mockedLineDbCollection ) . toHaveBeenCalledWith ( lineIds ) ;
476+ expect ( mockedLinesWithSchedules ) . toHaveBeenCalledWith ( [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ] ) ;
477+ expect ( mockedObjectsToCache ) . toHaveBeenCalledWith (
478+ [ expect . objectContaining ( { _attributes : expect . objectContaining ( lineAttributes ) } ) ] ,
479+ expectedPath
480+ ) ;
481+ } ) ;
482+
483+ test ( 'should not save anything when lineIds is empty' , async ( ) => {
484+ await loadAndSaveLinesByIdsToCache ( { lineIds : [ ] , cachePathDirectory : undefined } ) ;
485+ expect ( mockedLineDbCollection ) . not . toHaveBeenCalled ( ) ;
486+ expect ( mockedLinesWithSchedules ) . not . toHaveBeenCalled ( ) ;
487+ expect ( mockedObjectsToCache ) . not . toHaveBeenCalled ( ) ;
488+ } ) ;
489+
490+ test ( 'should save lines in chunks when many lineIds are provided' , async ( ) => {
491+ // Prepare test data with many lines
492+ const lineIds = Array . from ( { length : 250 } , ( ) => uuidV4 ( ) ) ;
493+ const linesAttributes = lineIds . map ( ( lineId ) => ( { ...lineAttributes , id : lineId } ) ) ;
494+ const lines = linesAttributes . map ( ( attributes ) => new Line ( attributes , false ) ) ;
495+ mockedLineDbCollection . mockResolvedValueOnce ( linesAttributes ) ;
496+
497+ await loadAndSaveLinesByIdsToCache ( { lineIds, cachePathDirectory : undefined } ) ;
498+ expect ( mockedLineDbCollection ) . toHaveBeenCalledWith ( lineIds ) ;
499+ // Should be called 3 times: 100 + 100 + 50
500+ expect ( mockedLinesWithSchedules ) . toHaveBeenCalledTimes ( 3 ) ;
501+ // Verify the calls were made with correct chunks (100 + 100 + 50)
502+ expect ( mockedLinesWithSchedules ) . toHaveBeenNthCalledWith ( 1 , lines . slice ( 0 , 100 ) ) ;
503+ expect ( mockedLinesWithSchedules ) . toHaveBeenNthCalledWith ( 2 , lines . slice ( 100 , 200 ) ) ;
504+ expect ( mockedLinesWithSchedules ) . toHaveBeenNthCalledWith ( 3 , lines . slice ( 200 , 250 ) ) ;
505+ expect ( mockedObjectsToCache ) . toHaveBeenCalledTimes ( 3 ) ;
506+ } ) ;
507+ } ) ;
508+
509+ describe ( 'loadAndSaveNodesToCache' , ( ) => {
510+ beforeEach ( ( ) => {
511+ jest . clearAllMocks ( ) ;
512+ } ) ;
513+
514+ test . each ( [
515+ { refreshTransferrableNodes : false , cachePathDirectory : undefined , expectedPath : undefined } ,
516+ { refreshTransferrableNodes : true , cachePathDirectory : undefined , expectedPath : undefined } ,
517+ { refreshTransferrableNodes : false , cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
518+ ] ) ( 'should load and save nodes to cache with refreshTransferrableNodes=$refreshTransferrableNodes and cachePathDirectory=$cachePathDirectory' , async ( { refreshTransferrableNodes, cachePathDirectory, expectedPath } ) => {
519+ const params : any = { refreshTransferrableNodes } ;
520+ if ( cachePathDirectory !== undefined ) {
521+ params . cachePathDirectory = cachePathDirectory ;
522+ }
523+ await loadAndSaveNodesToCache ( params ) ;
524+ expect ( mockedNodesToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
525+ _features : [ expect . objectContaining ( {
526+ type : 'Feature' as const ,
527+ properties : nodeAttributes ,
528+ geometry : nodeGeography
529+ } ) ]
530+ } ) , expectedPath ) ;
531+ if ( refreshTransferrableNodes ) {
532+ expect ( mockedSaveAndUpdateAllNodes ) . toHaveBeenCalledTimes ( 1 ) ;
533+ expect ( mockedSaveAllNodesToCache ) . not . toHaveBeenCalled ( ) ;
534+ } else {
535+ expect ( mockedSaveAndUpdateAllNodes ) . not . toHaveBeenCalled ( ) ;
536+ expect ( mockedSaveAllNodesToCache ) . toHaveBeenLastCalledWith (
537+ expect . anything ( ) ,
538+ expect . anything ( ) ,
539+ expectedPath
540+ ) ;
541+ }
542+ } ) ;
543+
544+ test ( 'should load and save nodes to cache without parameters' , async ( ) => {
545+ await loadAndSaveNodesToCache ( ) ;
546+ expect ( mockedNodesToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
547+ _features : [ expect . objectContaining ( {
548+ type : 'Feature' as const ,
549+ properties : nodeAttributes ,
550+ geometry : nodeGeography
551+ } ) ]
552+ } ) , undefined ) ;
553+ expect ( mockedSaveAllNodesToCache ) . toHaveBeenCalledTimes ( 1 ) ;
554+ expect ( mockedSaveAndUpdateAllNodes ) . not . toHaveBeenCalled ( ) ;
555+ } ) ;
556+ } ) ;
557+
558+ describe ( 'loadAndSavePathsToCache' , ( ) => {
559+ beforeEach ( ( ) => {
560+ jest . clearAllMocks ( ) ;
561+ } ) ;
562+
563+ test . each ( [
564+ { cachePathDirectory : undefined , expectedPath : undefined } ,
565+ { cachePathDirectory : '/custom/cache/path' , expectedPath : '/custom/cache/path' }
566+ ] ) ( 'should load and save paths to cache with cachePathDirectory=$cachePathDirectory' , async ( { cachePathDirectory, expectedPath } ) => {
567+ const params : any = { } ;
568+ if ( cachePathDirectory !== undefined ) {
569+ params . cachePathDirectory = cachePathDirectory ;
570+ }
571+ await loadAndSavePathsToCache ( params ) ;
572+ expect ( mockedPathToCache ) . toHaveBeenCalledWith ( expect . objectContaining ( {
573+ _features : [ expect . objectContaining ( {
574+ type : 'Feature' as const ,
575+ properties : pathAttributes ,
576+ geometry : pathGeography
577+ } ) ]
578+ } ) , expectedPath ) ;
579+ expect ( mockedPathToCache ) . toHaveBeenCalledTimes ( 1 ) ;
580+ } ) ;
581+ } ) ;
582+
305583describe ( 'Recreate cache' , ( ) => {
306584 beforeEach ( ( ) => {
307585 jest . clearAllMocks ( ) ;
0 commit comments