A Python ORM for Apache AGE graph database
Project description
age-orm
A Python ORM for Apache AGE, providing SQLAlchemy-like abstractions for graph database operations.
Status: v0.1.0 — Core implemented (models, CRUD, query builder, relationships, async)
Features
Core
- Pydantic v2-based model definitions for vertices and edges
- Graph, Vertex, and Edge abstractions
- Automatic schema creation (labels, indexes)
- CRUD operations (create, read, update, delete)
- Connection pooling via psycopg3
Query Building
- Fluent Cypher query builder (filter, sort, limit, skip)
- Safe parameter substitution
- Raw Cypher support
- Bulk mutations (update/delete via query)
Advanced
- Sync + Async support (psycopg3's unified API)
- Relationship descriptors with lazy loading
- Event system (pre/post hooks for add, update, delete)
- Bulk import (direct SQL INSERT for performance)
- Graph traversal helpers (expand, traverse)
- Dirty tracking (only update changed fields)
- Migrations and schema versioning
- Integration with AGEFreighter for bulk loads
Installation
# With uv
uv add age-orm
# With pip
pip install age-orm
Requires Python 3.12+ and a running Apache AGE instance.
Quick Start
from age_orm import Database, Vertex, Edge, relationship
# Define models
class Person(Vertex):
__label__ = "Person"
name: str
age: int
email: str | None = None
class Knows(Edge):
__label__ = "KNOWS"
since: int
relationship_type: str = "friend"
# Connect
db = Database("postgresql://ageuser:agepassword@localhost:5433/agedb")
graph = db.graph("social", create=True)
# Create vertices
alice = Person(name="Alice", age=30)
bob = Person(name="Bob", age=25)
graph.add(alice)
graph.add(bob)
# Create edge
knows = Knows(since=2020)
graph.connect(alice, knows, bob)
# Query
people = graph.query(Person).filter("n.age > $min_age", min_age=20).sort("n.name").all()
alice = graph.query(Person).filter_by(name="Alice").one()
# Traverse
friends = graph.traverse(alice, "KNOWS", depth=2, target_class=Person)
# Raw Cypher
results = graph.cypher(
"MATCH (n:Person)-[:KNOWS]->(m) RETURN n.name, m.name",
columns=["a", "b"]
)
# Cleanup
db.close()
Async Usage
from age_orm import AsyncDatabase
async with AsyncDatabase("postgresql://...") as db:
graph = await db.graph("social", create=True)
alice = Person(name="Alice", age=30)
await graph.add(alice)
q = await graph.query(Person)
people = await q.filter("n.age > $min", min=20).all()
Relationships
class Person(Vertex):
__label__ = "Person"
name: str
friends: list["Person"] = relationship("Person", "KNOWS", direction="outbound")
employer: "Company" = relationship("Company", "WORKS_AT", uselist=False)
Relationships are lazy-loaded on access when the entity is bound to a graph.
Event Hooks
from age_orm import listen, listens_for
@listens_for(Person, "pre_add")
def validate_person(target, event, **kwargs):
if target.age < 0:
raise ValueError("Age cannot be negative")
Dependencies
psycopg[binary,pool] >= 3.2— PostgreSQL driver with connection poolingpydantic >= 2.3— Data validation and models
Project Structure
age_orm/
├── __init__.py # Public API exports
├── exceptions.py # Custom exceptions
├── event.py # Event system (pre/post hooks)
├── database.py # Connection + pool management
├── graph.py # Graph class + CRUD + traversal
├── references.py # Relationship descriptors
├── models/
│ ├── base.py # AgeModel base class
│ ├── vertex.py # Vertex model
│ └── edge.py # Edge model
├── query/
│ └── builder.py # Cypher query builder
└── utils/
└── serialization.py # Agtype serialization helpers
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 age_orm-0.1.0.tar.gz.
File metadata
- Download URL: age_orm-0.1.0.tar.gz
- Upload date:
- Size: 54.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
852965d8e4a62f40a00cbe94ec9a64b869dad25b9acc38c8521f29ff361db808
|
|
| MD5 |
3288337ae7bf96490ffa1af2576ba115
|
|
| BLAKE2b-256 |
a945ff6f77b2e73aed26dcc819d8635a552aeae1ac5c5979ab3845b206b874fe
|
File details
Details for the file age_orm-0.1.0-py3-none-any.whl.
File metadata
- Download URL: age_orm-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.25 {"installer":{"name":"uv","version":"0.9.25","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53e11f0e62aee3aeb7bb4f6008cd59aa2b88024d5e2aebd64d9f5a275c557d8e
|
|
| MD5 |
91c460261a55a890c0e8728419c55de0
|
|
| BLAKE2b-256 |
0b312c077095f823a5a851f9b3a35fc97f64b4b130fe5005a99a4140a1500b93
|