Persistence Layer

The persistence package provides the SQLite-backed implementation of GraphRepository. The core engine never imports from this package — it depends only on the abstract GraphRepository interface defined in core.engine.

Design Decisions

Decision Rationale
SQLAlchemy 2.0 ORM Well-supported, type-safe, works with SQLite and can be swapped for other DBs
JSON attribute blobs Avoids schema migrations when AttributeFields are added to a GraphType
Upsert pattern save_graph / save_node / save_edge all insert-or-update — no separate insert/update paths
Session-per-operation Each call opens and closes a session; simple and safe for single-user desktop use
Cascade deletes GraphRow has SQLAlchemy cascade="all, delete-orphan" so deleting a graph removes all its nodes and edges automatically

Database Schema

erDiagram
    workspaces {
        string id PK
        string name
        datetime created_at
        datetime updated_at
    }
    graphs {
        string id PK
        string workspace_id FK
        string type_name
        string name
        int version
        datetime created_at
        datetime updated_at
    }
    nodes {
        string id PK
        string graph_id FK
        string type_name
        text attributes_json
        int version
        datetime created_at
        datetime updated_at
    }
    edges {
        string id PK
        string graph_id FK
        string source_id FK
        string target_id FK
        string type_name
        text attributes_json
        int version
        datetime created_at
        datetime updated_at
    }
    workspaces ||--o{ graphs : "owns"
    graphs ||--o{ nodes : "contains"
    graphs ||--o{ edges : "contains"
    nodes ||--o{ edges : "source"
    nodes ||--o{ edges : "target"

In-Memory Mode (Testing)

Pass ":memory:" to SqliteGraphRepository for a fully in-process database that is discarded when the object is garbage-collected:

from knowledge_platform.persistence.store import SqliteGraphRepository

repo = SqliteGraphRepository(":memory:")
# ... use repo ...
repo.close()  # release connection pool

File-Based Mode (Production)

Pass a Path or string path to a .db file:

from pathlib import Path
repo = SqliteGraphRepository(Path.home() / ".knowledge_platform" / "my_workspace.db")

Resource Management

Always call repo.close() when you are done — typically in a finally block or via WorkspaceService.close(). Failing to do so causes ResourceWarning about unclosed database connections.

API Reference

See SqliteGraphRepository for the concrete repository API.