EdgeKeyKind::TextPairWithMetadata extended with:
- from_col / to_col (custom column names, default src_path/dst_path)
- extra_columns: &[(name, FieldKind)] for domain-specific edge metadata
kei-crossdomain fully re-migrated via engine:
- edge_table: Some('cross_edges') + TextPairWithMetadata variant with
from_col='from_uri', to_col='to_uri', has_id/has_weight/has_created_at,
extra_columns=[evidence, metadata]
- Custom edges DDL dropped from custom_migrations (engine owns it now)
- edges.rs query_edges SELECT uses edge_id (engine-emitted PK)
Tests: 42/42 kei-entity-store (+2), 5/5 kei-crossdomain preserved.
Sister crates (task/chat/content/social/sage) no regression.
Closes HANDOFF-WAKE deferred item #2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
81 lines
3.5 KiB
Rust
81 lines
3.5 KiB
Rust
//! kei-crossdomain EntitySchema — declarative spec consumed by
|
|
//! `kei_entity_store::Store` for migrations + user_version pragma.
|
|
//!
|
|
//! **Architectural note (2026-04-23 re-migration, Option B):**
|
|
//! kei-crossdomain is an edges-only graph store — URIs (`domain://path`)
|
|
//! are the only identifiers; there is no primary "node" entity row. The
|
|
//! engine's `EntitySchema` contract requires exactly one `IntegerPk`
|
|
//! field, so we declare a minimal synthetic `cross_nodes` table purely
|
|
//! to satisfy the DDL contract. No code writes to this table; every
|
|
//! query still runs against `cross_edges`.
|
|
//!
|
|
//! The rich `cross_edges` DDL is now generated by `kei-entity-store` via
|
|
//! `EdgeKeyKind::TextPairWithMetadata { from_col: "from_uri", to_col:
|
|
//! "to_uri", has_id, has_weight, has_created_at, extra_columns }`. The
|
|
//! legacy hand-rolled `custom_migrations` DDL was dropped; see git
|
|
//! history for the prior version.
|
|
|
|
use kei_entity_store::schema::{EdgeKeyKind, EntitySchema, FieldDef, FieldKind};
|
|
use rusqlite::{Connection, Result};
|
|
|
|
/// Synthetic primary table — exists solely to satisfy the engine's
|
|
/// `IntegerPk` requirement. Not used by any verb or caller.
|
|
static FIELDS: &[FieldDef] = &[FieldDef::pk("id")];
|
|
|
|
/// Extra columns on `cross_edges` beyond the standard metadata
|
|
/// (id / weight / created_at / edge_type). Defaults (`E4`, `{}`) are
|
|
/// applied by kei-crossdomain callers at INSERT time since the engine's
|
|
/// edge DDL only emits `TEXT DEFAULT ''` for `FieldKind::Text`; existing
|
|
/// databases keep their original `DEFAULT 'E4' / '{}'` column attributes
|
|
/// via SQLite's `CREATE TABLE IF NOT EXISTS` no-op.
|
|
static EDGE_EXTRAS: &[(&str, FieldKind)] = &[
|
|
("evidence", FieldKind::Text),
|
|
("metadata", FieldKind::Text),
|
|
];
|
|
|
|
pub static CROSSDOMAIN_SCHEMA: EntitySchema = EntitySchema {
|
|
name: "crossdomain",
|
|
table: "cross_nodes",
|
|
fields: FIELDS,
|
|
// Empty verb set: every kei-crossdomain op is bespoke (rich typed
|
|
// edges with evidence/metadata — engine's `link` verb does dispatch
|
|
// extras now, but kei-crossdomain keeps its own typed wrappers in
|
|
// `edges.rs`/`bfs.rs`/`auto_link.rs` for the strongly-typed API).
|
|
enabled_verbs: &[],
|
|
fts_columns: None,
|
|
edge_table: Some("cross_edges"),
|
|
edge_key_kind: EdgeKeyKind::TextPairWithMetadata {
|
|
from_col: "from_uri",
|
|
to_col: "to_uri",
|
|
has_id: true,
|
|
has_weight: true,
|
|
has_created_at: true,
|
|
extra_columns: EDGE_EXTRAS,
|
|
},
|
|
archived_field: None,
|
|
// Legacy hand-rolled DDL dropped — engine now emits it. Only the
|
|
// kei-crossdomain-specific indexes (`idx_ce_from`, `idx_ce_type`)
|
|
// live here; the engine auto-emits `idx_cross_edges_dst` on `to_uri`.
|
|
custom_migrations: &[
|
|
"CREATE INDEX IF NOT EXISTS idx_ce_from ON cross_edges(from_uri);",
|
|
"CREATE INDEX IF NOT EXISTS idx_ce_type ON cross_edges(edge_type);",
|
|
],
|
|
};
|
|
|
|
/// Kept for backward compatibility with any external caller that
|
|
/// imported `schema::create_schema` directly. New code should open via
|
|
/// `Store::open` / `Store::open_memory`, which invokes the engine's
|
|
/// migration runner with `CROSSDOMAIN_SCHEMA`.
|
|
pub fn create_schema(conn: &Connection) -> Result<()> {
|
|
// Delegate to the engine's DDL generator so the one-shot path stays
|
|
// byte-identical to the engine-driven migration.
|
|
let ddl = kei_entity_store::ddl::edge_table_for(
|
|
"cross_edges",
|
|
CROSSDOMAIN_SCHEMA.edge_key_kind,
|
|
);
|
|
conn.execute_batch(&ddl)?;
|
|
for stmt in CROSSDOMAIN_SCHEMA.custom_migrations {
|
|
conn.execute_batch(stmt)?;
|
|
}
|
|
Ok(())
|
|
}
|