diff --git a/app/routes/search.js b/app/routes/search.js index b11d3a9..a1261a6 100644 --- a/app/routes/search.js +++ b/app/routes/search.js @@ -42,7 +42,7 @@ export default class SearchRoute extends Route { }; } - pois = await this.osm.getCategoryPois(bounds, params.category); + pois = await this.osm.getCategoryPois(bounds, params.category, lat, lon); // Sort by distance from center pois = pois diff --git a/app/services/osm.js b/app/services/osm.js index 48209da..f7c37c2 100644 --- a/app/services/osm.js +++ b/app/services/osm.js @@ -77,10 +77,23 @@ out center; } } - async getCategoryPois(bounds, categoryId) { + async getCategoryPois(bounds, categoryId, lat, lon) { const category = getCategoryById(categoryId); if (!category || !bounds) return []; + const queryKey = lat && lon ? `cat:${categoryId}:${lat}:${lon}` : null; + + if (queryKey && this.lastQueryKey === queryKey && this.cachedResults) { + console.debug('Returning cached category results for:', queryKey); + return this.cachedResults; + } + + if (this.controller) { + this.controller.abort(); + } + this.controller = new AbortController(); + const signal = this.controller.signal; + const { minLat, minLon, maxLat, maxLon } = bounds; // Build the query parts for each filter string and type @@ -104,16 +117,25 @@ out center; out center; `.trim(); - // No caching for now as bounds change frequently const url = `${this.settings.overpassApi}?data=${encodeURIComponent(query)}`; try { - const res = await this.fetchWithRetry(url); + const res = await this.fetchWithRetry(url, { signal }); if (!res.ok) throw new Error('Overpass request failed'); const data = await res.json(); const results = data.elements.map(this.normalizePoi); + + if (queryKey) { + this.lastQueryKey = queryKey; + this.cachedResults = results; + } + return results; } catch (e) { + if (e.name === 'AbortError') { + console.debug('Category search aborted'); + return []; + } console.error('Category search failed', e); return []; } diff --git a/tests/unit/services/osm-test.js b/tests/unit/services/osm-test.js index b106c81..74c7b3a 100644 --- a/tests/unit/services/osm-test.js +++ b/tests/unit/services/osm-test.js @@ -251,4 +251,45 @@ module('Unit | Service | osm', function (hooks) { [30, 30], ]); }); + + test('getCategoryPois uses cache when lat/lon matches', async function (assert) { + let service = this.owner.lookup('service:osm'); + + // Mock settings + service.settings = { overpassApi: 'http://test-api' }; + + // Mock fetchWithRetry + let fetchCount = 0; + service.fetchWithRetry = async () => { + fetchCount++; + return { + ok: true, + json: async () => ({ + elements: [{ id: 1, type: 'node', tags: { name: 'Test' } }], + }), + }; + }; + + const bounds = { minLat: 0, minLon: 0, maxLat: 1, maxLon: 1 }; + + // First call - should fetch + await service.getCategoryPois(bounds, 'restaurants', 52.5, 13.4); + assert.strictEqual(fetchCount, 1, 'First call should trigger fetch'); + + // Second call with same lat/lon - should cache + await service.getCategoryPois(bounds, 'restaurants', 52.5, 13.4); + assert.strictEqual( + fetchCount, + 1, + 'Second call with same lat/lon should use cache' + ); + + // Third call with diff lat/lon - should fetch + await service.getCategoryPois(bounds, 'restaurants', 52.6, 13.5); + assert.strictEqual( + fetchCount, + 2, + 'Call with different lat/lon should trigger fetch' + ); + }); });