Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 30 additions & 27 deletions app/api/tree.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
)
from ..dependencies import get_session
from ..services.tree import (
get_tree_by_id
get_tree_by_id,
get_tree_by_species
)

from geoalchemy2.shape import to_shape
from shapely.geometry import mapping

route_street_tree = APIRouter(prefix='/street_tree/v1')

def create_geojson_from_rows(rows: List[Dict[str, Any]]) -> FeatureCollection:
Expand All @@ -39,37 +37,42 @@ def create_geojson_from_rows(rows: List[Dict[str, Any]]) -> FeatureCollection:
'/details',
response_model=StreetTreeResponse,
tags=['Strassenbaeume'],
description='Retrieves street tree details based on the provided tree id.'
description=(
'Retrieves street tree details based on the provided tree id.'
)
)
async def fetch_tree_by_id(
tree_id: int,
session: AsyncSession = Depends(get_session)
) -> StreetTreeResponse:
row = await get_tree_by_id(session, tree_id)
) -> List[StreetTreeResponse]:
rows = await get_tree_by_id(session, tree_id)
identifier = f'tree_id {tree_id}'

if not row:
if not rows:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f'No matches found for tree_id {tree_id}'
detail=f'No matches found for {identifier}'
)

# `row` is a RowMapping, convert to model instance or dict if needed
tree: StreetTreeRegister = row[0] if isinstance(row, tuple) else row
return rows

@route_street_tree.get(
'/species',
response_model=StreetTreeResponse,
tags=['Strassenbaeume'],
description=(
'Retrieves street tree details based on the provided tree id.'
)
)
async def fetch_tree_by_species(
session: AsyncSession = Depends(get_session)
) -> List[StreetTreeResponse]:
rows = await get_tree_by_species(session)

# Convert WKBElement geom to GeoJSON dict
shape = to_shape(tree.geom)
geojson_dict = mapping(shape)
if not rows:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f'No matches found'
)

# Return tree data with geom as GeoJSON dict
return {
"id": tree.id,
"tree_number": tree.tree_number,
"street": tree.street,
"area_type": tree.area_type,
"species": tree.species,
"north": tree.north,
"east": tree.east,
"registration_date": tree.registration_date.isoformat() if tree.registration_date else None,
"type": tree.type,
"geom": geojson_dict,
}
return rows
2 changes: 1 addition & 1 deletion app/models/tree.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ class StreetTreeRegister(SQLModel, table=True):
east: float = Field(sa_column=Column(Numeric, nullable=False))
registration_date: datetime.date = Field(sa_column=Column(Date(), nullable=False))
type: str = Field(sa_column=Column(String, nullable=False))
geom: object = Field(sa_column=Column(Geometry('POINT', srid=31467), nullable=True)) # nullable depends on DB column
geom: object = Field(sa_column=Column(Geometry('POINT', srid=31467), nullable=True)) # nullable depends on DB column
Empty file modified app/schemas/tree.py
100755 → 100644
Empty file.
40 changes: 39 additions & 1 deletion app/services/tree.py
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from sqlalchemy import select, case, literal_column, func
from sqlalchemy.sql import exists, and_, not_, text
from sqlalchemy.orm import aliased
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select
from app.models.tree import StreetTreeRegister

async def get_tree_by_id(session: AsyncSession, tree_id: int):
Expand All @@ -10,3 +12,39 @@ async def get_tree_by_id(session: AsyncSession, tree_id: int):
row = result.scalars().first()

return row

async def get_tree_by_species(session: AsyncSession):
stmt = text('''
SELECT
tr.id,
tr.tree_number,
tr.street,
tr.species,
tr.type,
ROUND(ST_X(ST_Transform(tr.geom, 4326))::numeric, 6) AS lon,
ROUND(ST_Y(ST_Transform(tr.geom, 4326))::numeric, 6) AS lat,
CASE
WHEN tr.species ILIKE '%Tilia%' THEN 1
WHEN tr.species ILIKE '%Acer%' THEN 2
WHEN tr.species ILIKE '%Quercus%' THEN 3
WHEN tr.species ILIKE '%Fagus%' THEN 4
WHEN tr.species ILIKE '%Betula%' THEN 5
WHEN tr.species ILIKE '%Carpinus%' THEN 6
ELSE 0
END AS species_index
FROM flensburg.street_tree_register tr
WHERE tr.type = 'bestand'
AND NOT EXISTS (
SELECT 1
FROM flensburg.street_tree_register gef
WHERE gef.type = 'gefaellt'
AND gef.tree_number = tr.tree_number
AND gef.street = tr.street
)
ORDER BY tr.species
''')

result = await session.execute(stmt)
rows = result.mappings().all()

return [dict(row) for row in rows]
Loading