SQLAlchamy
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, insert, update, delete, text
async def addDocument(db: AsyncSession):
# READ
result = await db.execute(select(User).where(User.id == 1))
user = result.scalar_one_or_none()
# CREATE
db.add(User(name="Rishi"))
await db.commit()
# UPDATE
user.name = "Updated"
await db.commit()
# DELETE
await db.delete(user)
await db.commit()
# RAW SQL
result = await db.execute(text("SELECT * FROM users WHERE id = :id"), {"id": 1})
rows = result.fetchall()
Problem: SQLAlchemy Enum(StatusEnum, native_enum=True) uses enum member names (CHUNKED, SUMMARIZED, EMBEDDED) as database values instead of string values (chunked, summarized, embedded). Error: invalid input value for enum status_enum: "CHUNKED" — DB expects lowercase, got uppercase. Fix: Add values_callable to map enum → .value:
status: Mapped[StatusEnum] = mapped_column(
Enum(
StatusEnum,
native_enum=True,
name="status_enum",
values_callable=lambda x: [e.value for e in x], # ← ADD THIS
),
default=StatusEnum.CHUNKED,
)
Diffrence between AsyncSession and AsyncSessionLocal
AsyncSession is object of sqlalchamy which is used to perform non blocking i/o in db. And AsycnSessionLocal is convention that was made popular in fastapi docs which is of type AsycnSession and is returned my async_sessionmaker() fucntion. It is used with context to execute query on the db.
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
# 1. Create an async engine (e.g., PostgreSQL with asyncpg)
DATABASE_URL = ""
engine = create_async_engine(DATABASE_URL, echo=True)
# 2. Create the async session maker
AsyncSessionLocal = async_sessionmaker(
bind=engine,
class_=AsyncSession,
expire_on_commit=False
)
# 3. Usage inside a function
async def get_user_data(user_id: int):
async with AsyncSessionLocal() as session:
# All DB interactions are awaited
result = await session.execute(
select(User).where(User.id == user_id)
)
user = result.scalar_one_or_none()
return user
making AsyncSession generator Async session generator generates a AsyncSesssion and give it to a what evey called that generator. this generator is context managed which mean the db session will be closed and cleaned up automatically
this is a generator function
async def get_db_session() -> AsyncGenerator[AsyncSession, None]:
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
we need to use async generator when we need to use the session and keep it open even after getting out of the context
async def getClient(self) -> AsyncGenerator:
try:
client = Client(api_key=str(settings.GEMINI_API_KEY))
async with client.aio.live.connect(
model=settings.GEMINI_LIVE_MODEL, config=self.Config
) as session:
# we cannot use return here because when we return the session
# get automatically closed beacuse we are going out of the
# async with context so we need to use asyncgenerator
# return session
yield session
except Exception:
raise
As soon as return session happens, Python exits the async with block. That calls cleanup on the live connection. So the caller receives a session whose context has already been closed or is about to be closed.
Use an async generator/context manager if the caller needs to use the session while keeping the connection open
this is mostly true for context managers if want to use any thing from with in some place we might need to make generator in both async and sync
**What is func and func.count in the sqlalchamy
from sqlalchemy import func
func is a sql function generator. sql databases have some predefined function that we can call via sql for eg COUNT(*) This will sum the rows.
now to use it via sqlalchemy we need to use func like
result = session.execute(select(func.count()).select_from(User).where(User.age>30))
result = result.scalar()
SELECT COUNT(*)
FROM user
WHERE age > 30;
Some database lets us create custom function too.
database pool