Nova struktura DB pro data z OpenAIP API
This commit is contained in:
+45
-34
@@ -67,17 +67,25 @@ copilot_has_photo = Table(
|
||||
)
|
||||
|
||||
|
||||
class AirspaceItem(BaseModel):
|
||||
__tablename__ = "airspace_item"
|
||||
airport_has_reporting_point = Table(
|
||||
"airport_has_reporting_point",
|
||||
BaseModel.metadata,
|
||||
Column("airport_id", ForeignKey("airport.id"), primary_key=True),
|
||||
Column("reporting_point_id", ForeignKey("reporting_point.id"), primary_key=True),
|
||||
)
|
||||
|
||||
|
||||
class Airspace(BaseModel):
|
||||
__tablename__ = "airspace"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
country: Mapped[str] = mapped_column(String(8), nullable=False, index=True)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False, unique=True)
|
||||
type: Mapped[str] = mapped_column(String(8), nullable=False, index=True)
|
||||
lower_limit: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
lower_alt_unit: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||
upper_limit: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
center: Mapped[List[dict]] = mapped_column(JSON())
|
||||
radius: Mapped[float] = mapped_column(Float, nullable=True)
|
||||
upper_alt_unit: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||
bounds: Mapped[list[tuple[float, float]]] = mapped_column(JSON())
|
||||
|
||||
|
||||
@@ -111,21 +119,51 @@ class Airport(BaseModel):
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
openaip_id: Mapped[str] = mapped_column(String(32), nullable=False, unique=True)
|
||||
icao_code: Mapped[str] = mapped_column(String(8), nullable=False)
|
||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||
elevation: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||
airport_type: Mapped[str] = mapped_column(Enum("airport", "ull", "heliport"), nullable=False, server_default='airport') # noqa
|
||||
use_in_gpx_guess: Mapped[bool] = mapped_column(Boolean, server_default='1')
|
||||
is_public: Mapped[bool] = mapped_column(Boolean, server_default='0')
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'), nullable=True) # automaticky import nebude mit ID # noqa
|
||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||
|
||||
metars: Mapped['Metar'] = relationship()
|
||||
created_by: Mapped['User'] = relationship()
|
||||
|
||||
|
||||
class Runway(BaseModel):
|
||||
__tablename__ = "runway"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'))
|
||||
heading: Mapped[int] = mapped_column(Integer, nullable=False)
|
||||
designator: Mapped[str] = mapped_column(String(4), nullable=False)
|
||||
surface: Mapped[str] = mapped_column(Enum("asphalt", "concrete", "grass", "other"), nullable=False, server_default="other") # noqa
|
||||
length: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||
width: Mapped[int] = mapped_column(Integer, nullable=True)
|
||||
|
||||
|
||||
class Frequency(BaseModel):
|
||||
__tablename__ = "frequency"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'), nullable=True)
|
||||
airspace_id: Mapped[int] = mapped_column(Integer, ForeignKey('airspace.id'), nullable=True)
|
||||
frequency: Mapped[str] = mapped_column(String(7), nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
|
||||
|
||||
class ReportingPoint(BaseModel):
|
||||
__tablename__ = "reporting_point"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
openaip_id: Mapped[str] = mapped_column(String(32), nullable=False)
|
||||
name: Mapped[str] = mapped_column(String(64), nullable=False)
|
||||
gps_latitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||
gps_longitude: Mapped[float] = mapped_column(Float, nullable=True)
|
||||
|
||||
|
||||
class PointOfInterestType(BaseModel):
|
||||
__tablename__ = "point_of_interest_type"
|
||||
|
||||
@@ -370,32 +408,6 @@ class Copilot(BaseModel):
|
||||
title_photo: Mapped['Photo'] = relationship(foreign_keys=[title_photo_id])
|
||||
|
||||
|
||||
class Metar(BaseModel):
|
||||
__tablename__ = "metar"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
airport_id: Mapped[int] = mapped_column(Integer, ForeignKey('airport.id'))
|
||||
metar: Mapped[str] = mapped_column(Text, nullable=False)
|
||||
issued_at: Mapped[datetime] = mapped_column(DateTime)
|
||||
deleted: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default='0')
|
||||
|
||||
airport: Mapped['Airport'] = relationship()
|
||||
|
||||
|
||||
class License(BaseModel):
|
||||
__tablename__ = "license"
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
name: Mapped[str] = mapped_column(String(128), nullable=False)
|
||||
number: Mapped[str] = mapped_column(String(30), nullable=False)
|
||||
valid_until: Mapped[datetime] = mapped_column(DateTime, nullable=False)
|
||||
created_by_id: Mapped[int] = mapped_column(Integer, ForeignKey('user.id'))
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
user: Mapped['User'] = relationship()
|
||||
created_by: Mapped['User'] = relationship()
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
__tablename__ = "user"
|
||||
excluded_columns_in_dict = ('password_hashed',)
|
||||
@@ -410,7 +422,6 @@ class User(BaseModel):
|
||||
password_hashed: Mapped[str] = mapped_column(String(60), nullable=False)
|
||||
created_at: Mapped[datetime] = mapped_column(DateTime, server_default=func.now())
|
||||
|
||||
licences: Mapped[Set['License']] = relationship()
|
||||
flights: Mapped[Set['Flight']] = relationship()
|
||||
organizations: Mapped[Set['Organization']] = relationship(secondary=user_is_in_organization)
|
||||
|
||||
|
||||
Vendored
+12
-12
@@ -14,7 +14,7 @@ from external.gps_utils import get_distance, get_bearing, EARTH_RADIUS
|
||||
# https://pyopenair.readthedocs.io/en/latest/openair.html
|
||||
# http://www.winpilot.com/usersguide/userairspace.asp
|
||||
|
||||
class AirspaceItemType(enum.Enum):
|
||||
class AirspaceType(enum.Enum):
|
||||
AIRSPACE_A = "A"
|
||||
AIRSPACE_B = "B"
|
||||
AIRSPACE_C = "C"
|
||||
@@ -47,8 +47,8 @@ class Coordinates:
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class AirspaceItem:
|
||||
type: AirspaceItemType
|
||||
class Airspace:
|
||||
type: AirspaceType
|
||||
info: str = ""
|
||||
upper_limit: str = None
|
||||
lower_limit: str = None
|
||||
@@ -107,7 +107,7 @@ class OpenAirParser:
|
||||
def __init__(self, file: Path | str):
|
||||
self.file = None
|
||||
|
||||
self.context_type: Optional[AirspaceItemType] = None
|
||||
self.context_type: Optional[AirspaceType] = None
|
||||
self.context = {}
|
||||
|
||||
self.file = file
|
||||
@@ -116,7 +116,7 @@ class OpenAirParser:
|
||||
if not self.context_type:
|
||||
return
|
||||
|
||||
data = AirspaceItem(type=self.context_type, **self.context)
|
||||
data = Airspace(type=self.context_type, **self.context)
|
||||
|
||||
self.context_type = None
|
||||
self.context = {}
|
||||
@@ -194,19 +194,19 @@ class OpenAirParser:
|
||||
pass
|
||||
case 'AC':
|
||||
try:
|
||||
self.context_type = AirspaceItemType(value)
|
||||
self.context_type = AirspaceType(value)
|
||||
except ValueError as e:
|
||||
print(f"Neznam {e}, ignoruji")
|
||||
return
|
||||
case 'AN':
|
||||
if self.context_type == AirspaceItemType.AIRSPACE_G:
|
||||
if self.context_type == AirspaceType.AIRSPACE_G:
|
||||
match value[0:2]:
|
||||
case 'PG':
|
||||
self.context_type = AirspaceItemType.PARAGLIDING_ZONE
|
||||
self.context_type = AirspaceType.PARAGLIDING_ZONE
|
||||
case 'LK':
|
||||
self.context_type = AirspaceItemType.ATZ
|
||||
self.context_type = AirspaceType.ATZ
|
||||
case _:
|
||||
self.context_type = AirspaceItemType.TRAGA
|
||||
self.context_type = AirspaceType.TRAGA
|
||||
|
||||
self.context['info'] = value
|
||||
case 'AL':
|
||||
@@ -249,7 +249,7 @@ async def download_airspace(source, destination):
|
||||
async def save_airspace(destination):
|
||||
parser = OpenAirParser(destination)
|
||||
async with get_session() as db:
|
||||
await db.execute(delete(models.AirspaceItem))
|
||||
await db.execute(delete(models.Airspace))
|
||||
|
||||
for item in parser.parse():
|
||||
# if 'CTR KARLOVY VARY' not in item.info:
|
||||
@@ -261,7 +261,7 @@ async def save_airspace(destination):
|
||||
# print("---" * 10)
|
||||
|
||||
async with get_session() as db:
|
||||
await models.AirspaceItem.create(db, {
|
||||
await models.Airspace.create(db, {
|
||||
"country": "cz",
|
||||
"name": item.info,
|
||||
"type": item.type.value,
|
||||
|
||||
@@ -23,6 +23,14 @@ flight_copilots_dataloader = DataLoader(
|
||||
extra_join=[models.Copilot.flights]).load,
|
||||
cache=False)
|
||||
|
||||
reporting_points_dataloader = DataLoader(
|
||||
load_fn=MultiModelsDataloader(
|
||||
models.ReportingPoint,
|
||||
relationship_column=models.airport_has_reporting_point.c.airport_id,
|
||||
extra_join=[models.airport_has_reporting_point]
|
||||
).load, cache=False
|
||||
)
|
||||
|
||||
flights_by_copilot_dataloader = DataLoader(
|
||||
load_fn=MultiModelsDataloader(
|
||||
models.Flight,
|
||||
|
||||
@@ -16,11 +16,11 @@ class AirspaceQueries:
|
||||
|
||||
filters = []
|
||||
if country:
|
||||
filters.append(models.AirspaceItem.country == country)
|
||||
filters.append(models.Airspace.country == country)
|
||||
if types:
|
||||
filters.append(models.AirspaceItem.type.in_(types))
|
||||
filters.append(models.Airspace.type.in_(types))
|
||||
|
||||
return await BaseQueryResolver(Airspace, models.AirspaceItem).get_list(
|
||||
return await BaseQueryResolver(Airspace, models.Airspace).get_list(
|
||||
info.context.user_id,
|
||||
country=country,
|
||||
filters=filters
|
||||
|
||||
@@ -14,7 +14,7 @@ from graphql_schema.dataloaders.multi_models import (
|
||||
photos_dataloader, flights_by_aircraft_dataloader, users_in_organization_dataloader,
|
||||
aircrafts_from_organization_dataloader, user_organizations_dataloader, flights_by_event_dataloader,
|
||||
flights_by_copilot_dataloader, public_flights_by_event_dataloader, public_flights_by_copilot_dataloader,
|
||||
photo_copilots_dataloader, photos_aircraft_dataloader, copilots_in_photo_dataloader, flight_plan_markers_dataloader
|
||||
photo_copilots_dataloader, photos_aircraft_dataloader, copilots_in_photo_dataloader, flight_plan_markers_dataloader, reporting_points_dataloader
|
||||
)
|
||||
from graphql_schema.dataloaders.single_model import (
|
||||
poi_dataloader, poi_type_dataloader, event_dataloader, aircraft_dataloader, airport_dataloader,
|
||||
@@ -46,9 +46,19 @@ class GPXTrack:
|
||||
avg_altitude: float
|
||||
|
||||
|
||||
@strawberry_sqlalchemy_type(models.ReportingPoint)
|
||||
class ReportingPoint:
|
||||
pass
|
||||
|
||||
|
||||
@strawberry_sqlalchemy_type(models.Airport)
|
||||
class Airport:
|
||||
pass
|
||||
reporting_points: List[ReportingPoint] = strawberry.field(
|
||||
resolver=lambda root: reporting_points_dataloader.load(root.id)
|
||||
)
|
||||
|
||||
# TODO: loader na ikonu
|
||||
# TODO: loader na RWY a frekvence
|
||||
|
||||
|
||||
@strawberry.type
|
||||
@@ -58,15 +68,12 @@ class Airspace:
|
||||
country: str
|
||||
type: str
|
||||
lower_limit: str
|
||||
lower_alt_unit: str
|
||||
upper_alt_unit: str
|
||||
upper_limit: str
|
||||
center: Optional[tuple[float, float]]
|
||||
radius: Optional[float]
|
||||
bounds: list[tuple[float, float]]
|
||||
map_center: Optional[Point] = strawberry.field(
|
||||
resolver=lambda root: Point(lat=root.center[0], lng=root.center[1]) if root.center else None
|
||||
)
|
||||
map_bounds: list[Point] = strawberry.field(
|
||||
resolver=lambda root: [Point(lat=point[0], lng=point[1]) for point in root.bounds]
|
||||
resolver=lambda root: [Point(lat=point[1], lng=point[0]) for point in root.bounds]
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user