# ADR-033: JSON path queries and hand-written CRUD for v1 repository layer ## Status Accepted ## Context The repository layer is the next major feature for `@alkdev/storage`. It needs to provide typed CRUD operations for the 6 metagraph tables and query capability for node/edge attributes stored as JSON columns. The metagraph pattern stores node and edge attributes as JSON (`attributes text not null default '{}'` with JSON mode in SQLite, `jsonb` in PG). This is fundamental to the design — node types are dynamic schemas defined at runtime and stored in `node_types.schema`, not static columns known at database definition time. Three approaches exist for querying attributes: 1. **JSON path queries**: Map filter criteria to `json_extract()` (SQLite) or `->>` / `#>>` (PG). Works with current table definitions. No native index support on individual attributes. 2. **Native columns via dbtype**: Render the metagraph tables via `@alkdev/dbtype` element trees and make attributes native columns. Conflicts with the metagraph's dynamic schema model — attributes are runtime data, not static columns. 3. **Hybrid**: dbtype renders the 6 static tables. Attributes remain JSON (dynamic schema requirement). CRUD for static tables could be auto-generated. Graph-specific queries use JSON path. Virtual columns for frequently queried attributes as a later optimization. Separately, the CRUD operations for the 6 metagraph tables (insert graph type, find node by key, etc.) could be hand-written, auto-generated from Drizzle schemas (drizzle-graphql pattern), or auto-generated from dbtype element trees (the `from-dbtype` adapter pattern). ## Decision For v1: 1. **Attribute queries use JSON path extraction** (`json_extract` on SQLite, `->>`/`#>>` on PG). This preserves the metagraph's dynamic schema model. Native column indexes on individual attributes are not available in v1. 2. **Static table CRUD operations are hand-written** with explicit function signatures (`findNode(graphId, key)`, `insertNodeType(...)`, etc.). No auto-generation from Drizzle or dbtype. 3. **dbtype integration is deferred** (per ADR-018). The hybrid approach remains viable for a future iteration but is not the v1 path. 4. **Virtual/computed columns for frequently queried attributes** are a post-v1 optimization, not a v1 design concern. The repository layer will have two parts: - **Static table CRUD**: Insert, find, update, delete for graph_types, node_types, edge_types, graphs, nodes, edges, actors. - **Graph data queries**: JSON path queries against node/edge attributes, validated by the Module schema at the application layer. ## Consequences - v1 repository API uses JSON path for attribute queries — no native SQL indexes on attributes - CRUD function signatures are known and explicit — no generated code surface to learn - PG can add GIN indexes on `jsonb` columns for containment queries, but not for arbitrary key-value lookups - The hand-written CRUD path doesn't block any future auto-generation approach (dbtype `from-dbtype`, drizzle-graphql pattern, or a `from-storage` adapter in `@alkdev/operations`) - The metagraph's dynamic schema model is preserved — attributes are always JSON, not static columns ## References - [forward-look.md](../forward-look.md) — Repository Layer Strategy section (full analysis) - [overview.md](../overview.md) — Repository Layer Bridging Pattern - [sqlite-host.md](../sqlite-host.md) — JSON text for schema columns (ADR-019) - ADR-018: dbtype integration is post-v1 - ADR-005: Drizzle + TypeBox via drizzlebox