diff --git a/app/routes/place.js b/app/routes/place.js index efc5231..5742974 100644 --- a/app/routes/place.js +++ b/app/routes/place.js @@ -9,25 +9,47 @@ export default class PlaceRoute extends Route { async model(params) { const id = params.place_id; + let type, osmId; + let isExplicitOsm = false; + if ( id.startsWith('osm:node:') || id.startsWith('osm:way:') || id.startsWith('osm:relation:') ) { - const [, type, osmId] = id.split(':'); + isExplicitOsm = true; + [, type, osmId] = id.split(':'); console.debug(`Fetching explicit OSM ${type}:`, osmId); - return this.loadOsmPlace(osmId, type); + } + + let backgroundFetchPromise = null; + if (isExplicitOsm) { + backgroundFetchPromise = this.loadOsmPlace(osmId, type); } await this.waitForSync(); - let bookmark = this.storage.findPlaceById(id); + let lookupId = isExplicitOsm ? osmId : id; + let bookmark = this.storage.findPlaceById(lookupId); + + // Ensure type matches if we are looking up by osmId + if (bookmark && isExplicitOsm && bookmark.osmType !== type) { + bookmark = null; // Type mismatch, not the same OSM object + } if (bookmark) { console.debug('Found in bookmarks:', bookmark.title); return bookmark; } + if (isExplicitOsm) { + console.debug( + `Not in bookmarks, using explicitly fetched OSM ${type}:`, + osmId + ); + return await backgroundFetchPromise; + } + console.warn('Not in bookmarks:', id); return null; } @@ -119,14 +141,14 @@ export default class PlaceRoute extends Route { } serialize(model) { - // If the model is a saved bookmark, use its ID - if (model.id) { - return { place_id: model.id }; - } - // If it's an OSM POI, use the explicit format + // If it's an OSM POI, use the explicit format first if (model.osmId && model.osmType) { return { place_id: `osm:${model.osmType}:${model.osmId}` }; } + // If the model is a saved bookmark (and not OSM, e.g. custom place), use its ID + if (model.id) { + return { place_id: model.id }; + } // Fallback return { place_id: model.osmId }; } diff --git a/app/services/osm.js b/app/services/osm.js index e265178..5d42b6d 100644 --- a/app/services/osm.js +++ b/app/services/osm.js @@ -8,6 +8,7 @@ export default class OsmService extends Service { controller = null; cachedResults = null; lastQueryKey = null; + cachedPlaces = new Map(); cancelAll() { if (this.controller) { @@ -232,6 +233,13 @@ out center; async fetchOsmObject(osmId, osmType) { if (!osmId || !osmType) return null; + const cacheKey = `${osmType}:${osmId}`; + const cached = this.cachedPlaces.get(cacheKey); + if (cached && Date.now() - cached.timestamp < 10000) { + console.debug(`Using in-memory cached OSM object for ${cacheKey}`); + return cached.data; + } + let url; if (osmType === 'node') { url = `https://www.openstreetmap.org/api/0.6/node/${osmId}.json`; @@ -253,8 +261,25 @@ out center; } throw new Error(`OSM API request failed: ${res.status}`); } + const data = await res.json(); - return this.normalizeOsmApiData(data.elements, osmId, osmType); + const normalizedData = this.normalizeOsmApiData( + data.elements, + osmId, + osmType + ); + + this.cachedPlaces.set(cacheKey, { + data: normalizedData, + timestamp: Date.now(), + }); + + // Cleanup cache entry automatically after 10 seconds + setTimeout(() => { + this.cachedPlaces.delete(cacheKey); + }, 10000); + + return normalizedData; } catch (e) { console.error('Failed to fetch OSM object:', e); return null;