KeiSeiKit-1.0/_primitives/_rust/kei-content-store/src/schema.rs
Parfii-bot 0be354a920 KeiSeiKit-public — clean state
Single-commit clean baseline after security scrub of niche-tells,
project codenames, internal jargon, and contributor-email leaks.

Contents:
- 100 Rust crates (_primitives/_rust/)
- 37 agent manifests (_manifests/) + generated specs (_generated/)
- 67 user-invocable skills (skills/)
- 33 hooks (hooks/)
- Composition blocks (_blocks/)
- Documentation (docs/, README.md)
- TS adapter packages (_ts_packages/)
- Assembler (_assembler/)
- Roles (_roles/)
- Templates (_templates/)
- Forgejo CI (.forgejo/)

Author: Denis Parfionovich <info@greendragon.info>

License: see LICENSE.
2026-05-01 12:09:03 +08:00

105 lines
3.7 KiB
Rust

//! kei-content-store EntitySchemas — declarative specs consumed by
//! `kei_entity_store::Store` and its verb templates.
//!
//! Shape (multi-schema convergence, 2026-04-23):
//!
//! - `CONTENT_SCHEMA`: primary entity `content_units` (assets; INTEGER
//! PK; engine-owned create/get/list/search/update/delete + FTS).
//! - `CAMPAIGNS_SCHEMA`: plain-CRUD INTEGER-PK table promoted to engine
//! on this pass (create/get only — no idempotency or dedup).
//! - `ALL_SCHEMAS`: the `&[&EntitySchema]` slice `Store::open` hands
//! to the engine.
//!
//! Secondary tables that stay in `custom_migrations` (on CONTENT_SCHEMA)
//! and keep bespoke SQL in their sibling modules:
//!
//! - `prompts` — hash-dedup via `INSERT OR IGNORE` + re-query by
//! `UNIQUE(prompt_hash, model)`; engine `create` is plain INSERT,
//! would break `prompt_dedup_by_hash` test. Sibling: `prompts.rs`.
//! - `campaign_assets` — composite `(campaign_id, asset_id)` PK, no
//! single-column PK; engine schemas require one PK field. Also uses
//! `INSERT OR IGNORE` for idempotent attach. Sibling: `campaigns.rs`.
use kei_entity_store::schema::{EdgeKeyKind, EntitySchema, FieldDef};
// ---- content_units (primary, assets) ---------------------------------
static FIELDS: &[FieldDef] = &[
FieldDef::pk("id"),
FieldDef::text_default("unit_type", "asset"),
FieldDef::text_nn("title"),
FieldDef::text("content"),
FieldDef::text("media_type"),
FieldDef::text("file_path"),
FieldDef::text("file_hash"),
FieldDef::text("provider"),
FieldDef::integer("cost_cents"),
FieldDef::integer("parent_id"),
FieldDef::created_at(),
FieldDef::updated_at(),
];
/// Secondary DDL co-located with `content_units` — indexes on the
/// primary table plus the two bespoke-CRUD tables (prompts,
/// campaign_assets). Kept byte-for-byte compatible with the legacy
/// pre-multi-schema DB layout.
const DDL_SECONDARY: &str = r#"
CREATE INDEX IF NOT EXISTS idx_cu_type ON content_units(unit_type);
CREATE INDEX IF NOT EXISTS idx_cu_hash ON content_units(file_hash) WHERE file_hash != '';
CREATE TABLE IF NOT EXISTS prompts (
id INTEGER PRIMARY KEY,
prompt_text TEXT NOT NULL,
prompt_hash TEXT NOT NULL,
prompt_type TEXT DEFAULT '',
model TEXT DEFAULT '',
version INTEGER DEFAULT 1,
parent_id INTEGER DEFAULT 0,
created_at INTEGER NOT NULL,
UNIQUE(prompt_hash, model)
);
CREATE TABLE IF NOT EXISTS campaign_assets (
campaign_id INTEGER NOT NULL,
asset_id INTEGER NOT NULL,
PRIMARY KEY(campaign_id, asset_id)
);
"#;
pub static CONTENT_SCHEMA: EntitySchema = EntitySchema {
name: "asset",
table: "content_units",
fields: FIELDS,
enabled_verbs: &["create", "get", "list", "search", "update", "delete"],
fts_columns: Some(&["title", "content"]),
edge_table: None,
edge_key_kind: EdgeKeyKind::IntegerPair,
archived_field: None,
custom_migrations: &[DDL_SECONDARY],
};
// ---- campaigns (promoted 2026-04-23) --------------------------------
static CAMPAIGN_FIELDS: &[FieldDef] = &[
FieldDef::pk("id"),
FieldDef::text_nn("name"),
FieldDef::text_default("description", ""),
FieldDef::text_default("status", "draft"),
FieldDef::created_at(),
];
pub static CAMPAIGNS_SCHEMA: EntitySchema = EntitySchema {
name: "campaign",
table: "campaigns",
fields: CAMPAIGN_FIELDS,
enabled_verbs: &["create", "get"],
fts_columns: None,
edge_table: None,
edge_key_kind: EdgeKeyKind::IntegerPair,
archived_field: None,
custom_migrations: &[],
};
// ---- aggregate slice for Store::open --------------------------------
pub static ALL_SCHEMAS: &[&EntitySchema] = &[&CONTENT_SCHEMA, &CAMPAIGNS_SCHEMA];