Cache category search results
And abort ongoing searches when there's a new query
This commit is contained in:
@@ -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
|
// Sort by distance from center
|
||||||
pois = pois
|
pois = pois
|
||||||
|
|||||||
@@ -77,10 +77,23 @@ out center;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCategoryPois(bounds, categoryId) {
|
async getCategoryPois(bounds, categoryId, lat, lon) {
|
||||||
const category = getCategoryById(categoryId);
|
const category = getCategoryById(categoryId);
|
||||||
if (!category || !bounds) return [];
|
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;
|
const { minLat, minLon, maxLat, maxLon } = bounds;
|
||||||
|
|
||||||
// Build the query parts for each filter string and type
|
// Build the query parts for each filter string and type
|
||||||
@@ -104,16 +117,25 @@ out center;
|
|||||||
out center;
|
out center;
|
||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
// No caching for now as bounds change frequently
|
|
||||||
const url = `${this.settings.overpassApi}?data=${encodeURIComponent(query)}`;
|
const url = `${this.settings.overpassApi}?data=${encodeURIComponent(query)}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await this.fetchWithRetry(url);
|
const res = await this.fetchWithRetry(url, { signal });
|
||||||
if (!res.ok) throw new Error('Overpass request failed');
|
if (!res.ok) throw new Error('Overpass request failed');
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
const results = data.elements.map(this.normalizePoi);
|
const results = data.elements.map(this.normalizePoi);
|
||||||
|
|
||||||
|
if (queryKey) {
|
||||||
|
this.lastQueryKey = queryKey;
|
||||||
|
this.cachedResults = results;
|
||||||
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (e.name === 'AbortError') {
|
||||||
|
console.debug('Category search aborted');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
console.error('Category search failed', e);
|
console.error('Category search failed', e);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -251,4 +251,45 @@ module('Unit | Service | osm', function (hooks) {
|
|||||||
[30, 30],
|
[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'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user