Match on boundary=political

This commit is contained in:
Edward Betts 2023-10-13 16:48:20 +01:00
parent 41a34856b8
commit 2519ea74b8
4 changed files with 17 additions and 9 deletions

View file

@ -1,8 +1,9 @@
"""Database model.""" """Database model."""
import sqlalchemy import sqlalchemy
import sqlalchemy.orm.query
from geoalchemy2 import Geometry from geoalchemy2 import Geometry
from sqlalchemy import cast, func from sqlalchemy import and_, cast, func, or_
from sqlalchemy.dialects import postgresql from sqlalchemy.dialects import postgresql
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy.ext.hybrid import hybrid_property
@ -13,7 +14,7 @@ from sqlalchemy.types import Float, Integer, Numeric, String
from .database import session from .database import session
Base = declarative_base() Base = declarative_base()
Base.query = session.query_property() Base.query = session.query_property() # type:ignore
class Polygon(Base): class Polygon(Base):
@ -23,6 +24,7 @@ class Polygon(Base):
osm_id = Column(Integer, primary_key=True, autoincrement=False) osm_id = Column(Integer, primary_key=True, autoincrement=False)
admin_level = Column(String) admin_level = Column(String)
boundary = Column(String)
way_area = Column(Float) way_area = Column(Float)
tags = Column(postgresql.HSTORE) tags = Column(postgresql.HSTORE)
@ -43,15 +45,20 @@ class Polygon(Base):
@classmethod @classmethod
def coords_within( def coords_within(
cls, lat: str | float, lon: str | float cls, lat: str | float, lon: str | float
) -> sqlalchemy.orm.query.Query["Polygon"]: ) -> sqlalchemy.orm.query.Query: # type: ignore
"""Polygons that contain given coordinates.""" """Polygons that contain given coordinates."""
point = func.ST_SetSRID(func.ST_MakePoint(lon, lat), 4326) point = func.ST_SetSRID(func.ST_MakePoint(lon, lat), 4326)
q: sqlalchemy.orm.query.Query["Polygon"] = cls.query.filter( q = cls.query.filter( # type: ignore
cls.admin_level.isnot(None), or_(
cls.admin_level.regexp_match("^\d+$"), cls.boundary == "political",
and_(
cls.admin_level.isnot(None), # type: ignore
cls.admin_level.regexp_match(r"^\d+$"), # type: ignore
),
),
func.ST_Within(point, cls.way), func.ST_Within(point, cls.way),
).order_by(cls.area, cast(cls.admin_level, Integer).desc()) ).order_by(cls.area, cast(cls.admin_level, Integer).desc())
return q return q # type: ignore
class Scotland(Base): class Scotland(Base):

View file

@ -107,6 +107,7 @@ def geosearch(lat: str | float, lon: str | float) -> Row | None:
"Q5084": 1, # hamlet "Q5084": 1, # hamlet
"Q515": 2, # city "Q515": 2, # city
"Q1549591": 3, # big city "Q1549591": 3, # big city
"Q589282": 2, # ward or electoral division of the United Kingdom
} }
for row in rows: for row in rows:
isa = wd_uri_to_qid(row["isa"]["value"]) isa = wd_uri_to_qid(row["isa"]["value"])

View file

@ -66,7 +66,6 @@ def lat_lon_to_wikidata(lat: str | float, lon: str | float) -> dict[str, typing.
return {"elements": elements, "result": result} return {"elements": elements, "result": result}
admin_level = result.get("admin_level") admin_level = result.get("admin_level")
assert isinstance(admin_level, int)
if not admin_level or admin_level >= 7: if not admin_level or admin_level >= 7:
return {"elements": elements, "result": result} return {"elements": elements, "result": result}

View file

@ -1,7 +1,8 @@
SELECT DISTINCT ?item ?distance ?itemLabel ?isa ?isaLabel ?commonsCat ?commonsSiteLink WHERE { SELECT DISTINCT ?item ?distance ?itemLabel ?isa ?isaLabel ?commonsCat ?commonsSiteLink WHERE {
{ {
SELECT DISTINCT ?item ?location ?distance ?isa WHERE { SELECT DISTINCT ?item ?location ?distance ?isa WHERE {
?item wdt:P31/wdt:P279* wd:Q486972 . VALUES ?want { wd:Q486972 wd:Q56061 }
?item wdt:P31/wdt:P279* ?want .
?item wdt:P31 ?isa . ?item wdt:P31 ?isa .
SERVICE wikibase:around { SERVICE wikibase:around {
?item wdt:P625 ?location. ?item wdt:P625 ?location.