You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
3.7 KiB
TypeScript

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<string, any> = {};
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 {}
}
}