Skip to content

Quick start

Describe the database in the environment:

DATABASE_TYPE=NEO4J
DATABASE_HOST=localhost
DATABASE_USER=neo4j
DATABASE_PASSWORD=…

Declare a fragment for each node a use case reads, and a view that composes them:

from typing import Annotated
from drivine import GraphView, NodeFragment, NodeId, Relationship, RelationshipFragment, Root, TargetNode
class Person(NodeFragment, labels=["Person"]):
uuid: Annotated[str, NodeId()]
name: str
bio: str | None = None
class Organization(NodeFragment, labels=["Organization"]):
uuid: Annotated[str, NodeId()]
name: str
class WorkHistory(RelationshipFragment):
role: str
organization: Annotated[Organization, TargetNode()]
class PersonCareer(GraphView):
person: Annotated[Person, Root()]
employment_history: Annotated[list[WorkHistory], Relationship("WORKS_FOR")] = []

Then load and save, each in one statement:

import asyncio
from drivine import DatabaseRegistry, PersistenceManagerFactory, StatelessGraphObjectManager, refs
async def main() -> None:
registry = DatabaseRegistry()
registry.build_or_resolve_from_env()
gom = StatelessGraphObjectManager(PersistenceManagerFactory(registry).get())
try:
await gom.save(
PersonCareer(
person=Person(uuid="p1", name="Ada", bio="Design Lead"),
employment_history=[WorkHistory(role="Lead", organization=Organization(uuid="o1", name="Studio"))],
)
)
q = refs(PersonCareer)
for career in await gom.load_all(PersonCareer, where=q.person.bio.contains("Lead")):
print(career.person.name, [it.organization.name for it in career.employment_history])
finally:
await registry.close()
asyncio.run(main())

From here: the persistence manager for Cypher of your own, transactions, queries and typed references, the sync API, and DrivineAssembly to wire it into an application.