import type { Kysely } from 'kysely'; import { FACTS_TABLE, FACT_EMBEDDINGS_TABLE, FACT_TOPICS_TABLE, SPACES_TABLE, TOPIC_ALIASES_TABLE, TOPIC_RELATIONS_TABLE, TOPICS_TABLE, } from './schema'; import type { IdentityDatabaseSchema } from '../types/database'; export async function initializeSchema( db: Kysely, ): Promise { await db.schema .createTable(SPACES_TABLE) .ifNotExists() .addColumn('id', 'text', (column) => column.primaryKey()) .addColumn('name', 'text', (column) => column.notNull()) .addColumn('normalized_name', 'text', (column) => column.notNull().unique()) .addColumn('description', 'text') .addColumn('metadata', 'text') .addColumn('created_at', 'text', (column) => column.notNull()) .addColumn('updated_at', 'text', (column) => column.notNull()) .execute(); await db.schema .createTable(TOPICS_TABLE) .ifNotExists() .addColumn('id', 'text', (column) => column.primaryKey()) .addColumn('space_id', 'text', (column) => column.notNull().references(`${SPACES_TABLE}.id`).onDelete('cascade'), ) .addColumn('name', 'text', (column) => column.notNull()) .addColumn('normalized_name', 'text', (column) => column.notNull()) .addColumn('category', 'text', (column) => column.notNull()) .addColumn('granularity', 'text', (column) => column.notNull()) .addColumn('description', 'text') .addColumn('metadata', 'text') .addColumn('created_at', 'text', (column) => column.notNull()) .addColumn('updated_at', 'text', (column) => column.notNull()) .addUniqueConstraint('topics_space_normalized_name_key', ['space_id', 'normalized_name']) .execute(); await db.schema .createTable(FACTS_TABLE) .ifNotExists() .addColumn('id', 'text', (column) => column.primaryKey()) .addColumn('space_id', 'text', (column) => column.notNull().references(`${SPACES_TABLE}.id`).onDelete('cascade'), ) .addColumn('statement', 'text', (column) => column.notNull()) .addColumn('summary', 'text') .addColumn('source', 'text') .addColumn('confidence', 'real') .addColumn('metadata', 'text') .addColumn('created_at', 'text', (column) => column.notNull()) .addColumn('updated_at', 'text', (column) => column.notNull()) .execute(); await db.schema .createTable(FACT_EMBEDDINGS_TABLE) .ifNotExists() .addColumn('fact_id', 'text', (column) => column.notNull().references(`${FACTS_TABLE}.id`).onDelete('cascade'), ) .addColumn('model', 'text', (column) => column.notNull()) .addColumn('dimensions', 'integer', (column) => column.notNull()) .addColumn('embedding', 'text', (column) => column.notNull()) .addColumn('content_hash', 'text', (column) => column.notNull()) .addColumn('created_at', 'text', (column) => column.notNull()) .addColumn('updated_at', 'text', (column) => column.notNull()) .addPrimaryKeyConstraint('fact_embeddings_pk', ['fact_id', 'model']) .execute(); await db.schema .createTable(FACT_TOPICS_TABLE) .ifNotExists() .addColumn('fact_id', 'text', (column) => column.notNull().references(`${FACTS_TABLE}.id`).onDelete('cascade'), ) .addColumn('topic_id', 'text', (column) => column.notNull().references(`${TOPICS_TABLE}.id`).onDelete('cascade'), ) .addColumn('role', 'text') .addColumn('position', 'integer', (column) => column.notNull()) .addColumn('created_at', 'text', (column) => column.notNull()) .addPrimaryKeyConstraint('fact_topics_pk', ['fact_id', 'topic_id', 'position']) .execute(); await db.schema .createTable(TOPIC_RELATIONS_TABLE) .ifNotExists() .addColumn('parent_topic_id', 'text', (column) => column.notNull().references(`${TOPICS_TABLE}.id`).onDelete('cascade'), ) .addColumn('child_topic_id', 'text', (column) => column.notNull().references(`${TOPICS_TABLE}.id`).onDelete('cascade'), ) .addColumn('relation', 'text', (column) => column.notNull()) .addColumn('created_at', 'text', (column) => column.notNull()) .addPrimaryKeyConstraint('topic_relations_pk', ['parent_topic_id', 'child_topic_id', 'relation']) .execute(); await db.schema .createTable(TOPIC_ALIASES_TABLE) .ifNotExists() .addColumn('id', 'text', (column) => column.primaryKey()) .addColumn('space_id', 'text', (column) => column.notNull().references(`${SPACES_TABLE}.id`).onDelete('cascade'), ) .addColumn('topic_id', 'text', (column) => column.notNull().references(`${TOPICS_TABLE}.id`).onDelete('cascade'), ) .addColumn('alias', 'text', (column) => column.notNull()) .addColumn('normalized_alias', 'text', (column) => column.notNull()) .addColumn('is_primary', 'integer', (column) => column.notNull()) .addColumn('created_at', 'text', (column) => column.notNull()) .addColumn('updated_at', 'text', (column) => column.notNull()) .addUniqueConstraint('topic_aliases_space_normalized_alias_key', ['space_id', 'normalized_alias']) .execute(); await db.schema .createIndex('topics_space_id_idx') .ifNotExists() .on(TOPICS_TABLE) .column('space_id') .execute(); await db.schema .createIndex('facts_space_id_idx') .ifNotExists() .on(FACTS_TABLE) .column('space_id') .execute(); await db.schema .createIndex('fact_topics_topic_id_idx') .ifNotExists() .on(FACT_TOPICS_TABLE) .column('topic_id') .execute(); await db.schema .createIndex('fact_topics_fact_id_idx') .ifNotExists() .on(FACT_TOPICS_TABLE) .column('fact_id') .execute(); await db.schema .createIndex('fact_embeddings_model_idx') .ifNotExists() .on(FACT_EMBEDDINGS_TABLE) .column('model') .execute(); await db.schema .createIndex('topic_relations_parent_topic_id_idx') .ifNotExists() .on(TOPIC_RELATIONS_TABLE) .column('parent_topic_id') .execute(); await db.schema .createIndex('topic_relations_child_topic_id_idx') .ifNotExists() .on(TOPIC_RELATIONS_TABLE) .column('child_topic_id') .execute(); await db.schema .createIndex('topic_aliases_space_id_idx') .ifNotExists() .on(TOPIC_ALIASES_TABLE) .column('space_id') .execute(); await db.schema .createIndex('topic_aliases_topic_id_idx') .ifNotExists() .on(TOPIC_ALIASES_TABLE) .column('topic_id') .execute(); }