From 1814dd5677ab713f8969a906de0e05bd5f6f6df5 Mon Sep 17 00:00:00 2001 From: Alexandre Caron Date: Wed, 24 May 2023 11:34:55 -0400 Subject: [PATCH 1/4] feat(SearchBar): add a way to invalidate the cache on setting change infra-geo-ouverte/igo2#928 --- .vscode/settings.json | 3 +++ angular.json | 3 ++- .../lib/search/search-bar/search-bar.component.ts | 13 ++++++++++++- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..2e2264550e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "angular.enable-strict-mode-prompt": false +} \ No newline at end of file diff --git a/angular.json b/angular.json index 8e6c50d143..e84b21ffe9 100644 --- a/angular.json +++ b/angular.json @@ -516,6 +516,7 @@ "cache": { "enabled": false, "environment": "all" - } + }, + "analytics": false } } diff --git a/packages/geo/src/lib/search/search-bar/search-bar.component.ts b/packages/geo/src/lib/search/search-bar/search-bar.component.ts index 8961076637..af8fb17f3b 100644 --- a/packages/geo/src/lib/search/search-bar/search-bar.component.ts +++ b/packages/geo/src/lib/search/search-bar/search-bar.component.ts @@ -23,6 +23,7 @@ import { SEARCH_TYPES } from '../shared/search.enums'; import { SearchResult, Research } from '../shared/search.interfaces'; import { SearchService } from '../shared/search.service'; import { SearchSourceService } from '../shared/search-source.service'; +import { globalCacheBusterNotifier } from 'ts-cacheable'; /** * Searchbar that triggers a research in all search sources enabled. @@ -144,6 +145,11 @@ export class SearchBarComponent implements OnInit, OnDestroy { @Input() pointerSummaryEnabled: boolean = false; @Input() searchResultsGeometryEnabled: boolean = false; + /** + * Workaround, to invalidate the cache due to mishandling of cache settings + */ + @Input() bustCacheOnSettingChange: boolean = false; + /** * When reverse coordinates status change */ @@ -333,8 +339,13 @@ export class SearchBarComponent implements OnInit, OnDestroy { } onSearchSettingsChange() { - this.doSearch(this.term); this.searchSettingsChange.emit(); + + if (this.bustCacheOnSettingChange) { + globalCacheBusterNotifier.next(); + } + + this.doSearch(this.term); this.handlePlaceholder(); } From d631557bc129b517cd8476ab560e61a71c95f5e4 Mon Sep 17 00:00:00 2001 From: Alexandre Caron Date: Wed, 24 May 2023 13:25:25 -0400 Subject: [PATCH 2/4] fix(ICherche): add a custom cache hash to account for http settings --- .../search/search-bar/search-bar.component.ts | 13 +--------- .../src/lib/search/shared/sources/icherche.ts | 25 +++++++++++++------ packages/utils/src/lib/cache.utils.ts | 10 ++++++++ packages/utils/src/lib/index.ts | 1 + 4 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 packages/utils/src/lib/cache.utils.ts diff --git a/packages/geo/src/lib/search/search-bar/search-bar.component.ts b/packages/geo/src/lib/search/search-bar/search-bar.component.ts index af8fb17f3b..8961076637 100644 --- a/packages/geo/src/lib/search/search-bar/search-bar.component.ts +++ b/packages/geo/src/lib/search/search-bar/search-bar.component.ts @@ -23,7 +23,6 @@ import { SEARCH_TYPES } from '../shared/search.enums'; import { SearchResult, Research } from '../shared/search.interfaces'; import { SearchService } from '../shared/search.service'; import { SearchSourceService } from '../shared/search-source.service'; -import { globalCacheBusterNotifier } from 'ts-cacheable'; /** * Searchbar that triggers a research in all search sources enabled. @@ -145,11 +144,6 @@ export class SearchBarComponent implements OnInit, OnDestroy { @Input() pointerSummaryEnabled: boolean = false; @Input() searchResultsGeometryEnabled: boolean = false; - /** - * Workaround, to invalidate the cache due to mishandling of cache settings - */ - @Input() bustCacheOnSettingChange: boolean = false; - /** * When reverse coordinates status change */ @@ -339,13 +333,8 @@ export class SearchBarComponent implements OnInit, OnDestroy { } onSearchSettingsChange() { - this.searchSettingsChange.emit(); - - if (this.bustCacheOnSettingChange) { - globalCacheBusterNotifier.next(); - } - this.doSearch(this.term); + this.searchSettingsChange.emit(); this.handlePlaceholder(); } diff --git a/packages/geo/src/lib/search/shared/sources/icherche.ts b/packages/geo/src/lib/search/shared/sources/icherche.ts index 55e17f223c..ac887a228b 100644 --- a/packages/geo/src/lib/search/shared/sources/icherche.ts +++ b/packages/geo/src/lib/search/shared/sources/icherche.ts @@ -6,7 +6,7 @@ import { map, catchError } from 'rxjs/operators'; import { AuthService } from '@igo2/auth'; import { LanguageService, StorageService } from '@igo2/core'; -import { ObjectUtils } from '@igo2/utils'; +import { ObjectUtils, customCacheHasher } from '@igo2/utils'; import pointOnFeature from '@turf/point-on-feature'; @@ -354,9 +354,6 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { * @param term Location name or keyword * @returns Observable of [] */ - @Cacheable({ - maxCacheCount: 20 - }) search( term: string, options?: TextSearchOptions @@ -367,6 +364,14 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { } this.options.params.page = params.get('page') || '1'; + return this.getSearch(term, params); + } + + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher, + }) + private getSearch(term: string, params: HttpParams): Observable[]> { return this.http.get(`${this.searchUrl}/geocode`, { params }).pipe( map((response: IChercheResponse) => this.extractResults(response, term)), catchError((err) => { @@ -378,7 +383,6 @@ export class IChercheSearchSource extends SearchSource implements TextSearch { }) ); } - private getAllowedTypes() { return this.http .get(`${this.searchUrl}/types`) @@ -767,9 +771,6 @@ export class IChercheReverseSearchSource extends SearchSource * @param distance Search raidus around lonLat * @returns Observable of [] */ - @Cacheable({ - maxCacheCount: 20 - }) reverseSearch( lonLat: [number, number], options?: ReverseSearchOptions @@ -778,6 +779,14 @@ export class IChercheReverseSearchSource extends SearchSource if (!params.get('type').length) { return of([]); } + return this.getReverseSearch(params); + } + + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher, + }) + private getReverseSearch(params: HttpParams): Observable[]> { return this.http.get(`${this.searchUrl}/locate`, { params }).pipe( map((response: IChercheReverseResponse) => { return this.extractResults(response); diff --git a/packages/utils/src/lib/cache.utils.ts b/packages/utils/src/lib/cache.utils.ts new file mode 100644 index 0000000000..95294ad947 --- /dev/null +++ b/packages/utils/src/lib/cache.utils.ts @@ -0,0 +1,10 @@ +import { HttpParams } from '@angular/common/http'; + +export function customCacheHasher(parameters: unknown[]): unknown[] { + return parameters.map((param) => { + if (param instanceof HttpParams) { + return param.toString(); + } + return param !== undefined ? JSON.parse(JSON.stringify(param)) : param; + }); +} diff --git a/packages/utils/src/lib/index.ts b/packages/utils/src/lib/index.ts index 609286ba7f..42424d9b74 100644 --- a/packages/utils/src/lib/index.ts +++ b/packages/utils/src/lib/index.ts @@ -1,4 +1,5 @@ export * from './base64'; +export * from './cache.utils'; export * from './clipboard'; export * from './change'; export * from './change.interface'; From 76a15f47038e32fbac2d13532a33898b623edbd9 Mon Sep 17 00:00:00 2001 From: Alexandre Caron Date: Fri, 8 Sep 2023 09:36:58 -0400 Subject: [PATCH 3/4] fix(Request): bust the cache on params changes. fix(OsrmDirection): route fix(Cadastre): search fix(iLayer): search fix(Nominatim): search fix(StoredQueries): search and reverseSearch --- .../osrm-directions-source.ts | 23 +++- .../src/lib/search/shared/sources/cadastre.ts | 15 ++- .../src/lib/search/shared/sources/ilayer.ts | 20 +++- .../lib/search/shared/sources/nominatim.ts | 12 +- .../search/shared/sources/storedqueries.ts | 104 ++++++++++-------- projects/igo2 | 1 + 6 files changed, 112 insertions(+), 63 deletions(-) create mode 160000 projects/igo2 diff --git a/packages/geo/src/lib/directions/directions-sources/osrm-directions-source.ts b/packages/geo/src/lib/directions/directions-sources/osrm-directions-source.ts index 3023ce0a2f..b50a61e1c5 100644 --- a/packages/geo/src/lib/directions/directions-sources/osrm-directions-source.ts +++ b/packages/geo/src/lib/directions/directions-sources/osrm-directions-source.ts @@ -5,7 +5,7 @@ import { map } from 'rxjs/operators'; import { Cacheable } from 'ts-cacheable'; -import { uuid } from '@igo2/utils'; +import { customCacheHasher, uuid } from '@igo2/utils'; import { ConfigService } from '@igo2/core'; import { Direction, DirectionOptions } from '../shared/directions.interface'; @@ -37,16 +37,27 @@ export class OsrmDirectionsSource extends DirectionsSource { return OsrmDirectionsSource._name; } + route( + coordinates: [number, number][], + directionsOptions: DirectionOptions = {} + ): Observable { + const directionsParams = this.getRouteParams(directionsOptions); + return this.getRoute(coordinates, directionsParams); + } + @Cacheable({ - maxCacheCount: 20 + maxCacheCount: 20, + cacheHasher: customCacheHasher }) - route(coordinates: [number, number][], directionsOptions: DirectionOptions = {}): Observable { - const directionsParams = this.getRouteParams(directionsOptions); + private getRoute( + coordinates: [number, number][], + params: HttpParams + ): Observable { return this.http .get(this.directionsUrl + coordinates.join(';'), { - params: directionsParams + params }) - .pipe(map(res => this.extractRoutesData(res))); + .pipe(map((res) => this.extractRoutesData(res))); } private extractRoutesData(response): Direction[] { diff --git a/packages/geo/src/lib/search/shared/sources/cadastre.ts b/packages/geo/src/lib/search/shared/sources/cadastre.ts index f46947ac61..07f7fa0cc9 100644 --- a/packages/geo/src/lib/search/shared/sources/cadastre.ts +++ b/packages/geo/src/lib/search/shared/sources/cadastre.ts @@ -16,6 +16,7 @@ import { LanguageService, StorageService } from '@igo2/core'; import { computeTermSimilarity } from '../search.utils'; import { Cacheable } from 'ts-cacheable'; import { GeoJsonGeometryTypes } from 'geojson'; +import { customCacheHasher } from '@igo2/utils'; /** * Cadastre search source @@ -57,9 +58,6 @@ export class CadastreSearchSource extends SearchSource implements TextSearch { * @param term Place name * @returns Observable of [] */ - @Cacheable({ - maxCacheCount: 20 - }) search( term: string | undefined, options?: TextSearchOptions @@ -72,6 +70,17 @@ export class CadastreSearchSource extends SearchSource implements TextSearch { if (!params.get('numero') || !params.get('numero').match(/^[0-9,]+$/g)) { return of([]); } + return this.getCadastre(term, params); + } + + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher + }) + private getCadastre( + term: string, + params: HttpParams + ): Observable[]> { return this.http .get(this.searchUrl, { params, responseType: 'text' }) .pipe(map((response: string) => this.extractResults(response, term))); diff --git a/packages/geo/src/lib/search/shared/sources/ilayer.ts b/packages/geo/src/lib/search/shared/sources/ilayer.ts index 3dbec8521d..ee8ff3069d 100644 --- a/packages/geo/src/lib/search/shared/sources/ilayer.ts +++ b/packages/geo/src/lib/search/shared/sources/ilayer.ts @@ -5,7 +5,7 @@ import { Observable, BehaviorSubject, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { LanguageService, StorageService } from '@igo2/core'; -import { ObjectUtils } from '@igo2/utils'; +import { customCacheHasher, ObjectUtils } from '@igo2/utils'; import { getResolutionFromScale } from '../../../map/shared/map.utils'; import { LAYER } from '../../../layer'; @@ -204,10 +204,6 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { * @param term Layer name or keyword * @returns Observable of [] */ - - @Cacheable({ - maxCacheCount: 20 - }) search( term: string | undefined, options?: TextSearchOptions @@ -217,11 +213,23 @@ export class ILayerSearchSource extends SearchSource implements TextSearch { return of([]); } this.options.params.page = params.get('page') || '1'; + return this.getSearch(term, params); + } + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher + }) + private getSearch( + term: string, + params: HttpParams + ): Observable[]> { return this.http .get(this.searchUrl, { params }) .pipe( - map((response: ILayerServiceResponse) => this.extractResults(response, term)) + map((response: ILayerServiceResponse) => + this.extractResults(response, term) + ) ); } diff --git a/packages/geo/src/lib/search/shared/sources/nominatim.ts b/packages/geo/src/lib/search/shared/sources/nominatim.ts index 69d877ed83..0fc47d6f63 100644 --- a/packages/geo/src/lib/search/shared/sources/nominatim.ts +++ b/packages/geo/src/lib/search/shared/sources/nominatim.ts @@ -13,6 +13,7 @@ import { SearchSourceOptions, TextSearchOptions } from './source.interfaces'; import { NominatimData } from './nominatim.interfaces'; import { computeTermSimilarity } from '../search.utils'; import { Cacheable } from 'ts-cacheable'; +import { customCacheHasher } from '@igo2/utils'; /** * Nominatim search source @@ -142,9 +143,6 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { * @param term Place name * @returns Observable of [] */ - @Cacheable({ - maxCacheCount: 20 - }) search( term: string | undefined, options?: TextSearchOptions @@ -153,6 +151,14 @@ export class NominatimSearchSource extends SearchSource implements TextSearch { if (!params.get('q')) { return of([]); } + return this.getSearch(term, params); + } + + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher, + }) + private getSearch(term: string, params: HttpParams): Observable[]> { return this.http .get(this.searchUrl, { params }) .pipe(map((response: NominatimData[]) => this.extractResults(response, term))); diff --git a/packages/geo/src/lib/search/shared/sources/storedqueries.ts b/packages/geo/src/lib/search/shared/sources/storedqueries.ts index 6be8dece23..cea60baeea 100644 --- a/packages/geo/src/lib/search/shared/sources/storedqueries.ts +++ b/packages/geo/src/lib/search/shared/sources/storedqueries.ts @@ -4,7 +4,7 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { ObjectUtils } from '@igo2/utils'; +import { ObjectUtils, customCacheHasher } from '@igo2/utils'; import { FEATURE, Feature } from '../../../feature'; import { SearchResult } from '../search.interfaces'; @@ -164,10 +164,6 @@ export class StoredQueriesSearchSource extends SearchSource * @param term Location name or keyword * @returns Observable of [] */ - - @Cacheable({ - maxCacheCount: 20 - }) search( term: string, options?: TextSearchOptions @@ -183,38 +179,56 @@ export class StoredQueriesSearchSource extends SearchSource this.options.params = this.options.params ? this.options.params : {}; this.options.params.page = options.page ? String(options.page) : '1'; - if ( - new RegExp('.*?gml.*?', 'i').test(this.storedQueriesOptions.outputformat) - ) { - return this.http - .get(this.searchUrl, { params, responseType: 'text' }) - .pipe( - map(response => { - let resultArray = this.extractResults(this.extractWFSData(response), term); + return this.getSearch(term, params); + } + + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher + }) + private getSearch( + term: string, + params: HttpParams + ): Observable[]> { + return new RegExp('.*?gml.*?', 'i').test( + this.storedQueriesOptions.outputformat + ) + ? this.http.get(this.searchUrl, { params, responseType: 'text' }).pipe( + map((response) => { + let resultArray = this.extractResults( + this.extractWFSData(response), + term + ); resultArray.sort((a, b) => - (a.meta.score > b.meta.score) ? 1 : - (a.meta.score === b.meta.score) ? ((a.meta.titleHtml < b.meta.titleHtml) ? 1 : -1) : -1); + a.meta.score > b.meta.score + ? 1 + : a.meta.score === b.meta.score + ? a.meta.titleHtml < b.meta.titleHtml + ? 1 + : -1 + : -1 + ); resultArray.reverse(); if (resultArray.length > Number(this.options.params.limit)) { - const idxEnd = Number(this.options.params.limit) * Number(this.options.params.page); + const idxEnd = + Number(this.options.params.limit) * + Number(this.options.params.page); const resultTotLenght = resultArray.length; resultArray = resultArray.slice(0, idxEnd); if (idxEnd < resultTotLenght) { - resultArray[resultArray.length - 1 ].meta.nextPage = true; + resultArray[resultArray.length - 1].meta.nextPage = true; } else { - resultArray[resultArray.length - 1 ].meta.nextPage = false; + resultArray[resultArray.length - 1].meta.nextPage = false; } } return resultArray; }) + ) + : this.http.get(this.searchUrl, { params }).pipe( + map((response) => { + return this.extractResults(this.extractWFSData(response), term); + }) ); - } else { - return this.http.get(this.searchUrl, { params }).pipe( - map(response => { - return this.extractResults(this.extractWFSData(response), term); - }) - ); - } } private getFormatFromOptions() { @@ -432,32 +446,32 @@ export class StoredQueriesReverseSearchSource extends SearchSource * @param distance Search raidus around lonLat * @returns Observable of [] */ - @Cacheable({ - maxCacheCount: 20 - }) reverseSearch( lonLat: [number, number], options?: ReverseSearchOptions ): Observable[]> { const params = this.computeRequestParams(lonLat, options || {}); + return this.getReverseSearch(params); + } - if ( - new RegExp('.*?gml.*?', 'i').test(this.storedQueriesOptions.outputformat) - ) { - return this.http - .get(this.searchUrl, { params, responseType: 'text' }) - .pipe( - map(response => { - return this.extractResults(this.extractWFSData(response)); - }) - ); - } else { - return this.http.get(this.searchUrl, { params }).pipe( - map(response => { - return this.extractResults(this.extractWFSData(response)); - }) - ); - } + @Cacheable({ + maxCacheCount: 20, + cacheHasher: customCacheHasher + }) + private getReverseSearch( + params: HttpParams + ): Observable[]> { + const isGml = new RegExp('.*?gml.*?', 'i').test( + this.storedQueriesOptions.outputformat + ); + const request$ = isGml + ? this.http.get(this.searchUrl, { params, responseType: 'text' }) + : this.http.get(this.searchUrl, { params }); + return request$.pipe( + map((response) => { + return this.extractResults(this.extractWFSData(response)); + }) + ); } private getFormatFromOptions() { diff --git a/projects/igo2 b/projects/igo2 new file mode 160000 index 0000000000..d2d1b46aba --- /dev/null +++ b/projects/igo2 @@ -0,0 +1 @@ +Subproject commit d2d1b46aba8253dddc848534fcba5ce223c26c7d From abbb108da9b53aa88a30148b92b0757ce1ba51d0 Mon Sep 17 00:00:00 2001 From: Alexandre Caron Date: Wed, 13 Sep 2023 09:11:56 -0400 Subject: [PATCH 4/4] remove projects --- projects/igo2 | 1 - 1 file changed, 1 deletion(-) delete mode 160000 projects/igo2 diff --git a/projects/igo2 b/projects/igo2 deleted file mode 160000 index d2d1b46aba..0000000000 --- a/projects/igo2 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d2d1b46aba8253dddc848534fcba5ce223c26c7d