1 # SPDX-License-Identifier: GPL-3.0-or-later
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Custom types for SQLAlchemy.
10 from typing import Callable, Any
12 import sqlalchemy as sa
13 import sqlalchemy.types as types
15 from nominatim.typing import SaColumn
17 class Geometry(types.UserDefinedType[Any]):
18 """ Simplified type decorator for PostGIS geometry. This type
19 only supports geometries in 4326 projection.
23 def __init__(self, subtype: str = 'Geometry'):
24 self.subtype = subtype
27 def get_col_spec(self) -> str:
28 return f'GEOMETRY({self.subtype}, 4326)'
31 def bind_processor(self, dialect: 'sa.Dialect') -> Callable[[Any], str]:
32 def process(value: Any) -> str:
33 if isinstance(value, str):
34 return 'SRID=4326;' + value
36 return 'SRID=4326;' + value.to_wkt()
40 def result_processor(self, dialect: 'sa.Dialect', coltype: object) -> Callable[[Any], str]:
41 def process(value: Any) -> str:
42 assert isinstance(value, str)
47 def bind_expression(self, bindvalue: 'sa.BindParameter[Any]') -> SaColumn:
48 return sa.func.ST_GeomFromText(bindvalue, type_=self)
51 class comparator_factory(types.UserDefinedType.Comparator):
53 def intersects(self, other: SaColumn) -> SaColumn:
54 return self.op('&&')(other)
56 def is_line_like(self) -> SaColumn:
57 return sa.func.ST_GeometryType(self, type_=sa.String).in_(('ST_LineString',
58 'ST_MultiLineString'))
60 def is_area(self) -> SaColumn:
61 return sa.func.ST_GeometryType(self, type_=sa.String).in_(('ST_Polygon',
65 def ST_DWithin(self, other: SaColumn, distance: SaColumn) -> SaColumn:
66 return sa.func.ST_DWithin(self, other, distance, type_=sa.Float)
69 def ST_Distance(self, other: SaColumn) -> SaColumn:
70 return sa.func.ST_Distance(self, other, type_=sa.Float)
73 def ST_Contains(self, other: SaColumn) -> SaColumn:
74 return sa.func.ST_Contains(self, other, type_=sa.Float)
77 def ST_ClosestPoint(self, other: SaColumn) -> SaColumn:
78 return sa.func.ST_ClosestPoint(self, other, type_=Geometry)
81 def ST_Buffer(self, other: SaColumn) -> SaColumn:
82 return sa.func.ST_Buffer(self, other, type_=Geometry)
85 def ST_Expand(self, other: SaColumn) -> SaColumn:
86 return sa.func.ST_Expand(self, other, type_=Geometry)
89 def ST_Collect(self) -> SaColumn:
90 return sa.func.ST_Collect(self, type_=Geometry)
93 def ST_Centroid(self) -> SaColumn:
94 return sa.func.ST_Centroid(self, type_=Geometry)
97 def ST_LineInterpolatePoint(self, other: SaColumn) -> SaColumn:
98 return sa.func.ST_LineInterpolatePoint(self, other, type_=Geometry)
101 def ST_LineLocatePoint(self, other: SaColumn) -> SaColumn:
102 return sa.func.ST_LineLocatePoint(self, other, type_=sa.Float)