diff --git a/app/api/nonsense.py b/app/api/nonsense.py index 2da8313..7a90693 100644 --- a/app/api/nonsense.py +++ b/app/api/nonsense.py @@ -1,4 +1,7 @@ -from fastapi import APIRouter, Depends, status +import io +from fastapi import APIRouter, Depends, status, UploadFile, HTTPException +from sqlalchemy.exc import SQLAlchemyError +import polars as pl from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db @@ -48,3 +51,37 @@ async def merge_nonsense( nonsense = Nonsense(**payload.model_dump()) await nonsense.save_or_update(db_session) return nonsense + + +@router.post( + "/import", + status_code=status.HTTP_201_CREATED, +) +async def import_nonsense( + xlsx: UploadFile, + db_session: AsyncSession = Depends(get_db), +): + file_bytes = await xlsx.read() + + nonsense_data = pl.read_excel( + source=io.BytesIO(file_bytes), + sheet_name="New Nonsense", + engine="calamine", + ) + + try: + nonsense_records = [ + Nonsense( + name=nonsense.get("name"), + description=nonsense.get("description"), + ) + for nonsense in nonsense_data.to_dicts() + ] + db_session.add_all(nonsense_records) + await db_session.commit() + return {"filename": xlsx.filename, "nonsense_records": len(nonsense_records)} + except (SQLAlchemyError, HTTPException) as ex: + await db_session.rollback() + raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=repr(ex)) from ex + finally: + await db_session.close() diff --git a/app/models/shakespeare.py b/app/models/shakespeare.py index b4db11b..411984e 100644 --- a/app/models/shakespeare.py +++ b/app/models/shakespeare.py @@ -63,6 +63,7 @@ class Wordform(Base): - `occurrences` (int): The number of occurrences of the word form. """ + __tablename__ = "wordform" __table_args__ = (PrimaryKeyConstraint("id", name="wordform_pkey"), {"schema": "shakespeare"}) @@ -133,6 +134,7 @@ class Chapter(Base): - `paragraph` (list[Paragraph]): The paragraphs associated with the chapter. """ + __tablename__ = "chapter" __table_args__ = ( ForeignKeyConstraint(["work_id"], ["shakespeare.work.id"], name="chapter_work_id_fkey"), @@ -193,6 +195,7 @@ class Paragraph(Base): - `find(cls, db_session: AsyncSession, character: str) -> List[Paragraph]`: A class method that finds paragraphs associated with a specific character. It takes a database session and the name of the character as arguments, and returns a list of matching paragraphs. """ + __tablename__ = "paragraph" __table_args__ = ( ForeignKeyConstraint(["character_id"], ["shakespeare.character.id"], name="paragraph_character_id_fkey"), diff --git a/app/models/stuff.py b/app/models/stuff.py index 8bf33af..af9b86b 100644 --- a/app/models/stuff.py +++ b/app/models/stuff.py @@ -27,11 +27,7 @@ class Stuff(Base): :param name: :return: """ - stmt = ( - select(cls) - .options(joinedload(cls.nonsense)) - .where(cls.name == name) - ) + stmt = select(cls).options(joinedload(cls.nonsense)).where(cls.name == name) result = await db_session.execute(stmt) instance = result.scalars().first() if instance is None: