import Database, { type Database as SqliteDatabase } from 'bun:sqlite'; import { initializeDatabase } from '../../src/db'; import { setDb } from '../../src/db/locator'; import { toIsoSql } from './dates'; // Servicios opcionales para inyección de DB en tests. // Importamos con nombres existentes en la base de código para respetar convenciones. import { TaskService } from '../../src/tasks/service'; import { CommandService } from '../../src/services/command'; import { ResponseQueue } from '../../src/services/response-queue'; import { IdentityService } from '../../src/services/identity'; import { GroupSyncService } from '../../src/services/group-sync'; import { RemindersService } from '../../src/services/reminders'; import { AllowedGroups } from '../../src/services/allowed-groups'; /** * Crea una DB en memoria y aplica initializeDatabase() con todas las migraciones. */ export function makeMemDb(): SqliteDatabase { const memdb = new Database(':memory:'); initializeDatabase(memdb); return memdb; } /** * Inyecta la instancia de DB en los servicios que la exponen como propiedad estática. * Pensado para usarse en beforeAll/beforeEach de tests que usan estos servicios. */ export function injectAllServices(db: SqliteDatabase): void { setDb(db); } /** * Restablece estado global/cachés en servicios entre tests. * Best-effort: solo llama si existen los métodos. */ export function resetServices(): void { try { (IdentityService as any).clearCache?.(); } catch {} try { (GroupSyncService as any).clearCaches?.(); } catch {} try { (CommandService as any).resetForTests?.(); } catch {} try { (ResponseQueue as any).resetForTests?.(); } catch {} try { (RemindersService as any).resetForTests?.(); } catch {} } /** * Marca como 'allowed' los groupIds indicados en la DB provista. */ /** * Sembrar un grupo en la DB rellenando columnas NOT NULL sin valor por defecto. * Usa PRAGMA table_info para adaptarse automáticamente a la forma actual de la tabla. */ export function seedGroup(db: SqliteDatabase, groupId: string): void { const cols = db.query(`PRAGMA table_info(groups)`).all() as any[]; const values: Record = {}; const nowIso = toIsoSql(new Date()); for (const c of cols) { const name = String(c.name); const type = String(c.type || '').toUpperCase(); const notnull = Number(c.notnull || 0) === 1; const hasDefault = c.dflt_value != null; if (name === 'id') { values[name] = groupId; continue; } // Preconfigurar algunos alias comunes if (name === 'name' || name === 'title' || name === 'subject') { values[name] = 'Test Group'; continue; } if (name === 'created_by') { values[name] = 'tester'; continue; } if (name.endsWith('_at')) { values[name] = nowIso; continue; } if (name === 'is_active' || name === 'active') { values[name] = 1; continue; } // Para columnas NOT NULL sin valor por defecto, asignar valores genéricos if (notnull && !hasDefault) { if (type.includes('INT')) values[name] = 1; else if (type.includes('REAL')) values[name] = 0; else values[name] = 'N/A'; } } // Asegurar que id esté siempre if (!('id' in values)) values['id'] = groupId; const colsList = Object.keys(values); const placeholders = colsList.map(() => '?').join(', '); const sql = `INSERT OR REPLACE INTO groups (${colsList.join(', ')}) VALUES (${placeholders})`; db.prepare(sql).run(...colsList.map(k => values[k])); } export function seedAllowed(db: SqliteDatabase, groupIds: string[]): void { for (const gid of groupIds) { const g = String(gid || '').trim(); if (!g) continue; try { AllowedGroups.setStatus(g, 'allowed'); } catch {} } }