docling-studio/document-parser/infra/neo4j/driver.py
Pier-Jean Malandrino 712fc3f1cd feat(neo4j): Day 1 — compose service, driver, schema bootstrap
Add Neo4j as an optional graph-native storage layer (ingestion profile).
Introduces infra/neo4j with a singleton async driver wrapper and an
idempotent bootstrap of constraints + indexes, wired into the FastAPI
lifespan. Integration tests skip when no live Neo4j is reachable.

Refs #186
2026-04-29 14:00:00 +02:00

48 lines
1.2 KiB
Python

"""Async Neo4j driver wrapper.
Owns a single `AsyncDriver` per process. Callers acquire it via
`get_driver()` and must call `close_driver()` at shutdown.
"""
from __future__ import annotations
import logging
from dataclasses import dataclass
from neo4j import AsyncDriver, AsyncGraphDatabase
logger = logging.getLogger(__name__)
@dataclass(frozen=True)
class Neo4jDriver:
driver: AsyncDriver
database: str = "neo4j"
_instance: Neo4jDriver | None = None
async def get_driver(uri: str, user: str, password: str, database: str = "neo4j") -> Neo4jDriver:
"""Return the process-wide driver, creating it on first call.
Verifies connectivity once at creation — raises if the server is unreachable.
"""
global _instance
if _instance is not None:
return _instance
driver = AsyncGraphDatabase.driver(uri, auth=(user, password))
await driver.verify_connectivity()
logger.info("Neo4j driver connected to %s (db=%s)", uri, database)
_instance = Neo4jDriver(driver=driver, database=database)
return _instance
async def close_driver() -> None:
global _instance
if _instance is None:
return
await _instance.driver.close()
_instance = None
logger.info("Neo4j driver closed")