]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/api/lookup.py
Merge remote-tracking branch 'upstream/master'
[nominatim.git] / nominatim / api / lookup.py
index cb9f9839ea2722964a15ea9fce2ba0804161949a..1b0ee87f29607fe66c48a9237b253861d6ae52e4 100644 (file)
@@ -8,6 +8,7 @@
 Implementation of place lookup by ID.
 """
 from typing import Optional
 Implementation of place lookup by ID.
 """
 from typing import Optional
+import datetime as dt
 
 import sqlalchemy as sa
 
 
 import sqlalchemy as sa
 
@@ -15,6 +16,7 @@ from nominatim.typing import SaColumn, SaLabel, SaRow
 from nominatim.api.connection import SearchConnection
 import nominatim.api.types as ntyp
 import nominatim.api.results as nres
 from nominatim.api.connection import SearchConnection
 import nominatim.api.types as ntyp
 import nominatim.api.results as nres
+from nominatim.api.logging import log
 
 def _select_column_geometry(column: SaColumn,
                             geometry_output: ntyp.GeometryFormat) -> SaLabel:
 
 def _select_column_geometry(column: SaColumn,
                             geometry_output: ntyp.GeometryFormat) -> SaLabel:
@@ -36,6 +38,7 @@ async def find_in_placex(conn: SearchConnection, place: ntyp.PlaceRef,
     """ Search for the given place in the placex table and return the
         base information.
     """
     """ Search for the given place in the placex table and return the
         base information.
     """
+    log().section("Find in placex table")
     t = conn.t.placex
     sql = sa.select(t.c.place_id, t.c.osm_type, t.c.osm_id, t.c.name,
                     t.c.class_, t.c.type, t.c.admin_level,
     t = conn.t.placex
     sql = sa.select(t.c.place_id, t.c.osm_type, t.c.osm_id, t.c.name,
                     t.c.class_, t.c.type, t.c.admin_level,
@@ -44,8 +47,7 @@ async def find_in_placex(conn: SearchConnection, place: ntyp.PlaceRef,
                     t.c.importance, t.c.wikipedia, t.c.indexed_date,
                     t.c.parent_place_id, t.c.rank_address, t.c.rank_search,
                     t.c.linked_place_id,
                     t.c.importance, t.c.wikipedia, t.c.indexed_date,
                     t.c.parent_place_id, t.c.rank_address, t.c.rank_search,
                     t.c.linked_place_id,
-                    sa.func.ST_X(t.c.centroid).label('x'),
-                    sa.func.ST_Y(t.c.centroid).label('y'),
+                    t.c.centroid,
                     _select_column_geometry(t.c.geometry, details.geometry_output))
 
     if isinstance(place, ntyp.PlaceID):
                     _select_column_geometry(t.c.geometry, details.geometry_output))
 
     if isinstance(place, ntyp.PlaceID):
@@ -69,12 +71,12 @@ async def find_in_osmline(conn: SearchConnection, place: ntyp.PlaceRef,
     """ Search for the given place in the osmline table and return the
         base information.
     """
     """ Search for the given place in the osmline table and return the
         base information.
     """
+    log().section("Find in interpolation table")
     t = conn.t.osmline
     sql = sa.select(t.c.place_id, t.c.osm_id, t.c.parent_place_id,
                     t.c.indexed_date, t.c.startnumber, t.c.endnumber,
                     t.c.step, t.c.address, t.c.postcode, t.c.country_code,
     t = conn.t.osmline
     sql = sa.select(t.c.place_id, t.c.osm_id, t.c.parent_place_id,
                     t.c.indexed_date, t.c.startnumber, t.c.endnumber,
                     t.c.step, t.c.address, t.c.postcode, t.c.country_code,
-                    sa.func.ST_X(sa.func.ST_Centroid(t.c.linegeo)).label('x'),
-                    sa.func.ST_Y(sa.func.ST_Centroid(t.c.linegeo)).label('y'),
+                    t.c.linegeo.ST_Centroid().label('centroid'),
                     _select_column_geometry(t.c.linegeo, details.geometry_output))
 
     if isinstance(place, ntyp.PlaceID):
                     _select_column_geometry(t.c.linegeo, details.geometry_output))
 
     if isinstance(place, ntyp.PlaceID):
@@ -95,17 +97,41 @@ async def find_in_osmline(conn: SearchConnection, place: ntyp.PlaceRef,
 
 async def find_in_tiger(conn: SearchConnection, place: ntyp.PlaceRef,
                         details: ntyp.LookupDetails) -> Optional[SaRow]:
 
 async def find_in_tiger(conn: SearchConnection, place: ntyp.PlaceRef,
                         details: ntyp.LookupDetails) -> Optional[SaRow]:
-    """ Search for the given place in table of Tiger addresses and return the
-        base information.
+    """ Search for the given place in the table of Tiger addresses and return
+        the base information. Only lookup by place ID is supported.
     """
     """
+    log().section("Find in TIGER table")
     t = conn.t.tiger
     t = conn.t.tiger
+    parent = conn.t.placex
     sql = sa.select(t.c.place_id, t.c.parent_place_id,
     sql = sa.select(t.c.place_id, t.c.parent_place_id,
+                    parent.c.osm_type, parent.c.osm_id,
                     t.c.startnumber, t.c.endnumber, t.c.step,
                     t.c.postcode,
                     t.c.startnumber, t.c.endnumber, t.c.step,
                     t.c.postcode,
-                    sa.func.ST_X(sa.func.ST_Centroid(t.c.linegeo)).label('x'),
-                    sa.func.ST_Y(sa.func.ST_Centroid(t.c.linegeo)).label('y'),
+                    t.c.linegeo.ST_Centroid().label('centroid'),
                     _select_column_geometry(t.c.linegeo, details.geometry_output))
 
                     _select_column_geometry(t.c.linegeo, details.geometry_output))
 
+    if isinstance(place, ntyp.PlaceID):
+        sql = sql.where(t.c.place_id == place.place_id)\
+                 .join(parent, t.c.parent_place_id == parent.c.place_id, isouter=True)
+    else:
+        return None
+
+    return (await conn.execute(sql)).one_or_none()
+
+
+async def find_in_postcode(conn: SearchConnection, place: ntyp.PlaceRef,
+                           details: ntyp.LookupDetails) -> Optional[SaRow]:
+    """ Search for the given place in the postcode table and return the
+        base information. Only lookup by place ID is supported.
+    """
+    log().section("Find in postcode table")
+    t = conn.t.postcode
+    sql = sa.select(t.c.place_id, t.c.parent_place_id,
+                    t.c.rank_search, t.c.rank_address,
+                    t.c.indexed_date, t.c.postcode, t.c.country_code,
+                    t.c.geometry.label('centroid'),
+                    _select_column_geometry(t.c.geometry, details.geometry_output))
+
     if isinstance(place, ntyp.PlaceID):
         sql = sql.where(t.c.place_id == place.place_id)
     else:
     if isinstance(place, ntyp.PlaceID):
         sql = sql.where(t.c.place_id == place.place_id)
     else:
@@ -115,29 +141,45 @@ async def find_in_tiger(conn: SearchConnection, place: ntyp.PlaceRef,
 
 
 async def get_place_by_id(conn: SearchConnection, place: ntyp.PlaceRef,
 
 
 async def get_place_by_id(conn: SearchConnection, place: ntyp.PlaceRef,
-                          details: ntyp.LookupDetails) -> Optional[nres.SearchResult]:
+                          details: ntyp.LookupDetails) -> Optional[nres.DetailedResult]:
     """ Retrieve a place with additional details from the database.
     """
     """ Retrieve a place with additional details from the database.
     """
+    log().function('get_place_by_id', place=place, details=details)
+
     if details.geometry_output and details.geometry_output != ntyp.GeometryFormat.GEOJSON:
         raise ValueError("lookup only supports geojosn polygon output.")
 
     row = await find_in_placex(conn, place, details)
     if details.geometry_output and details.geometry_output != ntyp.GeometryFormat.GEOJSON:
         raise ValueError("lookup only supports geojosn polygon output.")
 
     row = await find_in_placex(conn, place, details)
+    log().var_dump('Result (placex)', row)
     if row is not None:
     if row is not None:
-        result = nres.create_from_placex_row(row)
-        await nres.add_result_details(conn, result, details)
-        return result
-
-    row = await find_in_osmline(conn, place, details)
-    if row is not None:
-        result = nres.create_from_osmline_row(row)
-        await nres.add_result_details(conn, result, details)
-        return result
-
-    row = await find_in_tiger(conn, place, details)
-    if row is not None:
-        result = nres.create_from_tiger_row(row)
-        await nres.add_result_details(conn, result, details)
-        return result
-
-    # Nothing found under this ID.
-    return None
+        result = nres.create_from_placex_row(row, nres.DetailedResult)
+    else:
+        row = await find_in_osmline(conn, place, details)
+        log().var_dump('Result (osmline)', row)
+        if row is not None:
+            result = nres.create_from_osmline_row(row, nres.DetailedResult)
+        else:
+            row = await find_in_postcode(conn, place, details)
+            log().var_dump('Result (postcode)', row)
+            if row is not None:
+                result = nres.create_from_postcode_row(row, nres.DetailedResult)
+            else:
+                row = await find_in_tiger(conn, place, details)
+                log().var_dump('Result (tiger)', row)
+                if row is not None:
+                    result = nres.create_from_tiger_row(row, nres.DetailedResult)
+                else:
+                    return None
+
+    # add missing details
+    assert result is not None
+    result.parent_place_id = row.parent_place_id
+    result.linked_place_id = getattr(row, 'linked_place_id', None)
+    result.admin_level = getattr(row, 'admin_level', 15)
+    indexed_date = getattr(row, 'indexed_date', None)
+    if indexed_date is not None:
+        result.indexed_date = indexed_date.replace(tzinfo=dt.timezone.utc)
+
+    await nres.add_result_details(conn, result, details)
+
+    return result