Object-Graph Mapping for FalkorDB with Spring Data-inspired patterns
Project description
FalkorDB Python ORM
Object-Graph Mapping for FalkorDB with Spring Data-inspired patterns
FalkorDB Python ORM provides intuitive, annotation-based object-graph mapping for FalkorDB, enabling developers to work with graph databases using familiar ORM patterns inspired by Spring Data.
๐ฏ Project Status
Production Ready! โ The FalkorDB Python ORM is fully implemented, tested, and documented.
๐ Features
Core Capabilities
- ๐ท๏ธ Decorator-based Entity Mapping: Use
@nodeandpropertydecorators for intuitive object-graph mapping - ๐ฆ Repository Pattern: Complete CRUD operations with type-safe
Repository[T] - ๐ ID Management: Auto-generated or manual IDs with
generated_id() - ๐ Type Conversion: Built-in converters for common Python types
- ๐ฏ Multiple Labels: Support for multiple node labels per entity
- ๐จ Type Safety: Full type hints and generic repositories for IDE support
Query Features
- ๐ Derived Query Methods: Auto-generate queries from method names (e.g.,
find_by_name(),count_by_age_greater_than()) - ๐ Comparison Operators: 14+ operators (equals, greater_than, less_than, between, in, etc.)
- ๐ Logical Operators: AND/OR combinations in queries
- ๐ String Operations: CONTAINS, STARTS WITH, ENDS WITH, regex patterns
- ๐ Sorting & Limiting: ORDER BY multiple fields, first/top_N result limiting
- โก Query Caching: Automatic QuerySpec caching for performance
- ๐ Custom Cypher Queries:
@querydecorator with parameter binding - ๐ Aggregation Methods: Built-in
sum(),avg(),min(),max()functions
Relationships
- ๐ Relationship Declaration:
relationship()decorator with full type support - ๐ค Lazy Loading: Relationships loaded on-demand with automatic caching
- โก Eager Loading: Solve N+1 queries with
fetch=['rel1', 'rel2']parameter - ๐ Cascade Operations: Auto-save related entities with
cascade=True - โ๏ธ Bidirectional Relationships: Full support for complex relationship graphs
- ๐ Reverse Relationships:
direction='INCOMING'for inverse traversal - ๐ Circular Reference Handling: Safe handling of circular relationships
Async Support
- โก AsyncRepository: Full async/await support for all CRUD operations
- ๐ Async Relationships: Async lazy loading with
AsyncLazyListandAsyncLazySingle - ๐ Async Derived Queries: Auto-generated async query methods
- ๐ Framework Ready: Perfect for FastAPI, aiohttp, and async Python applications
Advanced Features (v1.1.0)
- โก Transaction Support: Context managers with identity map and change tracking
- ๐๏ธ Index Management:
@indexedand@uniquedecorators with schema validation - ๐ Pagination: Full pagination with sorting and navigation (
Pageable,Page[T]) - ๐ Relationship Updates: Automatic deletion of old edges when relationships change
Security Features (v1.2.0 NEW! ๐)
- ๐ Role-Based Access Control (RBAC): Enterprise-grade security with fine-grained permissions
- ๐ฅ User & Role Management: Built-in user, role, and privilege entities
- ๐ก๏ธ Declarative Security:
@secureddecorator for entity-level access control - ๐ Property-Level Security: Control access to individual properties
- ๐ SecureSession: Security-aware sessions with automatic permission enforcement
- ๐จโ๐ผ Admin API: Comprehensive RBACManager for runtime administration
- ๐ Audit Logging: Complete audit trail for all security operations
- ๐ญ Impersonation: Test permissions safely with context managers
- โก Performance: <10ms overhead with intelligent privilege caching
Production Features
- ๐ Comprehensive Documentation: Complete API reference and migration guides
- ๐ง Enhanced Exceptions: Contextual error messages with structured error information
- ๐ CI/CD Workflows: Automated testing, linting, and publishing
- ๐พ Memory Optimization: Interned strings for repeated values with
@interneddecorator - ๐งช Integration Tests: Full end-to-end tests with real FalkorDB
๐ Future Enhancements (Optional)
- ๐ฆ Migration System: Schema version management and migrations
- ๐ Query Result Caching: Result caching for performance
- โ๏ธ Batch Optimization: UNWIND-based bulk operations
๐ Usage
Entity Definition
from falkordb_orm import node, property, relationship, Repository
from typing import Optional, List
@node(labels=["Person", "Individual"])
class Person:
id: Optional[int] = None
name: str = property("full_name") # Maps to 'full_name' in graph
email: str
age: int
friends: List["Person"] = relationship(type="KNOWS", direction="OUTGOING")
company: Optional["Company"] = relationship(type="WORKS_FOR", direction="OUTGOING")
@node("Company")
class Company:
id: Optional[int] = None
name: str
employees: List[Person] = relationship(type="WORKS_FOR", direction="INCOMING")
Repository Usage
from falkordb import FalkorDB
# Connect to FalkorDB
db = FalkorDB(host='localhost', port=6379)
graph = db.select_graph('social')
# Create repository
repo = Repository(graph, Person)
# Create and save
person = Person(name="Alice", email="alice@example.com", age=25)
saved = repo.save(person)
# Derived queries (auto-implemented)
adults = repo.find_by_age_greater_than(18)
alice = repo.find_by_name("Alice")
count = repo.count_by_age(25)
exists = repo.exists_by_email("alice@example.com")
# Eager loading relationships (prevents N+1 queries)
person_with_friends = repo.find_by_id(1, fetch=["friends", "company"])
all_with_friends = repo.find_all(fetch=["friends"]) # Single query!
# Cascade save (auto-saves related entities)
company = Company(name="Acme Corp")
employee = Employee(name="Bob", company=company)
repo.save(employee) # Company automatically saved!
Async Usage (Phase 5)
import asyncio
from falkordb.asyncio import FalkorDB
from falkordb_orm import node, AsyncRepository
from typing import Optional
@node("Person")
class Person:
id: Optional[int] = None
name: str
age: int
async def main():
# Connect to FalkorDB with async client
from redis.asyncio import BlockingConnectionPool
pool = BlockingConnectionPool(max_connections=16, timeout=None, decode_responses=True)
db = FalkorDB(connection_pool=pool)
graph = db.select_graph('social')
# Create async repository
repo = AsyncRepository(graph, Person)
# All operations are async
person = Person(name="Alice", age=25)
saved = await repo.save(person)
# Async derived queries
adults = await repo.find_by_age_greater_than(18)
count = await repo.count()
# Async eager loading
person_with_friends = await repo.find_by_id(1, fetch=["friends"])
print(f"Found {count} people")
asyncio.run(main())
Transaction Support (v1.1.0 NEW!)
from falkordb_orm import Session
# Use session for transactions with identity map
with Session(graph) as session:
# Get entity (cached in identity map)
person = session.get(Person, 1)
person.age = 31
session._dirty.add(person) # Mark as modified
# Add new entities
new_person = Person(name="Bob", age=25)
session.add(new_person)
# Auto-commit on success, auto-rollback on error
session.commit()
Index Management (v1.1.0 NEW!)
from falkordb_orm import node, indexed, unique, IndexManager
@node("User")
class User:
email: str = unique(required=True) # Unique constraint
age: int = indexed() # Regular index
bio: str = indexed(index_type="FULLTEXT") # Full-text search
# Create indexes
manager = IndexManager(graph)
manager.create_indexes(User, if_not_exists=True)
# Schema validation
from falkordb_orm import SchemaManager
schema_manager = SchemaManager(graph)
result = schema_manager.validate_schema([User, Product])
if not result.is_valid:
schema_manager.sync_schema([User, Product])
Pagination (v1.1.0 NEW!)
from falkordb_orm import Pageable
# Create pageable (page 0, 10 items, sorted by age)
pageable = Pageable(page=0, size=10, sort_by="age", direction="ASC")
# Get paginated results
page = repo.find_all_paginated(pageable)
print(f"Page {page.page_number + 1} of {page.total_pages}")
print(f"Total: {page.total_elements} items")
for person in page.content:
print(person.name)
# Navigate pages
if page.has_next():
next_page = repo.find_all_paginated(pageable.next())
Getting Started
For a complete walkthrough, see QUICKSTART.md.
Security Quick Start (v1.2.0)
Define a secured entity:
from falkordb_orm import node, generated_id
from falkordb_orm.security import secured
@node("Person")
@secured(
read=["reader", "admin"],
write=["editor", "admin"],
deny_read_properties={
"ssn": ["*"], # Nobody can read
"salary": ["reader"] # Readers cannot read salary
}
)
class Person:
id: int | None = generated_id()
name: str
email: str
ssn: str
salary: float
Create roles, users, and grant privileges:
from datetime import datetime
from falkordb_orm.repository import Repository
from falkordb_orm.security import Role, User, SecurityPolicy
role_repo = Repository(graph, Role)
user_repo = Repository(graph, User)
reader = Role(name="reader", description="Read-only", created_at=datetime.now())
editor = Role(name="editor", description="Edit", created_at=datetime.now())
role_repo.save(reader)
role_repo.save(editor)
alice = User(username="alice", email="alice@example.com", created_at=datetime.now())
alice.roles = [reader]
user_repo.save(alice)
policy = SecurityPolicy(graph)
policy.grant("READ", "Person", to="reader")
policy.grant("WRITE", "Person", to="editor")
policy.deny("READ", "Person.ssn", to="reader")
Use SecureSession:
from falkordb_orm.security import SecureSession
session = SecureSession(graph, alice)
repo = session.get_repository(Person)
p = repo.find_by_id(1)
print(p.name) # โ Allowed
print(p.ssn) # None (filtered)
Admin API example:
from falkordb_orm.security import RBACManager
admin_session = SecureSession(graph, admin_user)
rbac = RBACManager(graph, admin_session.security_context)
rbac.create_user("bob", "bob@example.com", roles=["editor"]) # create
rbac.assign_role("alice", "editor") # assign
rbac.grant_privilege("editor", "WRITE", "NODE", "Document") # grant
logs = rbac.query_audit_logs(limit=10) # audit
Custom Queries (Phase 4)
from falkordb_orm import query
class PersonRepository(Repository[Person]):
@query(
"MATCH (p:Person)-[:KNOWS]->(f:Person) WHERE p.name = $name RETURN f",
returns=Person
)
def find_friends(self, name: str) -> List[Person]:
pass
@query(
"MATCH (p:Person) WHERE p.age BETWEEN $min AND $max RETURN p",
returns=Person
)
def find_by_age_range(self, min: int, max: int) -> List[Person]:
pass
๐ Comparison with Current Approach
Before (Raw Cypher)
from falkordb import FalkorDB
db = FalkorDB(host='localhost', port=6379)
g = db.select_graph('social')
# Create manually
g.query('''
CREATE (p:Person {name: $name, email: $email, age: $age})
RETURN p, id(p)
''', {'name': 'Alice', 'email': 'alice@example.com', 'age': 25})
# Query manually
result = g.query('''
MATCH (p:Person) WHERE p.age > $min_age RETURN p
''', {'min_age': 18})
# Manual result processing
for record in result.result_set:
person = record[0]
print(person.properties['name'])
After (ORM - Planned)
from falkordb import FalkorDB
from falkordb_orm import node, Repository
@node("Person")
class Person:
id: Optional[int] = None
name: str
email: str
age: int
db = FalkorDB(host='localhost', port=6379)
graph = db.select_graph('social')
repo = Repository(graph, Person)
# Create with ORM
person = Person(name="Alice", email="alice@example.com", age=25)
saved = repo.save(person)
# Query with derived method
adults = repo.find_by_age_greater_than(18)
# Automatic object mapping
for person in adults:
print(person.name)
๐ Documentation
- Quick Start Guide - Get started in minutes
- Design Document - Comprehensive design and architecture
- API Reference - Complete API documentation
- Decorators -
@node,property(),relationship() - Repository -
RepositoryandAsyncRepository
- Decorators -
- Security Module - Complete RBAC security guide (v1.2.0)
- Migration Guide - Migrating from raw FalkorDB client
- Examples - Complete working examples
- Security Examples - RBAC and admin API examples
- Contributing - Contribution guidelines
๐ค Comparison with Spring Data FalkorDB
This project is inspired by Spring Data FalkorDB, bringing similar patterns to Python:
| Feature | Spring Data FalkorDB | falkordb-orm (v1.2.0) |
|---|---|---|
| Core Mapping | ||
| Entity Mapping | @Node annotation |
@node decorator |
| Property Mapping | @Property |
property() function |
| Relationships | @Relationship |
relationship() function |
| ID Generation | @GeneratedValue |
generated_id() |
| Repository Pattern | ||
| Repository | FalkorDBRepository<T, ID> |
Repository[T] |
| Query Methods | Method name derivation | Method name derivation |
| Custom Queries | @Query annotation |
@query decorator |
| Pagination | Pageable, Page<T> |
Pageable, Page[T] โ
|
| Transactions & Sessions | ||
| Transactions | @Transactional |
Session (unit of work) โ
|
| Identity Map | โ | โ (via Session) |
| Change Tracking | โ | โ (dirty checking) |
| Advanced Features | ||
| Async Support | โ | โ
AsyncRepository |
| Index Management | Manual | @indexed, @unique โ
|
| Schema Validation | โ | โ
SchemaManager |
| Lazy Loading | โ | โ (lazy/eager) |
| Cascade Operations | โ | โ (cascade save) |
| Security (v1.2.0) | ||
| RBAC | โ | โ Role-Based Access Control |
| Entity Security | โ | โ
@secured decorator |
| Property Security | โ | โ Property-level controls |
| Secure Sessions | โ | โ
SecureSession |
| Admin API | โ | โ
RBACManager |
| Audit Logging | โ | โ Complete audit trail |
| User/Role Management | โ | โ Built-in entities |
| Impersonation | โ | โ Testing support |
| Language & Ecosystem | ||
| Language | Java | Python 3.9+ |
| Type Safety | Java generics | Python type hints |
| Framework Integration | Spring Boot | FastAPI, Django, Flask |
๐ฏ Goals
- Developer Productivity: Reduce boilerplate code and manual Cypher writing
- Type Safety: Leverage Python type hints for better IDE support
- Familiarity: Use patterns developers know from SQLAlchemy, Django ORM, Spring Data
- Performance: Optimize queries, support batching, implement lazy loading
- Flexibility: Support both simple and complex use cases
๐ง Technology Stack
- Python: 3.8+
- FalkorDB Client: falkordb-py
- Type Hints: For IDE support and validation
- Decorators: For entity and query definition
- Generics: For type-safe repositories
๐ฆ Installation
pip install falkordb-orm
Or install from source:
git clone https://github.com/FalkorDB/falkordb-py-orm.git
cd falkordb-py-orm
pip install -e .
๐ก Design Principles
- Convention over Configuration: Sensible defaults with customization options
- Explicit is Better: Clear, readable API over implicit magic
- Performance Matters: Optimize for common use cases
- Pythonic: Follow Python idioms and best practices
- Compatibility: Work seamlessly with existing falkordb-py code
๐ License
MIT License - See LICENSE file for details
๐ Acknowledgments
- Inspired by Spring Data FalkorDB
- Built on top of falkordb-py
- Follows patterns from SQLAlchemy and Django ORM
๐ค Contributing
Contributions are welcome! Please see CONTRIBUTING.md for guidelines.
๐ฆ Resources
- FalkorDB: falkordb.com
- Discord: FalkorDB Community
- GitHub: FalkorDB Organization
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 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 falkordb_orm-1.2.1.tar.gz.
File metadata
- Download URL: falkordb_orm-1.2.1.tar.gz
- Upload date:
- Size: 65.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
20a43043fcc8973df458fa97c5cf040da24a0a54542e1f224f9c66b20ae354df
|
|
| MD5 |
2cf833c2af313bfcc2c231cc1d4ce320
|
|
| BLAKE2b-256 |
7d211065144cee494c4d1083cc83d359fcc1c6d25f66dd12fff7c72997f70704
|
Provenance
The following attestation bundles were made for falkordb_orm-1.2.1.tar.gz:
Publisher:
publish.yml on FalkorDB/falkordb-py-orm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
falkordb_orm-1.2.1.tar.gz -
Subject digest:
20a43043fcc8973df458fa97c5cf040da24a0a54542e1f224f9c66b20ae354df - Sigstore transparency entry: 732027095
- Sigstore integration time:
-
Permalink:
FalkorDB/falkordb-py-orm@132a3a6b204bb19eb961e31a5999007af48947d0 -
Branch / Tag:
refs/tags/v1.2.1 - Owner: https://github.com/FalkorDB
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@132a3a6b204bb19eb961e31a5999007af48947d0 -
Trigger Event:
release
-
Statement type:
File details
Details for the file falkordb_orm-1.2.1-py3-none-any.whl.
File metadata
- Download URL: falkordb_orm-1.2.1-py3-none-any.whl
- Upload date:
- Size: 75.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce8fa8fb617f98ce4e887aa6bfe3ed49d06510adc6b0483b027d8288dff51a89
|
|
| MD5 |
a6bb9efe67d18a60f5cd471bf422aa6d
|
|
| BLAKE2b-256 |
7a98d023959b2548d0e1c2a1f8865cfca14af256fb5e5b660c188e8666ca7bda
|
Provenance
The following attestation bundles were made for falkordb_orm-1.2.1-py3-none-any.whl:
Publisher:
publish.yml on FalkorDB/falkordb-py-orm
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
falkordb_orm-1.2.1-py3-none-any.whl -
Subject digest:
ce8fa8fb617f98ce4e887aa6bfe3ed49d06510adc6b0483b027d8288dff51a89 - Sigstore transparency entry: 732027096
- Sigstore integration time:
-
Permalink:
FalkorDB/falkordb-py-orm@132a3a6b204bb19eb961e31a5999007af48947d0 -
Branch / Tag:
refs/tags/v1.2.1 - Owner: https://github.com/FalkorDB
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@132a3a6b204bb19eb961e31a5999007af48947d0 -
Trigger Event:
release
-
Statement type: