From 8c99bd1b0d19c053acbc7c0998a62ebdfca05e86 Mon Sep 17 00:00:00 2001 From: Florian Date: Sat, 31 Oct 2026 22:33:57 +0100 Subject: [PATCH] fix(search-osm-aliases): return no suggestions until an index is built The provider read osm_search.index_state on every request, so a server whose data-manager never built the OSM alias index failed each suggestion request in Postgres. Check that the table exists first, as the notable-places provider and this integration's health check do. --- .../__tests__/provider.test.ts | 24 ++++++++++++++++--- integrations/search-osm-aliases/provider.ts | 10 ++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/integrations/search-osm-aliases/__tests__/provider.test.ts b/integrations/search-osm-aliases/__tests__/provider.test.ts index 1cdc061f3..fa2fb073b 100644 --- a/integrations/search-osm-aliases/__tests__/provider.test.ts +++ b/integrations/search-osm-aliases/__tests__/provider.test.ts @@ -6,6 +6,7 @@ describe("OSM alias suggestion provider", () => { it("uses normalized parameterized lookup and maps exact code evidence", async () => { const execute = vi .fn() + .mockResolvedValueOnce([{ exists: true }]) .mockResolvedValueOnce([{ epoch: "epoch-1", status: "ready" }]) .mockResolvedValueOnce([ { @@ -32,7 +33,7 @@ describe("OSM alias suggestion provider", () => { { signal: new AbortController().signal, deadlineAt: Number.POSITIVE_INFINITY }, ); - expect(execute.mock.calls[1]?.[1]).toEqual(["fra", true, 8, null, null, true]); + expect(execute.mock.calls[2]?.[1]).toEqual(["fra", true, 8, null, null, true]); expect(result.suggestions[0]).toMatchObject({ id: "osm:node/42", ids: { osm: "node/42", wikidata: "Q46033" }, @@ -63,6 +64,7 @@ describe("OSM alias suggestion provider", () => { it("passes lowercase acronym intent and proximity to the SQL gate", async () => { const execute = vi .fn() + .mockResolvedValueOnce([{ exists: true }]) .mockResolvedValueOnce([{ epoch: "epoch-2", status: "ready" }]) .mockResolvedValueOnce([]); const provider = createOsmAliasSuggestionProvider( @@ -74,7 +76,23 @@ describe("OSM alias suggestion provider", () => { { signal: new AbortController().signal, deadlineAt: Number.POSITIVE_INFINITY }, ); - expect(execute.mock.calls[1]?.[1]).toEqual(["uncc", true, 4, -80.73, 35.3, false]); - expect(String(execute.mock.calls[1]?.[0])).toContain("ST_DWithin"); + expect(execute.mock.calls[2]?.[1]).toEqual(["uncc", true, 4, -80.73, 35.3, false]); + expect(String(execute.mock.calls[2]?.[0])).toContain("ST_DWithin"); + }); + + it("returns nothing, without reading the index, until an index is built", async () => { + const execute = vi.fn().mockResolvedValueOnce([{ exists: false }]); + const provider = createOsmAliasSuggestionProvider( + createMockIntegrationContext({ db: { execute } }), + ); + + const result = await provider.searchSuggestions( + { query: "FRA", lang: "en", limit: 8 }, + { signal: new AbortController().signal, deadlineAt: Number.POSITIVE_INFINITY }, + ); + + expect(result).toEqual({ suggestions: [], attributions: [], freshnessSeconds: 86_400 }); + expect(execute).toHaveBeenCalledTimes(1); + expect(String(execute.mock.calls[0]?.[0])).toContain("to_regclass('osm_search.index_state')"); }); }); diff --git a/integrations/search-osm-aliases/provider.ts b/integrations/search-osm-aliases/provider.ts index 50b56cfb1..ec8bf1b88 100644 --- a/integrations/search-osm-aliases/provider.ts +++ b/integrations/search-osm-aliases/provider.ts @@ -125,6 +125,16 @@ export function createOsmAliasSuggestionProvider( ): Promise { signal.throwIfAborted(); if (!ctx.db) return { suggestions: [], attributions: [], freshnessSeconds: 86_400 }; + // Until the data-manager builds a first index there is no schema to + // read, which is not a fault of the provider. + const published = await ctx.db.execute<{ exists: boolean }[]>( + "SELECT to_regclass('osm_search.index_state') IS NOT NULL AS exists", + undefined, + { signal }, + ); + if (!published[0]?.exists) { + return { suggestions: [], attributions: [], freshnessSeconds: 86_400 }; + } const states = await ctx.db.execute( "SELECT epoch, status FROM osm_search.index_state WHERE singleton = 1", undefined,