MapComplete/src/Logic/Search/CombinedSearcher.ts

57 lines
2.1 KiB
TypeScript
Raw Normal View History

2024-10-19 14:44:55 +02:00
import GeocodingProvider, {
SearchResult,
GeocodingOptions,
GeocodeResult,
} from "./GeocodingProvider"
import { Utils } from "../../Utils"
2024-08-22 22:50:37 +02:00
import { Store, Stores } from "../UIEventSource"
2024-08-15 01:51:33 +02:00
export default class CombinedSearcher implements GeocodingProvider {
private _providers: ReadonlyArray<GeocodingProvider>
private _providersWithSuggest: ReadonlyArray<GeocodingProvider>
2024-08-15 01:51:33 +02:00
constructor(...providers: ReadonlyArray<GeocodingProvider>) {
this._providers = Utils.NoNull(providers)
2024-10-19 14:44:55 +02:00
this._providersWithSuggest = this._providers.filter((pr) => pr.suggest !== undefined)
2024-08-15 01:51:33 +02:00
}
2024-08-21 14:06:42 +02:00
/**
* Merges the geocode-results from various sources.
* If the same osm-id is mentioned multiple times, only the first result will be kept
* @param geocoded
* @private
*/
public static merge(geocoded: GeocodeResult[][]): GeocodeResult[] {
const results: GeocodeResult[] = []
2024-08-21 14:06:42 +02:00
const seenIds = new Set<string>()
for (const geocodedElement of geocoded) {
2024-10-19 14:44:55 +02:00
if (geocodedElement === undefined) {
continue
}
2024-08-21 14:06:42 +02:00
for (const entry of geocodedElement) {
2024-08-26 13:09:46 +02:00
if (entry.osm_id === undefined) {
throw "Invalid search result: a search result always must have an osm_id to be able to merge results from different sources"
}
const id = (entry["osm_type"] ?? "") + entry.osm_id
2024-08-22 22:50:37 +02:00
if (seenIds.has(id)) {
2024-08-21 14:06:42 +02:00
continue
}
seenIds.add(id)
results.push(entry)
}
}
return results
}
2024-08-26 13:09:46 +02:00
async search(query: string, options?: GeocodingOptions): Promise<SearchResult[]> {
2024-10-19 14:44:55 +02:00
const results = await Promise.all(this._providers.map((pr) => pr.search(query, options)))
return CombinedSearcher.merge(results)
2024-08-15 01:51:33 +02:00
}
2024-08-26 13:09:46 +02:00
suggest(query: string, options?: GeocodingOptions): Store<SearchResult[]> {
return Stores.concat(
2024-10-19 14:44:55 +02:00
this._providersWithSuggest.map((pr) => pr.suggest(query, options))
).map((gcrss) => CombinedSearcher.merge(gcrss))
2024-08-15 01:51:33 +02:00
}
}