3
3
4
4
from fastapi_pagination import Page
5
5
from fastapi_pagination .ext .sqlalchemy import paginate
6
+ from geoalchemy2 import Geometry
6
7
from geoalchemy2 .functions import ST_Transform
7
8
from sqlalchemy import select , Select , func , text , Row , Label
8
9
from sqlalchemy .dialects .postgresql import JSONB
9
10
from sqlalchemy .orm import Session , InstrumentedAttribute
10
11
from sqlalchemy .sql import operators
11
12
13
+ import database
12
14
import filters
13
15
import models
14
16
import schemas
@@ -70,16 +72,33 @@ class BaseBoundariesService(abc.ABC):
70
72
model_class : Type [models .BaseBoundaries ]
71
73
72
74
@abc .abstractmethod
73
- def _get_select_query (self , srid : Optional [int ]) -> Select :
75
+ def _get_select_query (self , srid : Optional [int ],
76
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ]) -> Select :
74
77
pass
75
78
76
79
@abc .abstractmethod
77
80
def _filter_by_code (self , query : Select , code : int ) -> Select :
78
81
pass
79
82
80
83
@staticmethod
81
- def _get_geometry_field (field : InstrumentedAttribute , srid : int ) -> Label :
82
- return ST_Transform (field , srid ).label ("geometry" )
84
+ def _get_geometry_output_type (geometry_output_format : schemas .GeometryOutputFormat ):
85
+ match geometry_output_format :
86
+ case schemas .GeometryOutputFormat .ewkt :
87
+ return database .EWKTGeometry
88
+ case schemas .GeometryOutputFormat .ewkb :
89
+ return Geometry ()
90
+ case _:
91
+ raise ValueError (f"Unable to map geometry output format { geometry_output_format } " )
92
+
93
+ @staticmethod
94
+ def _get_geometry_field (
95
+ field : InstrumentedAttribute ,
96
+ srid : int ,
97
+ geometry_output_format : schemas .GeometryOutputFormat
98
+ ) -> Label :
99
+ geometry_output_type = BaseBoundariesService ._get_geometry_output_type (geometry_output_format )
100
+
101
+ return ST_Transform (field , srid , type_ = geometry_output_type ).label ("geometry" )
83
102
84
103
def search (
85
104
self ,
@@ -89,8 +108,9 @@ def search(
89
108
request : schemas .BaseSearchRequest ,
90
109
boundaries_filter : filters .BaseFilter ,
91
110
srid : Optional [int ],
111
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ]
92
112
) -> Page :
93
- query = self ._get_select_query (srid = srid )
113
+ query = self ._get_select_query (srid = srid , geometry_output_format = geometry_output_format )
94
114
95
115
query = boundaries_filter .apply (request , db , query )
96
116
@@ -106,9 +126,10 @@ def get_by_code(
106
126
self ,
107
127
db : Session ,
108
128
code : int ,
129
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ] = None ,
109
130
srid : Optional [int ] = None ,
110
131
) -> Row | None :
111
- query = self ._get_select_query (srid = srid )
132
+ query = self ._get_select_query (srid = srid , geometry_output_format = geometry_output_format )
112
133
query = self ._filter_by_code (code = code , query = query )
113
134
114
135
return db .execute (query ).first ()
@@ -117,15 +138,20 @@ def get_by_code(
117
138
class CountiesService (BaseBoundariesService ):
118
139
model_class = models .Counties
119
140
120
- def _get_select_query (self , srid : Optional [int ]) -> Select :
141
+ def _get_select_query (
142
+ self ,
143
+ srid : Optional [int ],
144
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
145
+ ) -> Select :
121
146
columns = [
122
147
models .Counties .code ,
123
148
models .Counties .feature_id ,
124
149
models .Counties .name ,
125
150
models .Counties .area_ha ,
126
151
models .Counties .area_ha ,
127
152
models .Counties .created_at ,
128
- ] + ([self ._get_geometry_field (models .Counties .geom , srid )] if srid else [])
153
+ ] + ([self ._get_geometry_field (models .Counties .geom , srid ,
154
+ geometry_output_format )] if srid and geometry_output_format else [])
129
155
130
156
return select (* columns ).select_from (models .Counties )
131
157
@@ -136,7 +162,11 @@ def _filter_by_code(self, query: Select, code: int) -> Select:
136
162
class MunicipalitiesService (BaseBoundariesService ):
137
163
model_class = models .Municipalities
138
164
139
- def _get_select_query (self , srid : Optional [int ]) -> Select :
165
+ def _get_select_query (
166
+ self ,
167
+ srid : Optional [int ],
168
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
169
+ ) -> Select :
140
170
columns = [
141
171
models .Municipalities .code ,
142
172
models .Municipalities .feature_id ,
@@ -157,7 +187,11 @@ def _filter_by_code(self, query: Select, code: int) -> Select:
157
187
class EldershipsService (BaseBoundariesService ):
158
188
model_class = models .Elderships
159
189
160
- def _get_select_query (self , srid : Optional [int ]) -> Select :
190
+ def _get_select_query (
191
+ self ,
192
+ srid : Optional [int ],
193
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
194
+ ) -> Select :
161
195
columns = [
162
196
models .Elderships .code ,
163
197
models .Elderships .feature_id ,
@@ -178,7 +212,10 @@ def _filter_by_code(self, query: Select, code: int) -> Select:
178
212
class ResidentialAreasService (BaseBoundariesService ):
179
213
model_class = models .ResidentialAreas
180
214
181
- def _get_select_query (self , srid : Optional [int ]) -> Select :
215
+ def _get_select_query (
216
+ self , srid : Optional [int ],
217
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
218
+ ) -> Select :
182
219
columns = [
183
220
models .ResidentialAreas .code ,
184
221
models .ResidentialAreas .feature_id ,
@@ -199,7 +236,11 @@ def _filter_by_code(self, query: Select, code: int) -> Select:
199
236
class StreetsService (BaseBoundariesService ):
200
237
model_class = models .Streets
201
238
202
- def _get_select_query (self , srid : Optional [int ]) -> Select :
239
+ def _get_select_query (
240
+ self ,
241
+ srid : Optional [int ],
242
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
243
+ ) -> Select :
203
244
columns = [
204
245
models .Streets .code ,
205
246
models .Streets .feature_id ,
@@ -221,7 +262,11 @@ def _filter_by_code(self, query: Select, code: int) -> Select:
221
262
class AddressesService (BaseBoundariesService ):
222
263
model_class = models .Addresses
223
264
224
- def _get_select_query (self , srid : Optional [int ]) -> Select :
265
+ def _get_select_query (
266
+ self ,
267
+ srid : Optional [int ],
268
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
269
+ ) -> Select :
225
270
columns = [
226
271
models .Addresses .feature_id ,
227
272
models .Addresses .code ,
@@ -232,7 +277,7 @@ def _get_select_query(self, srid: Optional[int]) -> Select:
232
277
_flat_residential_area_object ,
233
278
_municipality_object ,
234
279
_flat_street_object ,
235
- self ._get_geometry_field (models .Addresses .geom , srid )
280
+ self ._get_geometry_field (models .Addresses .geom , srid , geometry_output_format )
236
281
]
237
282
238
283
return select (* columns ).select_from (models .Addresses ) \
@@ -248,13 +293,18 @@ def _filter_by_code(self, query: Select, code: int) -> Select:
248
293
class RoomsService (BaseBoundariesService ):
249
294
model_class = models .Rooms
250
295
251
- def _get_select_query (self , srid : Optional [int ]) -> Select :
296
+ def _get_select_query (
297
+ self ,
298
+ srid : Optional [int ],
299
+ geometry_output_format : Optional [schemas .GeometryOutputFormat ],
300
+ ) -> Select :
252
301
columns = [
253
302
models .Rooms .code ,
254
303
models .Rooms .room_number ,
255
304
models .Rooms .created_at ,
256
305
_address_short_object ,
257
- ] + ([self ._get_geometry_field (models .Addresses .geom , srid )] if srid else [])
306
+ ] + ([self ._get_geometry_field (models .Addresses .geom , srid ,
307
+ geometry_output_format )] if srid and geometry_output_format else [])
258
308
259
309
return select (* columns ).select_from (models .Rooms ) \
260
310
.outerjoin (models .Rooms .address ) \
0 commit comments