feat: locations endpoint#1767
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new /v1/locations search capability to the Mobility Feed API, backed by a new geopolygon-based materialized view/read-model and populated/maintained via the reverse-geolocation population workflow.
Changes:
- Introduces
/v1/locationsin the OpenAPI spec and wires the generated router into the FastAPI app. - Adds backend query implementation for location search (FTS + filters + pagination) and unit tests.
- Adds Liquibase migrations for a
GeopolygonHierarchytable plus aGeopolygonLocationSearchmaterialized view and indexes; updates the reverse-geolocation populate function to maintain/refresh this read model.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
liquibase/materialized_views/materialized_views.xml |
Adds rebuild step for the new location-search materialized view. |
liquibase/materialized_views/geopolygon_location_search.sql |
Defines GeopolygonLocationSearch MV and related indexes for search. |
liquibase/changes/feat_pt_202.sql |
Adds GeopolygonHierarchy table used to resolve parent/country/subdivision relationships. |
liquibase/changelog.xml |
Ensures the hierarchy table is created before materialized views are rebuilt. |
functions-python/reverse_geolocation_populate/src/main.py |
Updates the populate workflow to upsert hierarchy edges and refresh the MV. |
functions-python/reverse_geolocation_populate/tests/test_reverse_geolocation_populate.py |
Adds unit coverage for hierarchy update + MV refresh hooks. |
docs/DatabaseCatalogAPI.yaml |
Adds /v1/locations endpoint and new response/result schemas + limit parameter. |
api/src/feeds/impl/locations_api_impl.py |
Implements the location search query logic against the MV. |
api/tests/unittest/test_locations_api_impl.py |
Adds unit tests for helpers and get_locations behavior. |
api/src/shared/database/sql_functions/unaccent.py |
Enables SQLAlchemy caching for the unaccent SQL function wrapper. |
api/src/main.py |
Registers the new locations router. |
api/.openapi-generator/FILES |
Updates the generated-file manifest for new locations API/models. |
| locality's representative point is computed once, and containment is tested with | ||
| ``ST_Covers`` against the raw (spatially indexed) candidate geometry. Point-in- | ||
| polygon is robust to invalid polygons, so the large candidate geometries are | ||
| never repaired with ``ST_MakeValid`` here. |
| """ | ||
|
|
||
| pass | ||
| inherit_cache = True |
There was a problem hiding this comment.
fixes unaccent warning in logs
|
[question]: Should we add the |
Any reason why we would need the parent as well? |
No hard requirements currently; we can skip it for simplicity. |
| locations_query = locations_query.order_by( | ||
| location_search.c.admin_level.asc(), | ||
| func.ts_rank(location_search.c.document, _ts_query(normalized_query)).desc(), | ||
| location_search.c.display_name.asc(), |
There was a problem hiding this comment.
Add a deterministic fallback sorting:
| location_search.c.display_name.asc(), | |
| location_search.c.display_name.asc(), | |
| location_search.c.osm_id.asc(), # deterministic tiebreaker for stable pagination |
| else: | ||
| locations_query = locations_query.order_by( | ||
| location_search.c.admin_level.asc(), | ||
| location_search.c.display_name.asc(), |
There was a problem hiding this comment.
| location_search.c.display_name.asc(), | |
| location_search.c.display_name.asc(), | |
| location_search.c.osm_id.asc(), # deterministic tiebreaker for stable pagination |
Summary:
Closes https://github.com/MobilityData/product-tasks/issues/202
This pull request introduces a new
/locationsAPI endpoint for searching locations in the Mobility Database, along with the associated backend implementation, OpenAPI documentation, and tests. It also includes minor improvements to the database utility functions and code organization.The most important changes are:
New Locations API Endpoint
/v1/locationswith parameters for search query, country code, subdivision code, location type, and pagination; response includes total count and results. [1] [2] [3]locationstag and endpoint in the API generator and FastAPI application. [1] [2] [3] [4] [5]Backend Implementation
LocationsApiImplinlocations_api_impl.py, supporting full-text search (with typeahead), filtering, normalization, and paginated results from the geopolygon materialized view.Testing
test_locations_api_impl.py.Supporting Changes
LocationSearchResponseandLocationSearchResult.unaccentSQL function to support caching in SQLAlchemy.These changes collectively add a robust, well-documented, and tested location search capability to the API.
Please make sure these boxes are checked before submitting your pull request - thanks!
./scripts/api-tests.shto make sure you didn't break anything