diff --git a/server/src/data/database.py b/server/src/data/database.py index 01711ae..789eb48 100644 --- a/server/src/data/database.py +++ b/server/src/data/database.py @@ -1,11 +1,20 @@ from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker +from sqlalchemy.orm import sessionmaker, declarative_base, Session # TODO Maybe create env file DATABASE_URL = "mysql+pymysql://wind:wind@193.124.203.110:3306/wind_towers" engine = create_engine(DATABASE_URL) -session_maker = sessionmaker(autocommit=False, autoflush=False, bind=engine) - +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +# Базовый класс для декларативных моделей +Base = declarative_base() +# Функция для получения сессии +def get_db() -> Session: + db = SessionLocal() + try: + yield db + finally: + db.close() diff --git a/server/src/data/models.py b/server/src/data/models.py index e7ef36e..e85f7eb 100644 --- a/server/src/data/models.py +++ b/server/src/data/models.py @@ -1,6 +1,6 @@ from datetime import datetime -from sqlalchemy import Integer, ForeignKey, String +from sqlalchemy import Integer, ForeignKey, String, Float from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase, relationship from sqlalchemy.dialects.mysql import TIMESTAMP, TIME, VARCHAR @@ -28,39 +28,46 @@ class Weather(Base): RainStorm: Mapped[float] RainYear: Mapped[float] SunRise: Mapped[datetime] = mapped_column(TIME) - SunSet:Mapped[datetime] = mapped_column(TIME) + SunSet: Mapped[datetime] = mapped_column(TIME) TempIn: Mapped[float] TempOut: Mapped[float] WindDir: Mapped[str] = mapped_column(VARCHAR(50)) WindSpeed: Mapped[float] WindSpeed10Min: Mapped[float] + class WindTurbineType(Base): __tablename__ = 'wind_turbine_type' Id: Mapped[int] = mapped_column(primary_key=True) Name: Mapped[str] = mapped_column(VARCHAR(255)) - Height: Mapped[float] - BladeLength: Mapped[float] + Height: Mapped[float] = mapped_column(Float) + BladeLength: Mapped[float] = mapped_column(Float) + + # Связь с WindParkTurbine + turbine_parks: Mapped["list[WindParkTurbine]"] = relationship("WindParkTurbine", back_populates="turbine") class WindPark(Base): __tablename__ = 'wind_park' Id: Mapped[int] = mapped_column(primary_key=True) Name: Mapped[str] = mapped_column(VARCHAR(255)) - CenterLatitude: Mapped[float] - CenterLongitude: Mapped[float] + CenterLatitude: Mapped[float] = mapped_column(Float) + CenterLongitude: Mapped[float] = mapped_column(Float) + + # Связь с WindParkTurbine + wind_park_turbines: Mapped["list[WindParkTurbine]"] = relationship("WindParkTurbine", back_populates="wind_park") class WindParkTurbine(Base): __tablename__ = 'wind_park_turbine' - wind_park_id: Mapped[int] = mapped_column(Integer, ForeignKey('wind_park.id'), primary_key=True) - turbine_id: Mapped[int] = mapped_column(Integer, ForeignKey('wind_turbine_type.id'), primary_key=True) + wind_park_id: Mapped[int] = mapped_column(Integer, ForeignKey('wind_park.Id'), primary_key=True) + turbine_id: Mapped[int] = mapped_column(Integer, ForeignKey('wind_turbine_type.Id'), primary_key=True) x_offset: Mapped[int] = mapped_column(Integer, nullable=False) y_offset: Mapped[int] = mapped_column(Integer, nullable=False) angle: Mapped[int] = mapped_column(Integer, nullable=True) comment: Mapped[str] = mapped_column(String(2000), nullable=True) # Связи с другими таблицами - wind_park: Mapped["WindPark"] = relationship("WindPark", back_populates="wind_park_turbines") - turbine: Mapped["WindTurbineType"] = relationship("WindTurbineType", back_populates="turbine_parks") + wind_park: Mapped[WindPark] = relationship("WindPark", back_populates="wind_park_turbines") + turbine: Mapped[WindTurbineType] = relationship("WindTurbineType", back_populates="turbine_parks") diff --git a/server/src/data/repository.py b/server/src/data/repository.py index 84fb1db..760446a 100644 --- a/server/src/data/repository.py +++ b/server/src/data/repository.py @@ -1,9 +1,11 @@ +from typing import List, Type + from sqlalchemy import select from sqlalchemy.orm import Session from .models import WindTurbineType, WindPark, WindParkTurbine -from .schemas import WindTurbineTypeCreate, WindParkCreate, WindParkTurbineCreate -from data.database import session_maker +from .schemas import WindTurbineTypeCreate, WindParkCreate, WindParkTurbineCreate, WindParkResponse, WindTurbineResponse +from data.database import SessionLocal from data.models import Weather from data.schemas import SWeatherInfo @@ -11,7 +13,7 @@ from data.schemas import SWeatherInfo class WeatherRepository: @classmethod def get_all(cls): - with session_maker() as session: + with SessionLocal() as session: query = ( select(Weather) ) @@ -21,7 +23,7 @@ class WeatherRepository: @classmethod def get_by_id(cls, id): - with session_maker() as session: + with SessionLocal() as session: query = ( select(Weather).where(Weather.id == id) ) @@ -64,6 +66,10 @@ class WindTurbineTypeRepository: return True return False + @staticmethod + def get_all_turbines(db: Session) -> list[Type[WindTurbineType]]: + return db.query(WindTurbineType).all() + class WindParkRepository: @staticmethod @@ -98,6 +104,26 @@ class WindParkRepository: return True return False + @staticmethod + def get_all_parks(db: Session) -> list[WindParkResponse]: + return db.query(WindPark).all() + + @staticmethod + def get_turbines_by_park_id(park_id: int, db: Session) -> list[WindTurbineResponse]: + turbines = ( + db.query(WindParkTurbine) + .filter(WindParkTurbine.wind_park_id == park_id) + .all() + ) + + if not turbines: + return [] # Возвращаем пустой список, если не найдено + + turbine_ids = [turbine.turbine_id for turbine in turbines] + turbine_details = db.query(WindTurbineType).filter(WindTurbineType.Id.in_(turbine_ids)).all() + + return turbine_details + class WindParkTurbineRepository: @staticmethod @@ -130,4 +156,4 @@ class WindParkTurbineRepository: db.delete(db_park_turbine) db.commit() return True - return False \ No newline at end of file + return False diff --git a/server/src/data/schemas.py b/server/src/data/schemas.py index 87c0f09..5c72545 100644 --- a/server/src/data/schemas.py +++ b/server/src/data/schemas.py @@ -28,9 +28,11 @@ class WindTurbineTypeBase(BaseModel): Height: float BladeLength: float + class WindTurbineTypeCreate(WindTurbineTypeBase): pass + class WindTurbineTypeResponse(WindTurbineTypeBase): Id: int @@ -43,15 +45,10 @@ class WindParkBase(BaseModel): CenterLatitude: float CenterLongitude: float + class WindParkCreate(WindParkBase): pass -class WindParkResponse(WindParkBase): - Id: int - - class Config: - orm_mode = True - class WindParkTurbineBase(BaseModel): wind_park_id: int @@ -61,9 +58,41 @@ class WindParkTurbineBase(BaseModel): angle: Optional[int] = None comment: Optional[str] = None + class WindParkTurbineCreate(WindParkTurbineBase): pass + class WindParkTurbineResponse(WindParkTurbineBase): class Config: - orm_mode = True \ No newline at end of file + orm_mode = True + + +class WindTurbineType(BaseModel): + Id: int + Name: str + Height: float + BladeLength: float + + class Config: + orm_mode = True + + +class WindParkResponse(BaseModel): + Id: int + Name: str + CenterLatitude: float + CenterLongitude: float + + class Config: + orm_mode = True + + +class WindTurbineResponse(BaseModel): + Id: int + Name: str + Height: float + BladeLength: float + + class Config: + orm_mode = True diff --git a/server/src/main.py b/server/src/main.py index 78939e1..6dbeee5 100644 --- a/server/src/main.py +++ b/server/src/main.py @@ -6,6 +6,7 @@ from fastapi import FastAPI from fastapi.staticfiles import StaticFiles +from routers.wind_park_router import router as wind_park_router from routers.floris_router import router as floris_router from routers.floris_template_router import router as floris_template_router from routers.weather_router import router as weather_router @@ -33,3 +34,4 @@ app.mount("/public", StaticFiles(directory=Path("../public")), name="public") app.include_router(floris_router) app.include_router(floris_template_router) app.include_router(weather_router) +app.include_router(wind_park_router) diff --git a/server/src/routers/wind_park_router.py b/server/src/routers/wind_park_router.py index cac4098..200ca21 100644 --- a/server/src/routers/wind_park_router.py +++ b/server/src/routers/wind_park_router.py @@ -1,8 +1,8 @@ from fastapi import APIRouter, HTTPException, Depends from sqlalchemy.orm import Session -from typing import List -from data.schemas import WindTurbineTypeCreate, WindTurbineTypeResponse, WindParkCreate, WindParkResponse, WindParkTurbineCreate, WindParkTurbineResponse +from data.schemas import WindTurbineTypeCreate, WindTurbineTypeResponse, WindParkCreate, WindParkResponse, \ + WindParkTurbineCreate, WindParkTurbineResponse, WindTurbineResponse from data.database import get_db from data.repository import WindTurbineTypeRepository, WindParkRepository, WindParkTurbineRepository @@ -11,11 +11,13 @@ router = APIRouter( tags=["Wind API"], ) + # Wind Turbine Type CRUD @router.post("/turbine_type/", response_model=WindTurbineTypeResponse) async def create_turbine_type(turbine_type: WindTurbineTypeCreate, db: Session = Depends(get_db)): return WindTurbineTypeRepository.create(db=db, turbine_type=turbine_type) + @router.get("/turbine_type/{turbine_type_id}", response_model=WindTurbineTypeResponse) async def read_turbine_type(turbine_type_id: int, db: Session = Depends(get_db)): turbine_type = WindTurbineTypeRepository.get(db=db, turbine_type_id=turbine_type_id) @@ -23,24 +25,29 @@ async def read_turbine_type(turbine_type_id: int, db: Session = Depends(get_db)) raise HTTPException(status_code=404, detail="Turbine Type not found") return turbine_type + @router.put("/turbine_type/{turbine_type_id}", response_model=WindTurbineTypeResponse) async def update_turbine_type(turbine_type_id: int, turbine_type: WindTurbineTypeCreate, db: Session = Depends(get_db)): - updated_turbine_type = WindTurbineTypeRepository.update(db=db, turbine_type_id=turbine_type_id, turbine_type=turbine_type) + updated_turbine_type = WindTurbineTypeRepository.update(db=db, turbine_type_id=turbine_type_id, + turbine_type=turbine_type) if updated_turbine_type is None: raise HTTPException(status_code=404, detail="Turbine Type not found") return updated_turbine_type + @router.delete("/turbine_type/{turbine_type_id}", status_code=204) async def delete_turbine_type(turbine_type_id: int, db: Session = Depends(get_db)): result = WindTurbineTypeRepository.delete(db=db, turbine_type_id=turbine_type_id) if not result: raise HTTPException(status_code=404, detail="Turbine Type not found") + # Wind Park CRUD @router.post("/park/", response_model=WindParkResponse) async def create_park(park: WindParkCreate, db: Session = Depends(get_db)): return WindParkRepository.create(db=db, park=park) + @router.get("/park/{park_id}", response_model=WindParkResponse) async def read_park(park_id: int, db: Session = Depends(get_db)): park = WindParkRepository.get(db=db, park_id=park_id) @@ -48,6 +55,7 @@ async def read_park(park_id: int, db: Session = Depends(get_db)): raise HTTPException(status_code=404, detail="Park not found") return park + @router.put("/park/{park_id}", response_model=WindParkResponse) async def update_park(park_id: int, park: WindParkCreate, db: Session = Depends(get_db)): updated_park = WindParkRepository.update(db=db, park_id=park_id, park=park) @@ -55,17 +63,20 @@ async def update_park(park_id: int, park: WindParkCreate, db: Session = Depends( raise HTTPException(status_code=404, detail="Park not found") return updated_park + @router.delete("/park/{park_id}", status_code=204) async def delete_park(park_id: int, db: Session = Depends(get_db)): result = WindParkRepository.delete(db=db, park_id=park_id) if not result: raise HTTPException(status_code=404, detail="Park not found") + # Wind Park Turbine CRUD @router.post("/park_turbine/", response_model=WindParkTurbineResponse) async def create_park_turbine(park_turbine: WindParkTurbineCreate, db: Session = Depends(get_db)): return WindParkTurbineRepository.create(db=db, park_turbine=park_turbine) + @router.get("/park_turbine/{park_turbine_id}", response_model=WindParkTurbineResponse) async def read_park_turbine(park_turbine_id: int, db: Session = Depends(get_db)): park_turbine = WindParkTurbineRepository.get(db=db, park_turbine_id=park_turbine_id) @@ -73,15 +84,41 @@ async def read_park_turbine(park_turbine_id: int, db: Session = Depends(get_db)) raise HTTPException(status_code=404, detail="Park Turbine not found") return park_turbine + @router.put("/park_turbine/{park_turbine_id}", response_model=WindParkTurbineResponse) async def update_park_turbine(park_turbine_id: int, park_turbine: WindParkTurbineCreate, db: Session = Depends(get_db)): - updated_park_turbine = WindParkTurbineRepository.update(db=db, park_turbine_id=park_turbine_id, park_turbine=park_turbine) + updated_park_turbine = WindParkTurbineRepository.update(db=db, park_turbine_id=park_turbine_id, + park_turbine=park_turbine) if updated_park_turbine is None: raise HTTPException(status_code=404, detail="Park Turbine not found") return updated_park_turbine + @router.delete("/park_turbine/{park_turbine_id}", status_code=204) async def delete_park_turbine(park_turbine_id: int, db: Session = Depends(get_db)): result = WindParkTurbineRepository.delete(db=db, park_turbine_id=park_turbine_id) if not result: raise HTTPException(status_code=404, detail="Park Turbine not found") + + +@router.get("/parks/", response_model=list[WindParkResponse]) +async def get_all_parks(db: Session = Depends(get_db)): + """Получить все ветропарки""" + return WindParkRepository.get_all_parks(db) + + +@router.get("/parks/{park_id}/turbines/", response_model=list[WindTurbineResponse]) +async def get_turbines_by_park_id(park_id: int, db: Session = Depends(get_db)): + """Получить все турбины в ветропарке по ID""" + turbines = WindParkRepository.get_turbines_by_park_id(park_id, db) + + if not turbines: + raise HTTPException(status_code=404, detail="Турбины не найдены для данного ветропарка") + + return turbines + + +@router.get("/turbines/", response_model=list[WindTurbineResponse]) +async def get_all_turbines(db: Session = Depends(get_db)): + """Получить все турбины""" + return WindTurbineTypeRepository.get_all_turbines(db)