A framework for storing and managing component and application data for machine apps.
Project description
Vention Storage
A framework for storing and managing component and application data with persistence, validation, and audit trails for machine applications.
Table of Contents
- ✨ Features
- 🧠 Concepts & Overview
- ⚙️ Installation & Setup
- 🚀 Quickstart Tutorial
- 🛠 How-to Guides
- 📖 API Reference
- 🔍 Troubleshooting & FAQ
✨ Features
- Persistent storage with SQLite
- Automatic audit trails (who, when, what changed)
- Strong typing & validation via SQLModel
- Lifecycle hooks before/after insert, update, delete
- Soft delete with
deleted_atfields - ConnectRPC bundle generation with Create, Read, Update, Delete + audit
- Health & monitoring actions (audit log, schema diagram)
- Batch operations for insert/delete
- Session management with smart reuse & transactions
- Bootstrap system for one-command setup
- CSV export/import for backups and migration
- Database backup/restore with integrity checking
🧠 Concepts & Overview
Vention Storage is a component-based persistence layer for machine apps:
- Database → SQLite database with managed sessions and transactions
- ModelAccessor → Strongly-typed Create, Read, Update, Delete interface for your SQLModel classes
- Hooks → Functions that run before/after Create, Read, Update, Delete operations
- AuditLog → Automatically records all data mutations
- RpcBundle → Auto-generated ConnectRPC bundle with Create, Read, Update, Delete + database management actions
⚙️ Installation & Setup
pip install vention-storage
Optional dependencies:
- sqlalchemy-schemadisplay and Graphviz → enable database schema visualization
MacOS:
brew install graphviz
pip install sqlalchemy-schemadisplay
Linux (Debian/Ubuntu)
sudo apt-get install graphviz
pip install sqlalchemy-schemadisplay
🚀 Quickstart Tutorial
Define a model, bootstrap storage, and get full Create, Read, Update, Delete RPC actions in minutes:
from datetime import datetime
from typing import Optional
from sqlmodel import Field, SQLModel
from communication.app import VentionApp
from storage.bootstrap import bootstrap
from storage.accessor import ModelAccessor
from storage.vention_communication import build_storage_bundle
class User(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str
email: str
deleted_at: Optional[datetime] = Field(default=None, index=True)
# Initialize database
bootstrap(
database_url="sqlite:///./my_app.db",
create_tables=True
)
# Create accessor
user_accessor = ModelAccessor(User, "users")
# Build RPC bundle and add to app
app = VentionApp(name="my-app")
storage_bundle = build_storage_bundle(
accessors=[user_accessor],
max_records_per_model=100,
enable_db_actions=True
)
app.add_bundle(storage_bundle)
app.finalize()
➡️ You now have Create, Read, Update, Delete, audit, backup, and CSV actions available via ConnectRPC.
🛠 How-to Guides
Bootstrap Multiple Models
# user_accessor was created earlier in the Quickstart example
# Reuse it here to bootstrap multiple models at once
product_accessor = ModelAccessor(Product, "products")
# Build bundle with multiple accessors
storage_bundle = build_storage_bundle(
accessors=[user_accessor, product_accessor],
max_records_per_model=100,
enable_db_actions=True
)
app.add_bundle(storage_bundle)
Export to CSV
# Using ConnectRPC client
from communication.client import ConnectClient
client = ConnectClient("http://localhost:8000")
response = await client.call("Database_ExportZip", {})
with open("backup.zip", "wb") as f:
f.write(response.data)
Backup & Restore
# Backup
backup_response = await client.call("Database_BackupSqlite", {})
with open(backup_response.filename, "wb") as f:
f.write(backup_response.data)
# Restore
with open("backup.sqlite", "rb") as f:
restore_response = await client.call(
"Database_RestoreSqlite",
{
"bytes": f.read(),
"filename": "backup.sqlite",
"integrity_check": True,
"dry_run": False
}
)
Use Lifecycle Hooks
@user_accessor.before_insert()
def validate_email(session, instance):
if "@" not in instance.email:
raise ValueError("Invalid email")
@user_accessor.after_insert()
def log_creation(session, instance):
print(f"User created: {instance.name}")
Query Audit Logs
from storage.auditor import AuditLog
from sqlmodel import select
with database.transaction() as session:
logs = session.exec(select(AuditLog).where(AuditLog.component == "users")).all()
Using the model accessors
# Create
user = user_accessor.insert(User(name="Alice", email="alice@example.com"), actor="admin")
# Read
user = user_accessor.get(user.id)
# Update
user.name = "Alice Smith"
user_accessor.save(user, actor="admin")
# Delete
user_accessor.delete(user.id, actor="admin")
# Restore (for soft-deleted models)
user_accessor.restore(user.id, actor="admin")
Using ConnectRPC Client
Once the bundle is added to your VentionApp, each ModelAccessor automatically exposes full CRUD actions via ConnectRPC.
Example: interacting with the Users RPC actions.
import { createPromiseClient } from "@connectrpc/connect";
import { createConnectTransport } from "@connectrpc/connect-web";
const transport = createConnectTransport({
baseUrl: "http://localhost:8000",
});
const client = createPromiseClient(YourServiceClient, transport);
// Create
export async function createUser(name: string, email: string) {
const res = await client.usersCreateRecord({
record: { name, email },
actor: "operator"
});
return res.record;
}
// Read
export async function getUser(id: number) {
const res = await client.usersGetRecord({
recordId: id,
includeDeleted: false
});
return res.record;
}
// Update
export async function updateUser(id: number, name: string) {
const res = await client.usersUpdateRecord({
recordId: id,
record: { name },
actor: "operator"
});
return res.record;
}
// Delete (soft delete if model supports deleted_at)
export async function deleteUser(id: number) {
await client.usersDeleteRecord({
recordId: id,
actor: "operator"
});
}
// Restore
export async function restoreUser(id: number) {
const res = await client.usersRestoreRecord({
recordId: id,
actor: "operator"
});
return res.record;
}
// List
export async function listUsers() {
const res = await client.usersListRecords({
includeDeleted: false
});
return res.records;
}
📖 API Reference
bootstrap
def bootstrap(
*,
database_url: Optional[str] = None,
create_tables: bool = True,
) -> None
Initialize the database engine and optionally create tables. This function performs environment setup only.
build_storage_bundle
def build_storage_bundle(
*,
accessors: Sequence[ModelAccessor[Any]],
max_records_per_model: Optional[int] = 5,
enable_db_actions: bool = True,
) -> RpcBundle
Build a ConnectRPC RpcBundle exposing CRUD and database utilities. Returns an RpcBundle that can be added to a VentionApp using app.add_bundle().
ModelAccessor
ModelAccessor(
model: Type[ModelType],
component_name: str,
*,
enable_auditing: bool = True,
)
Read
get(id, include_deleted=False) -> Optional[ModelType]all(include_deleted=False) -> List[ModelType]
Write
insert(obj, actor="internal") -> ModelTypesave(obj, actor="internal") -> ModelTypedelete(id, actor="internal") -> boolrestore(id, actor="internal") -> bool
Batch
insert_many(objs, actor="internal") -> List[ModelType]delete_many(ids, actor="internal") -> int
Hooks
@accessor.before_insert()@accessor.after_insert()@accessor.before_update()@accessor.after_update()@accessor.before_delete()@accessor.after_delete()
Parameters
enable_auditing: IfFalse, disables audit logging for this accessor. Useful for models that shouldn't be audited (e.g., audit logs themselves). Defaults toTrue.
Database Helpers
database.set_database_url(url: str) -> Nonedatabase.get_engine() -> Enginedatabase.transaction() -> Iterator[Session]database.use_session(session: Optional[Session] = None) -> Iterator[Session]
AuditLog model
class AuditLog(SQLModel, table=True):
id: int
timestamp: datetime
component: str
record_id: int
operation: str
actor: str
before: Optional[Dict[str, Any]]
after: Optional[Dict[str, Any]]
🔍 Troubleshooting & FAQ
- Diagram endpoint fails → Ensure Graphviz + sqlalchemy-schemadisplay are installed.
- No audit actor shown → Provide X-User header in API requests.
- Soft delete not working → Your model must have a
deleted_atfield. - Restore fails → Ensure
integrity_check=Truepasses when restoring backups.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vention_storage-0.6.tar.gz.
File metadata
- Download URL: vention_storage-0.6.tar.gz
- Upload date:
- Size: 18.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.10.12 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ffb5b20a0ffcc316868a74a40bc5d4179e0f835b8219ff176fd7238697c8949
|
|
| MD5 |
b4a788d7d979a52307dbc6c60fa3fbcb
|
|
| BLAKE2b-256 |
c7e9ab721cc8ec9efdf92a215fedc2270c6716c2d5a356ef7790f980ba580952
|
File details
Details for the file vention_storage-0.6.0-py3-none-any.whl.
File metadata
- Download URL: vention_storage-0.6.0-py3-none-any.whl
- Upload date:
- Size: 20.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.10.12 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
346a086c2dea0d40ed759397a70066e11cc10db4ba925097f6ed91f90a28d74d
|
|
| MD5 |
355ce9ad331e7de729ce99ee63ebb1ff
|
|
| BLAKE2b-256 |
c013a194a73487d2621a50efccd5b88a06630fdff9b8e41665679fe09d531eff
|
File details
Details for the file vention_storage-0.6-py3-none-any.whl.
File metadata
- Download URL: vention_storage-0.6-py3-none-any.whl
- Upload date:
- Size: 20.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.2.1 CPython/3.10.12 Linux/6.11.0-1018-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a07efbb2fddf6406b85cfeb8529ae74033bb80bbcdd6246caa0ac6bf898ba030
|
|
| MD5 |
8bd4ac4dd238ea6db696cc681c26f4bc
|
|
| BLAKE2b-256 |
58fbe5c0bc3ccb3b29564c7990a1ba40a96e1d419cc55f50dbece04ded9c4b0f
|