import { sql } from 'kysely'; import { afterEach, describe, expect, it } from 'vitest'; import { createDatabase } from '../src/adapters/dialect'; import { initializeSchema } from '../src/core/migrations'; const openConnections: Array<() => Promise> = []; afterEach(async () => { while (openConnections.length > 0) { const close = openConnections.pop(); if (close) { await close(); } } }); describe('initializeSchema', () => { it('creates the spaces, topics, facts, fact_embeddings, fact_topics, topic_relations, and topic_aliases tables', async () => { const connection = await createDatabase({ client: 'sqlite', filename: ':memory:' }); openConnections.push(connection.destroy); await initializeSchema(connection.db); const tables = await sql<{ name: string }>` SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name `.execute(connection.db); const tableNames = tables.rows.map((row) => row.name); expect(tableNames).toContain('spaces'); expect(tableNames).toContain('topics'); expect(tableNames).toContain('facts'); expect(tableNames).toContain('fact_embeddings'); expect(tableNames).toContain('fact_topics'); expect(tableNames).toContain('topic_relations'); expect(tableNames).toContain('topic_aliases'); }); it('creates the expected columns for each table', async () => { const connection = await createDatabase({ client: 'sqlite', filename: ':memory:' }); openConnections.push(connection.destroy); await initializeSchema(connection.db); const spaceColumns = await sql<{ name: string }>`PRAGMA table_info(spaces)`.execute(connection.db); const topicsColumns = await sql<{ name: string }>`PRAGMA table_info(topics)`.execute(connection.db); const factsColumns = await sql<{ name: string }>`PRAGMA table_info(facts)`.execute(connection.db); const factEmbeddingsColumns = await sql<{ name: string }>`PRAGMA table_info(fact_embeddings)`.execute(connection.db); const factTopicsColumns = await sql<{ name: string }>`PRAGMA table_info(fact_topics)`.execute(connection.db); const topicRelationsColumns = await sql<{ name: string }>`PRAGMA table_info(topic_relations)`.execute(connection.db); const topicAliasesColumns = await sql<{ name: string }>`PRAGMA table_info(topic_aliases)`.execute(connection.db); expect(spaceColumns.rows.map((row) => row.name)).toEqual([ 'id', 'name', 'normalized_name', 'description', 'metadata', 'created_at', 'updated_at', ]); expect(topicsColumns.rows.map((row) => row.name)).toEqual([ 'id', 'space_id', 'name', 'normalized_name', 'category', 'granularity', 'description', 'metadata', 'created_at', 'updated_at', ]); expect(factsColumns.rows.map((row) => row.name)).toEqual([ 'id', 'space_id', 'statement', 'summary', 'source', 'confidence', 'metadata', 'created_at', 'updated_at', ]); expect(factEmbeddingsColumns.rows.map((row) => row.name)).toEqual([ 'fact_id', 'model', 'dimensions', 'embedding', 'content_hash', 'created_at', 'updated_at', ]); expect(factTopicsColumns.rows.map((row) => row.name)).toEqual([ 'fact_id', 'topic_id', 'role', 'position', 'created_at', ]); expect(topicRelationsColumns.rows.map((row) => row.name)).toEqual([ 'parent_topic_id', 'child_topic_id', 'relation', 'created_at', ]); expect(topicAliasesColumns.rows.map((row) => row.name)).toEqual([ 'id', 'space_id', 'topic_id', 'alias', 'normalized_alias', 'is_primary', 'created_at', 'updated_at', ]); }); it('is idempotent when called more than once', async () => { const connection = await createDatabase({ client: 'sqlite', filename: ':memory:' }); openConnections.push(connection.destroy); await initializeSchema(connection.db); await expect(initializeSchema(connection.db)).resolves.toBeUndefined(); }); });