Database & ORM
Caspian provides a type-safe, auto-generated Async Python client for your database. Follow this guide to configure your environment, define your schema, and perform non-blocking operations.
Environment Setup
Define your database connection string in the
.env
file. This is the entry point for the Prisma engine.
# Connect to SQLite (Recommended for dev) DATABASE_URL="file:./prisma/dev.db" # Or PostgreSQL / MySQL (Recommended for Async/Production) # DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
Global Configuration
Use
prisma.config.ts
to configure seeding behavior and global ORM settings.
export default seed: import: "./prisma/seed.ts", autoRun: true , client: logLevel: "info"
Define Your Schema
Model your data in
prisma/schema.prisma. This single file acts as the source of truth.
datasource db provider = "sqlite" model User id String @id @default(cuid()) email String @unique name String? posts Post[] model Post id String @id @default(cuid()) title String published Boolean @default(false) authorId String author User @relation(fields: [authorId], references: [id])
Command Reference
Use the CLI to sync, migrate, and seed your database.
| Command | Description |
|---|---|
| npx ppy generate |
Critical Compiles the Prisma schema into a type-safe Python client. Run this after every schema change. |
| npx prisma migrate dev | Creates a new SQL migration file based on your schema changes and applies it to the development database. |
| npx prisma migrate deploy | Applies pending migrations to production databases. Use this in your CI/CD pipelines. |
| npx prisma db push | Quickly syncs the database schema without creating a migration file. Great for prototyping. |
| npx prisma db seed |
Populates the database with initial data defined in your seeding
script (configured in prisma.config.ts).
|
| npx prisma studio | Opens a visual GUI in your browser to inspect, edit, and manage database records manually. |
Async Client Usage
Import the global
prisma instance. It is
pre-configured and ready to use. The client is
fully asynchronous, so always use
await for database operations.
Ready-to-Use Import
from src.lib.prisma.db import prisma # No manual connection required. # Just import and await.
Non-Blocking I/O
Queries run on the event loop, allowing your application to handle concurrent requests efficiently. Ideal for high-performance RPC agents and endpoints.
Create
user = await prisma.user.create( data= 'email': "alice@example.com", 'name': "Alice", )
Read
posts = await prisma.post.find_many( where= 'published': True, 'title': 'contains': "Caspian" , order_by= 'createdAt': 'desc' )
# Fetch user and join their role data user = await prisma.user.find_unique( where= 'email': "alice@example.com" , include= 'userRole': True )
Update
Atomic updates are supported for numeric fields.
await prisma.user.update( where='id': "123", data= 'name': "New Name", # Atomic increment 'loginCount': 'increment': 1 )
Delete
# Delete specific record await prisma.user.delete(where='id': "123") # Batch delete await prisma.log.delete_many( where= 'createdAt': 'lt': yesterday )
Create
user = await prisma.user.create( data= 'email': "alice@example.com", 'name': "Alice", )
Read
posts = await prisma.post.find_many( where= 'published': True, 'title': 'contains': "Caspian" , order_by= 'createdAt': 'desc' )
# Fetch user and join their role data user = await prisma.user.find_unique( where= 'email': "alice@example.com" , include= 'userRole': True , select= 'id': True, 'name': True )
Update
Atomic updates are supported for numeric fields.
await prisma.user.update( where='id': "123", data= 'name': "New Name", # Atomic increment 'loginCount': 'increment': 1 )
Delete
# Delete specific record await prisma.user.delete(where='id': "123") # Batch delete await prisma.log.delete_many( where= 'createdAt': 'lt': yesterday )
Advanced Features
Aggregations
Perform calculations directly in the database using
aggregate or
group_by.
stats = await prisma.sales.aggregate( _sum='amount': True, _avg='rating': True, where='status': "completed" ) print(stats['_sum']['amount'])
Async Transactions
Ensure data integrity with atomic transactions. If any operation fails, all are rolled back.
async with prisma.tx() as tx: user = await tx.user.create(data=...) await tx.log.create(data= 'action': "CREATED_USER", 'userId': user.id )
Raw SQL Fallback
For complex queries that cannot be expressed via the ORM, use
query_raw or
execute_raw.
# Safe parameterized raw query users = await prisma.query_raw( "SELECT * FROM User WHERE email LIKE ?", "%@gmail.com" )