From 8d4dda666ff1949d9cd49804dd669c08b2b1890c Mon Sep 17 00:00:00 2001 From: Backend IM Bot Date: Mon, 21 Apr 2025 17:00:50 +0000 Subject: [PATCH] feat: Generated endpoint endpoints/fruits.get.py via AI for Fruit with auto lint fixes --- .../20250421_165959_3dee6a81_update_fruit.py | 33 ++++ endpoints/fruits.get.py | 30 ++++ helpers/fruit_helpers.py | 163 ++++++++++++++++++ models/fruit.py | 21 +++ schemas/fruit.py | 42 +++++ 5 files changed, 289 insertions(+) create mode 100644 alembic/versions/20250421_165959_3dee6a81_update_fruit.py create mode 100644 helpers/fruit_helpers.py create mode 100644 models/fruit.py create mode 100644 schemas/fruit.py diff --git a/alembic/versions/20250421_165959_3dee6a81_update_fruit.py b/alembic/versions/20250421_165959_3dee6a81_update_fruit.py new file mode 100644 index 0000000..55715ec --- /dev/null +++ b/alembic/versions/20250421_165959_3dee6a81_update_fruit.py @@ -0,0 +1,33 @@ +"""create table for Fruit +Revision ID: a2b3c4d5e6f7 +Revises: 0001 +Create Date: 2023-07-20 12:00:00.000000 +""" +from alembic import op +import sqlalchemy as sa +from sqlalchemy.sql import func + +# revision identifiers, used by Alembic. +revision = 'a2b3c4d5e6f7' +down_revision = '0001' +branch_labels = None +depends_on = None + + +def upgrade(): + op.create_table( + 'fruits', + sa.Column('id', sa.String(36), primary_key=True), + sa.Column('name', sa.String(), nullable=False), + sa.Column('description', sa.Text(), nullable=True), + sa.Column('color', sa.String(), nullable=True), + sa.Column('is_seasonal', sa.Boolean(), default=False), + sa.Column('created_at', sa.DateTime(), server_default=func.now()), + sa.Column('updated_at', sa.DateTime(), server_default=func.now()), + ) + op.create_index(op.f('ix_fruits_name'), 'fruits', ['name'], unique=False) + + +def downgrade(): + op.drop_index(op.f('ix_fruits_name'), table_name='fruits') + op.drop_table('fruits') \ No newline at end of file diff --git a/endpoints/fruits.get.py b/endpoints/fruits.get.py index e69de29..21803f2 100644 --- a/endpoints/fruits.get.py +++ b/endpoints/fruits.get.py @@ -0,0 +1,30 @@ +from fastapi import APIRouter, Depends, Query, status +from typing import List, Optional +from sqlalchemy.orm import Session +from core.database import get_db +from schemas.fruit import FruitSchema +from helpers.fruit_helpers import get_all_fruits + +router = APIRouter() + +@router.get("/fruits", response_model=List[FruitSchema], status_code=status.HTTP_200_OK) +async def get_fruits( + skip: int = Query(0, ge=0, description="Number of records to skip"), + limit: int = Query(100, ge=1, le=100, description="Maximum number of records to return"), + sort_by: Optional[str] = Query(None, description="Field to sort by (name, color, etc.)"), + sort_order: str = Query("asc", description="Sort direction ('asc' or 'desc')"), + filter_seasonal: Optional[bool] = Query(None, description="Filter by seasonal status"), + db: Session = Depends(get_db) +): + """ + Get all fruits with optional filtering, sorting, and pagination. + """ + fruits = get_all_fruits( + db=db, + skip=skip, + limit=limit, + sort_by=sort_by, + sort_order=sort_order, + filter_seasonal=filter_seasonal + ) + return fruits \ No newline at end of file diff --git a/helpers/fruit_helpers.py b/helpers/fruit_helpers.py new file mode 100644 index 0000000..c9c9fad --- /dev/null +++ b/helpers/fruit_helpers.py @@ -0,0 +1,163 @@ +from typing import List, Optional +from sqlalchemy.orm import Session +from sqlalchemy import desc, asc +from uuid import UUID + +# Import the model and schema +from models.fruit import Fruit +from schemas.fruit import FruitCreate, FruitUpdate + +def get_all_fruits( + db: Session, + skip: int = 0, + limit: int = 100, + sort_by: Optional[str] = None, + sort_order: str = "asc", + filter_seasonal: Optional[bool] = None +) -> List[Fruit]: + """ + Retrieves all fruits from the database with optional pagination, sorting, and filtering. + + Args: + db (Session): The database session. + skip (int, optional): Number of records to skip. Defaults to 0. + limit (int, optional): Maximum number of records to return. Defaults to 100. + sort_by (Optional[str], optional): Field to sort by. Defaults to None. + sort_order (str, optional): Sort direction ('asc' or 'desc'). Defaults to "asc". + filter_seasonal (Optional[bool], optional): Filter by seasonal status. Defaults to None. + + Returns: + List[Fruit]: A list of fruit objects. + """ + query = db.query(Fruit) + + # Apply seasonal filter if specified + if filter_seasonal is not None: + query = query.filter(Fruit.is_seasonal == filter_seasonal) + + # Apply sorting if specified + if sort_by and hasattr(Fruit, sort_by): + sort_column = getattr(Fruit, sort_by) + if sort_order.lower() == "desc": + query = query.order_by(desc(sort_column)) + else: + query = query.order_by(asc(sort_column)) + + # Apply pagination + return query.offset(skip).limit(limit).all() + +def get_fruit_by_id(db: Session, fruit_id: UUID) -> Optional[Fruit]: + """ + Retrieves a single fruit by its ID. + + Args: + db (Session): The database session. + fruit_id (UUID): The ID of the fruit to retrieve. + + Returns: + Optional[Fruit]: The fruit object if found, otherwise None. + """ + return db.query(Fruit).filter(Fruit.id == fruit_id).first() + +def get_fruits_by_color(db: Session, color: str) -> List[Fruit]: + """ + Retrieves all fruits matching a specific color. + + Args: + db (Session): The database session. + color (str): The color to filter by. + + Returns: + List[Fruit]: A list of fruit objects with the specified color. + """ + return db.query(Fruit).filter(Fruit.color == color).all() + +def get_seasonal_fruits(db: Session) -> List[Fruit]: + """ + Retrieves all seasonal fruits from the database. + + Args: + db (Session): The database session. + + Returns: + List[Fruit]: A list of seasonal fruit objects. + """ + return db.query(Fruit).filter(Fruit.is_seasonal).all() + +def create_fruit(db: Session, fruit_data: FruitCreate) -> Fruit: + """ + Creates a new fruit in the database. + + Args: + db (Session): The database session. + fruit_data (FruitCreate): The data for the fruit to create. + + Returns: + Fruit: The newly created fruit object. + """ + db_fruit = Fruit(**fruit_data.dict()) + db.add(db_fruit) + db.commit() + db.refresh(db_fruit) + return db_fruit + +def update_fruit(db: Session, fruit_id: UUID, fruit_data: FruitUpdate) -> Optional[Fruit]: + """ + Updates an existing fruit in the database. + + Args: + db (Session): The database session. + fruit_id (UUID): The ID of the fruit to update. + fruit_data (FruitUpdate): The data to update the fruit with. + + Returns: + Optional[Fruit]: The updated fruit object if found, otherwise None. + """ + db_fruit = get_fruit_by_id(db, fruit_id) + if not db_fruit: + return None + + # Update only the fields that are provided + update_data = fruit_data.dict(exclude_unset=True) + for key, value in update_data.items(): + setattr(db_fruit, key, value) + + db.commit() + db.refresh(db_fruit) + return db_fruit + +def delete_fruit(db: Session, fruit_id: UUID) -> bool: + """ + Deletes a fruit from the database. + + Args: + db (Session): The database session. + fruit_id (UUID): The ID of the fruit to delete. + + Returns: + bool: True if the fruit was deleted, False if not found. + """ + db_fruit = get_fruit_by_id(db, fruit_id) + if not db_fruit: + return False + + db.delete(db_fruit) + db.commit() + return True + +def search_fruits(db: Session, search_term: str) -> List[Fruit]: + """ + Searches for fruits by name or description. + + Args: + db (Session): The database session. + search_term (str): The term to search for. + + Returns: + List[Fruit]: A list of fruit objects matching the search term. + """ + search_pattern = f"%{search_term}%" + return db.query(Fruit).filter( + (Fruit.name.ilike(search_pattern)) | + (Fruit.description.ilike(search_pattern)) + ).all() \ No newline at end of file diff --git a/models/fruit.py b/models/fruit.py new file mode 100644 index 0000000..f0b1b32 --- /dev/null +++ b/models/fruit.py @@ -0,0 +1,21 @@ +from sqlalchemy import Column, String, DateTime, Text, Boolean +from sqlalchemy.dialects.postgresql import UUID +from sqlalchemy.sql import func +from core.database import Base +import uuid + +class Fruit(Base): + __tablename__ = "fruits" + + # Primary key using UUID + id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) + + # Basic fruit properties + name = Column(String, nullable=False, index=True) + description = Column(Text, nullable=True) + color = Column(String, nullable=True) + is_seasonal = Column(Boolean, default=False) + + # Timestamps + created_at = Column(DateTime, default=func.now()) + updated_at = Column(DateTime, default=func.now(), onupdate=func.now()) \ No newline at end of file diff --git a/schemas/fruit.py b/schemas/fruit.py new file mode 100644 index 0000000..7a0d977 --- /dev/null +++ b/schemas/fruit.py @@ -0,0 +1,42 @@ +from pydantic import BaseModel, Field +from typing import Optional +from datetime import datetime +from uuid import UUID + +# Base schema for Fruit, used for inheritance +class FruitBase(BaseModel): + name: str = Field(..., description="Name of the fruit") + description: Optional[str] = Field(None, description="Description of the fruit") + color: Optional[str] = Field(None, description="Color of the fruit") + is_seasonal: bool = Field(False, description="Whether the fruit is seasonal") + +# Schema for creating a new Fruit +class FruitCreate(FruitBase): + pass + +# Schema for updating an existing Fruit (all fields optional) +class FruitUpdate(BaseModel): + name: Optional[str] = Field(None, description="Name of the fruit") + description: Optional[str] = Field(None, description="Description of the fruit") + color: Optional[str] = Field(None, description="Color of the fruit") + is_seasonal: Optional[bool] = Field(None, description="Whether the fruit is seasonal") + +# Schema for representing a Fruit in responses +class FruitSchema(FruitBase): + id: UUID + created_at: datetime + updated_at: datetime + + class Config: + orm_mode = True + schema_extra = { + "example": { + "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", + "name": "Apple", + "description": "A round fruit with red, yellow, or green skin and crisp flesh", + "color": "Red", + "is_seasonal": True, + "created_at": "2023-01-01T12:00:00", + "updated_at": "2023-01-01T12:00:00" + } + } \ No newline at end of file