-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #101 from hotosm/feat/drone-crud-operations
Feat/drone crud operations
- Loading branch information
Showing
5 changed files
with
264 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
from app.drones import drone_schemas | ||
from app.models.enums import HTTPStatus | ||
from databases import Database | ||
from loguru import logger as log | ||
from fastapi import HTTPException | ||
from asyncpg import UniqueViolationError | ||
from typing import List | ||
from app.drones.drone_schemas import DroneOut | ||
|
||
|
||
async def read_all_drones(db: Database) -> List[DroneOut]: | ||
""" | ||
Retrieves all drone records from the database. | ||
Args: | ||
db (Database): The database connection object. | ||
Returns: | ||
List[DroneOut]: A list of all drone records. | ||
""" | ||
try: | ||
select_query = """ | ||
SELECT * FROM drones | ||
""" | ||
results = await db.fetch_all(select_query) | ||
return results | ||
|
||
except Exception as e: | ||
log.exception(e) | ||
raise HTTPException( | ||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Retrieval failed" | ||
) from e | ||
|
||
|
||
async def delete_drone(db: Database, drone_id: int) -> bool: | ||
""" | ||
Deletes a drone record from the database, along with associated drone flights. | ||
Args: | ||
db (Database): The database connection object. | ||
drone_id (int): The ID of the drone to be deleted. | ||
Returns: | ||
bool: True if the drone was successfully deleted, False otherwise. | ||
""" | ||
try: | ||
delete_query = """ | ||
WITH deleted_flights AS ( | ||
DELETE FROM drone_flights | ||
WHERE drone_id = :drone_id | ||
RETURNING drone_id | ||
) | ||
DELETE FROM drones | ||
WHERE id = :drone_id | ||
""" | ||
await db.execute(delete_query, {"drone_id": drone_id}) | ||
return True | ||
|
||
except Exception as e: | ||
log.exception(e) | ||
raise HTTPException( | ||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Deletion failed" | ||
) from e | ||
|
||
|
||
async def get_drone(db: Database, drone_id: int): | ||
""" | ||
Retrieves a drone record from the database. | ||
Args: | ||
db (Database): The database connection object. | ||
drone_id (int): The ID of the drone to be retrieved. | ||
Returns: | ||
dict: The drone record if found, otherwise None. | ||
""" | ||
try: | ||
select_query = """ | ||
SELECT * FROM drones | ||
WHERE id = :id | ||
""" | ||
result = await db.fetch_one(select_query, {"id": drone_id}) | ||
return result | ||
|
||
except Exception as e: | ||
log.exception(e) | ||
raise HTTPException( | ||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Retrieval failed" | ||
) from e | ||
|
||
|
||
async def create_drone(db: Database, drone_info: drone_schemas.DroneIn): | ||
""" | ||
Creates a new drone record in the database. | ||
Args: | ||
db (Database): The database connection object. | ||
drone (drone_schemas.DroneIn): The schema object containing drone details. | ||
Returns: | ||
The ID of the newly created drone record. | ||
""" | ||
try: | ||
insert_query = """ | ||
INSERT INTO drones ( | ||
model, manufacturer, camera_model, sensor_width, sensor_height, | ||
max_battery_health, focal_length, image_width, image_height, | ||
max_altitude, max_speed, weight, created | ||
) VALUES ( | ||
:model, :manufacturer, :camera_model, :sensor_width, :sensor_height, | ||
:max_battery_health, :focal_length, :image_width, :image_height, | ||
:max_altitude, :max_speed, :weight, CURRENT_TIMESTAMP | ||
) | ||
RETURNING id | ||
""" | ||
result = await db.execute(insert_query, drone_info.__dict__) | ||
return result | ||
|
||
except UniqueViolationError as e: | ||
log.exception("Unique constraint violation: %s", e) | ||
raise HTTPException( | ||
status_code=HTTPStatus.CONFLICT, | ||
detail="A drone with this model already exists", | ||
) | ||
|
||
except Exception as e: | ||
log.exception(e) | ||
raise HTTPException( | ||
status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail="Drone creation failed" | ||
) from e |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
from app.users.user_deps import login_required | ||
from app.users.user_schemas import AuthUser | ||
from app.models.enums import HTTPStatus | ||
from fastapi import APIRouter, Depends, HTTPException | ||
from app.db.database import get_db | ||
from app.config import settings | ||
from app.drones import drone_schemas | ||
from databases import Database | ||
from app.drones import drone_crud | ||
from typing import List | ||
|
||
|
||
router = APIRouter( | ||
prefix=f"{settings.API_PREFIX}/drones", | ||
responses={404: {"description": "Not found"}}, | ||
) | ||
|
||
|
||
@router.get("/", tags=["Drones"], response_model=List[drone_schemas.DroneOut]) | ||
async def read_drones( | ||
db: Database = Depends(get_db), | ||
user_data: AuthUser = Depends(login_required), | ||
): | ||
""" | ||
Retrieves all drone records from the database. | ||
Args: | ||
db (Database, optional): The database session object. | ||
user_data (AuthUser, optional): The authenticated user data. | ||
Returns: | ||
List[drone_schemas.DroneOut]: A list of all drone records. | ||
""" | ||
drones = await drone_crud.read_all_drones(db) | ||
return drones | ||
|
||
|
||
@router.delete("/{drone_id}", tags=["Drones"]) | ||
async def delete_drone( | ||
drone_id: int, | ||
db: Database = Depends(get_db), | ||
user_data: AuthUser = Depends(login_required), | ||
): | ||
""" | ||
Deletes a drone record from the database. | ||
Args: | ||
drone_id (int): The ID of the drone to be deleted. | ||
db (Database, optional): The database session object. | ||
user_data (AuthUser, optional): The authenticated user data. | ||
Returns: | ||
dict: A success message if the drone was deleted. | ||
""" | ||
success = await drone_crud.delete_drone(db, drone_id) | ||
if not success: | ||
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Drone not found") | ||
return {"message": "Drone deleted successfully"} | ||
|
||
|
||
@router.post("/create_drone", tags=["Drones"]) | ||
async def create_drone( | ||
drone_info: drone_schemas.DroneIn, | ||
db: Database = Depends(get_db), | ||
user_data: AuthUser = Depends(login_required), | ||
): | ||
""" | ||
Creates a new drone record in the database. | ||
Args: | ||
drone_info (drone_schemas.DroneIn): The schema object containing drone details. | ||
db (Database, optional): The database session object. | ||
user_data (AuthUser, optional): The authenticated user data. | ||
Returns: | ||
dict: A dictionary containing a success message and the ID of the newly created drone. | ||
""" | ||
drone_id = await drone_crud.create_drone(db, drone_info) | ||
if not drone_id: | ||
raise HTTPException( | ||
status_code=HTTPStatus.BAD_REQUEST, detail="Drone creation failed" | ||
) | ||
return {"message": "Drone created successfully", "drone_id": drone_id} | ||
|
||
|
||
@router.get("/{drone_id}", tags=["Drones"], response_model=drone_schemas.DroneOut) | ||
async def read_drone( | ||
drone_id: int, | ||
db: Database = Depends(get_db), | ||
user_data: AuthUser = Depends(login_required), | ||
): | ||
""" | ||
Retrieves a drone record from the database. | ||
Args: | ||
drone_id (int): The ID of the drone to be retrieved. | ||
db (Database, optional): The database session object. | ||
user_data (AuthUser, optional): The authenticated user data. | ||
Returns: | ||
dict: The drone record if found. | ||
""" | ||
drone = await drone_crud.get_drone(db, drone_id) | ||
if not drone: | ||
raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Drone not found") | ||
return drone |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
from pydantic import BaseModel | ||
|
||
|
||
class DroneIn(BaseModel): | ||
model: str | ||
manufacturer: str | ||
camera_model: str | ||
sensor_width: float | ||
sensor_height: float | ||
max_battery_health: float | ||
focal_length: float | ||
image_width: int | ||
image_height: int | ||
max_altitude: float | ||
max_speed: float | ||
weight: float | ||
|
||
|
||
class DroneOut(BaseModel): | ||
id: int | ||
model: str |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters