A portable object model mapper that can work with any database and model library (dataclasses, Attrs, Pydantic, etc.). It is designed for the general case to support the largest possible number of databases.
Project description
Ommi
[!CAUTION] Ommi is under construction and much of the functionality is undergoing frequent revision. There is no guarantee future versions will be backwards compatible.
Have you ever needed to use a database for a simple project but didn't want to worry about which database you were going to use? Or maybe you wanted to create a package that needed to store data but didn't want to force your users to use a specific database? Meet Ommi, a simple object model mapper that allows you to use whatever models you want to interface with whatever database you like.
Ommi doesn't provide its own model types, it allows you to use whatever models you are already using. Compatibility with the most popular model implementations are ensured through unit tests.
Compatible Model Implementations
Ommi's test suite checks for compatibility with the following model implementations:
Included Database Support
SQLite3
- Table creation from models
- Select, Insert, Update, Delete
Usage
Defining Models
All models that support Ommi database drivers need to use the ommi_model
class decorator.
from ommi import ommi_model, Key
from dataclasses import dataclass
from typing import Annotated
@ommi_model
@dataclass
class User:
name: str
age: int
id: Annotated[int, Key] = None # Optional primary key
Models can be assigned to model collections. Any model not assigned a collection will be assigned to a global
collection which can be accessed by calling ommi.models.get_global_collection()
.
from ommi.model_collections import ModelCollection
collection = ModelCollection()
@ommi_model(collection=collection)
@dataclass
class User:
name: str
age: int
Connecting
from ommi.ext.drivers.sqlite import SQLiteDriver, SQLiteConfig
async def example():
async with SQLiteDriver(SQLiteConfig(filename=":memory:")) as db:
...
Database Actions
The database drivers provide add
, count
, delete,
fetch,
sync_schema, and
updatemethods. These methods should be wrapped in an
ommi.drivers.DatabaseAction. The database action will capture the return and wrap it in a
DatabaseStatusresult that is either a
Successor
Exception. The database action provides an
or_raisemethod that will force the exception to be raised immediately or return a
Successresult. The
DatabaseStatustypes are sub-types of
tramp.results.Result` types.
Add
Add takes any number of model instances and adds them to the database.
user = User(name="Alice", age=25)
await db.add(user).or_raise()
Count
Count takes any number of predicates and returns the number of models that match the predicates. The predicates will be ANDed together.
count = await db.count(User.name == "Alice").or_raise()
Delete
Delete takes any number of model instances and deletes them from the database.
await db.delete(user).or_raise()
Fetch
Fetch takes any number of predicates and returns a result of matching models. The predicates will be ANDed together.
users = await db.fetch(User.name == "Alice").or_raise()
Sync Schema
Sync schema takes a model collection and makes updates the database to match. If no model collection is provided, a global collection is used.
await db.sync_schema().or_raise()
Update
Update takes any number of model instances and syncs their changes to the database.
user.name = "Bob"
await db.update(user).or_raise()
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.