]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/api/results.py
enable API use with psycopg 3
[nominatim.git] / nominatim / api / results.py
index 2999b9a781c29fe2e18cdc3e46007396beb23bcc..98b13380726e98361bc2571c85bd78928c1afc12 100644 (file)
@@ -11,7 +11,7 @@ Data classes are part of the public API while the functions are for
 internal use only. That's why they are implemented as free-standing functions
 instead of member functions.
 """
 internal use only. That's why they are implemented as free-standing functions
 instead of member functions.
 """
-from typing import Optional, Tuple, Dict, Sequence, TypeVar, Type
+from typing import Optional, Tuple, Dict, Sequence, TypeVar, Type, List
 import enum
 import dataclasses
 import datetime as dt
 import enum
 import dataclasses
 import datetime as dt
@@ -22,6 +22,7 @@ from nominatim.typing import SaSelect, SaRow
 from nominatim.api.types import Point, Bbox, LookupDetails
 from nominatim.api.connection import SearchConnection
 from nominatim.api.logging import log
 from nominatim.api.types import Point, Bbox, LookupDetails
 from nominatim.api.connection import SearchConnection
 from nominatim.api.logging import log
+from nominatim.api.localization import Locales
 
 # This file defines complex result data classes.
 # pylint: disable=too-many-instance-attributes
 
 # This file defines complex result data classes.
 # pylint: disable=too-many-instance-attributes
@@ -52,8 +53,30 @@ class AddressLine:
     rank_address: int
     distance: float
 
     rank_address: int
     distance: float
 
+    local_name: Optional[str] = None
+
+
+class AddressLines(List[AddressLine]):
+    """ Sequence of address lines order in descending order by their rank.
+    """
+
+    def localize(self, locales: Locales) -> List[str]:
+        """ Set the local name of address parts according to the chosen
+            locale. Return the list of local names without duplications.
+
+            Only address parts that are marked as isaddress are localized
+            and returned.
+        """
+        label_parts: List[str] = []
+
+        for line in self:
+            if line.isaddress and line.names:
+                line.local_name = locales.display_name(line.names)
+                if not label_parts or label_parts[-1] != line.local_name:
+                    label_parts.append(line.local_name)
+
+        return label_parts
 
 
-AddressLines = Sequence[AddressLine]
 
 
 @dataclasses.dataclass
 
 
 @dataclasses.dataclass
@@ -144,6 +167,25 @@ class ReverseResult(BaseResult):
     bbox: Optional[Bbox] = None
 
 
     bbox: Optional[Bbox] = None
 
 
+class ReverseResults(List[ReverseResult]):
+    """ Sequence of reverse lookup results ordered by distance.
+        May be empty when no result was found.
+    """
+
+
+@dataclasses.dataclass
+class SearchResult(BaseResult):
+    """ A search result for forward geocoding.
+    """
+    bbox: Optional[Bbox] = None
+
+
+class SearchResults(List[SearchResult]):
+    """ Sequence of forward lookup results ordered by relevance.
+        May be empty when no result was found.
+    """
+
+
 def _filter_geometries(row: SaRow) -> Dict[str, str]:
     return {k[9:]: v for k, v in row._mapping.items() # pylint: disable=W0212
             if k.startswith('geometry_')}
 def _filter_geometries(row: SaRow) -> Dict[str, str]:
     return {k[9:]: v for k, v in row._mapping.items() # pylint: disable=W0212
             if k.startswith('geometry_')}
@@ -226,6 +268,7 @@ def create_from_tiger_row(row: Optional[SaRow],
 
     res = class_type(source_table=SourceTable.TIGER,
                      place_id=row.place_id,
 
     res = class_type(source_table=SourceTable.TIGER,
                      place_id=row.place_id,
+                     osm_object=(row.osm_type, row.osm_id),
                      category=('place', 'houses' if hnr is None else 'house'),
                      postcode=row.postcode,
                      country_code='us',
                      category=('place', 'houses' if hnr is None else 'house'),
                      postcode=row.postcode,
                      country_code='us',
@@ -286,8 +329,8 @@ def _result_row_to_address_row(row: SaRow) -> AddressLine:
     """ Create a new AddressLine from the results of a datbase query.
     """
     extratags: Dict[str, str] = getattr(row, 'extratags', {})
     """ Create a new AddressLine from the results of a datbase query.
     """
     extratags: Dict[str, str] = getattr(row, 'extratags', {})
-    if 'place_type' in row:
-        extratags['place_type'] = row.place_type
+    if hasattr(row, 'place_type') and row.place_type:
+        extratags['place'] = row.place_type
 
     names = row.name
     if getattr(row, 'housenumber', None) is not None:
 
     names = row.name
     if getattr(row, 'housenumber', None) is not None:
@@ -333,7 +376,7 @@ async def complete_address_details(conn: SearchConnection, result: BaseResult) -
     sql = sa.select(sfn).order_by(sa.column('rank_address').desc(),
                                   sa.column('isaddress').desc())
 
     sql = sa.select(sfn).order_by(sa.column('rank_address').desc(),
                                   sa.column('isaddress').desc())
 
-    result.address_rows = []
+    result.address_rows = AddressLines()
     for row in await conn.execute(sql):
         result.address_rows.append(_result_row_to_address_row(row))
 
     for row in await conn.execute(sql):
         result.address_rows.append(_result_row_to_address_row(row))
 
@@ -357,7 +400,7 @@ def _placex_select_address_row(conn: SearchConnection,
 async def complete_linked_places(conn: SearchConnection, result: BaseResult) -> None:
     """ Retrieve information about places that link to the result.
     """
 async def complete_linked_places(conn: SearchConnection, result: BaseResult) -> None:
     """ Retrieve information about places that link to the result.
     """
-    result.linked_rows = []
+    result.linked_rows = AddressLines()
     if result.source_table != SourceTable.PLACEX:
         return
 
     if result.source_table != SourceTable.PLACEX:
         return
 
@@ -392,7 +435,7 @@ async def complete_parented_places(conn: SearchConnection, result: BaseResult) -
     """ Retrieve information about places that the result provides the
         address for.
     """
     """ Retrieve information about places that the result provides the
         address for.
     """
-    result.parented_rows = []
+    result.parented_rows = AddressLines()
     if result.source_table != SourceTable.PLACEX:
         return
 
     if result.source_table != SourceTable.PLACEX:
         return