Skip to content
/ coodie Public

coodie = cassandra+beanie(hoodie)

License

Notifications You must be signed in to change notification settings

fruch/coodie

Repository files navigation

coodie logo

coodie

The modern Pydantic-based ODM for Cassandra & ScyllaDB

Cassandra + Beanie (hoodie) = coodie πŸ§₯

CI Status Docs Coverage PyPI Python License

πŸ“– Documentation β€’ πŸš€ Quick Start β€’ 🀝 Contributing β€’ πŸ“‹ Changelog


Define your data models as Python classes, and coodie handles schema synchronization, serialization, and query building β€” with both sync and async APIs.

✨ Feature Highlights

🧬 Pydantic v2 Models β€” full type-checking & validation
⚑ Sync & Async β€” coodie.sync for blocking, coodie.aio for asyncio
πŸ”— Chainable QuerySet β€” .filter() Β· .limit() Β· .order_by()

πŸ”„ Automatic Schema Sync β€” sync_table() creates & evolves tables
πŸ—οΈ Batch & LWT β€” BatchQuery + if_not_exists() support
🎯 Multi-Driver β€” scylla-driver Β· cassandra-driver Β· acsylla

πŸ” How Does coodie Compare?

Feature coodie beanie cqlengine
Database Cassandra / ScyllaDB MongoDB Cassandra
Schema Definition Pydantic v2 BaseModel Pydantic v2 BaseModel Custom columns.* classes
Type Hints βœ… Native Annotated[] βœ… Native Pydantic ❌ No type hints
Async Support βœ… First-class βœ… First-class ❌ Sync only
Sync Support βœ… coodie.sync ❌ Async only βœ… Sync only
Query API Chainable QuerySet Chainable FindMany Chainable QuerySet
Schema Migration βœ… sync_table() ❌ Manual βœ… sync_table()
LWT (Compare-and-Set) βœ… if_not_exists() N/A βœ… iff()
Batch Operations βœ… BatchQuery ❌ βœ… BatchQuery
Counter Columns βœ… Counter() ❌ βœ… columns.Counter
User-Defined Types βœ… UserType ❌ βœ… UserType
TTL Support βœ… Per-save TTL ❌ βœ… Per-save TTL
Pagination βœ… Token-based PagedResult βœ… Cursor-based ❌ Manual
Multiple Drivers βœ… 3 drivers motor only cassandra-driver only
Polymorphic Models βœ… Discriminator ❌ ❌
Python Version 3.10+ 3.8+ 3.6+

πŸ“¦ Installation

pip install coodie

Choose a driver extra for your cluster:

pip install "coodie[scylla]"      # ScyllaDB / Cassandra (recommended)
pip install "coodie[cassandra]"   # Cassandra via cassandra-driver
pip install "coodie[acsylla]"     # Async-native via acsylla

πŸš€ Quick Start

1. Start a local ScyllaDB (or use an existing cluster):

docker run --name scylla -d -p 9042:9042 scylladb/scylla --smp 1

# Wait for it to be ready (~30s), then create a keyspace
docker exec -it scylla cqlsh -e \
  "CREATE KEYSPACE IF NOT EXISTS my_ks
   WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};"

2. Install coodie:

pip install "coodie[scylla]"

3. Write your first script:

from coodie.sync import Document, init_coodie
from coodie.fields import PrimaryKey
from pydantic import Field
from typing import Annotated
from uuid import UUID, uuid4

# Connect
init_coodie(hosts=["127.0.0.1"], keyspace="my_ks")

# Define a model
class User(Document):
    id: Annotated[UUID, PrimaryKey()] = Field(default_factory=uuid4)
    name: str
    email: str

    class Settings:
        name = "users"

# Sync schema & insert
User.sync_table()
user = User(name="Alice", email="[email protected]")
user.save()

# Query
print(User.find(name="Alice").allow_filtering().all())

πŸ’‘ Async? Just swap coodie.sync for coodie.aio and add await β€” that's it!

πŸ“– Usage

Define a Document
from typing import Annotated
from uuid import UUID, uuid4
from pydantic import Field
from coodie import Document, PrimaryKey, ClusteringKey, Indexed

class Product(Document):
    id: Annotated[UUID, PrimaryKey()] = Field(default_factory=uuid4)
    category: Annotated[str, ClusteringKey()] = "general"
    name: str
    brand: Annotated[str, Indexed()] = "Unknown"
    price: float = 0.0

    class Settings:
        name = "products"      # table name (defaults to snake_case class name)
        keyspace = "my_ks"
Async API β€” coodie / coodie.aio
import asyncio
from coodie import init_coodie
# Product defined above β€” same field definitions, using coodie.aio.Document

async def main():
    await init_coodie(hosts=["127.0.0.1"], keyspace="my_ks")
    await Product.sync_table()

    p = Product(name="Gadget", brand="Acme", price=9.99)
    await p.save()

    results = await Product.find(brand="Acme").limit(10).all()
    for product in results:
        print(product.name, product.price)

    gadget = await Product.get(id=p.id)
    await gadget.delete()

asyncio.run(main())
Sync API β€” coodie.sync
from coodie.sync import Document, init_coodie

class Product(Document):
    ...  # same field definitions

init_coodie(hosts=["127.0.0.1"], keyspace="my_ks")
Product.sync_table()

p = Product(name="Widget", price=4.99)
p.save()

results = Product.find(brand="Acme").allow_filtering().all()
one = Product.find_one(name="Widget")
QuerySet Chaining
# Filter, sort, and limit
products = (
    await Product.find()
    .filter(brand="Acme")
    .order_by("price")
    .limit(20)
    .all()
)

# Count
n = await Product.find(brand="Acme").allow_filtering().count()

# Async iteration
async for p in Product.find(brand="Acme"):
    print(p)

# Delete matching rows
await Product.find(brand="Discontinued").allow_filtering().delete()
Field Annotations Reference
Annotation Purpose
PrimaryKey(partition_key_index=0) Partition key column (composite keys via index)
ClusteringKey(order="ASC", clustering_key_index=0) Clustering column
Indexed(index_name=None) Secondary index
Counter() Counter column
Discriminator() Polymorphic model discriminator

πŸ“š Learn More

Resource Link
πŸ“– Full Documentation fruch.github.io/coodie
πŸš€ Quick Start Guide Installation & Quickstart
πŸ“Š Benchmark History Performance Trends
πŸ”„ Migrating from cqlengine Migration Guide
🀝 Contributing CONTRIBUTING.md
πŸ“‹ Changelog CHANGELOG.md
πŸ› Bug Reports GitHub Issues

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Israel Fruchter

πŸ’» πŸ€” πŸ“–

This project follows the all-contributors specification. Contributions of any kind welcome!

Credits

This package was created with Cookiecutter and the browniebroke/cookiecutter-pypackage project template.

About

coodie = cassandra+beanie(hoodie)

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Sponsor this project

Packages

 
 
 

Contributors 5