# Database Utilities

The `arandu.db` module provides low-level database setup functions. These are used internally by `MemoryClient` but are available for advanced use cases where you need direct control over the database engine and session lifecycle.

```python
from arandu.db import create_engine, create_session_factory, init_db
```

---

## create_engine

Create an async SQLAlchemy engine from a connection string.

Automatically converts `postgresql://` to `postgresql+psycopg://` if the async driver prefix is missing.

```python
def create_engine(database_url: str) -> AsyncEngine
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `database_url` | `str` | PostgreSQL connection string. |

**Returns:** `AsyncEngine` instance.

```python
from arandu.db import create_engine

engine = create_engine("postgresql://user:pass@localhost:5432/mydb")
# Internally becomes: postgresql+psycopg://user:pass@localhost:5432/mydb
```

---

## create_session_factory

Create an async session factory bound to the given engine.

```python
def create_session_factory(engine: AsyncEngine) -> async_sessionmaker[AsyncSession]
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `engine` | `AsyncEngine` | The async engine to bind sessions to. |

**Returns:** `async_sessionmaker[AsyncSession]` with `expire_on_commit=False`.

```python
from arandu.db import create_engine, create_session_factory

engine = create_engine("postgresql://user:pass@localhost:5432/mydb")
SessionFactory = create_session_factory(engine)

async with SessionFactory() as session:
    # Use session for queries
    ...
```

---

## init_db

Create all memory tables in the consumer's database.

Uses `Base.metadata.create_all` -- safe to call multiple times (creates only tables that don't already exist). This ensures all SQLAlchemy model classes are registered before creating tables.

```python
async def init_db(engine: AsyncEngine) -> None
```

| Parameter | Type | Description |
|-----------|------|-------------|
| `engine` | `AsyncEngine` | The async engine to create tables on. |

```python
from arandu.db import create_engine, init_db

engine = create_engine("postgresql://user:pass@localhost:5432/mydb")
await init_db(engine)
```

---

## Database Schema

The SDK defines its SQLAlchemy models in `arandu.models`. Key tables include:

| Table | Description |
|-------|-------------|
| `memory_events` | Immutable event records (user messages with embeddings). |
| `memory_facts` | Extracted facts with entity/attribute/value triples and embeddings. |
| `memory_entities` | Entity registry (people, places, pets, etc.). |
| `memory_entity_aliases` | Aliases for entity resolution. |
| `memory_entity_relationships` | Knowledge graph edges between entities. |
| `memory_clusters` | Semantic clusters of related facts. |
| `memory_meta_observations` | Detected patterns, insights, and behavioral preferences. |
| `memory_attribute_registry` | Custom attribute key registry per user. |
| `session_observations` | L1 session-level observations from the observer. |

All tables use UUID primary keys and include `user_id` for multi-tenant isolation. The `memory_facts` and `memory_events` tables have `pgvector` embedding columns for semantic search.

!!! info "Schema Management"
    For production deployments, consider using Alembic migrations instead of `init_db()`. The `init_db()` function is convenient for development and testing but does not handle schema migrations for existing tables.
