"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ThreadsDAO = void 0; const uuid_1 = require("uuid"); class ThreadsDAO { dbManager; constructor(dbManager) { this.dbManager = dbManager; } get db() { return this.dbManager.getDatabase(); } create(input) { const id = input.id || (0, uuid_1.v4)(); const now = new Date(); const thread = { id, sessionId: input.sessionId || id, title: input.title || 'New Thread', description: input.description, gitBranch: input.gitBranch, createdAt: input.createdAt || now, updatedAt: input.updatedAt || now, messageCount: input.messageCount || 0, isActive: input.isActive || false, metadata: { filesChanged: input.metadata?.filesChanged || 0, linesAdded: input.metadata?.linesAdded || 0, linesDeleted: input.metadata?.linesDeleted || 0, tags: input.metadata?.tags || [] } }; const stmt = this.db.prepare(` INSERT INTO threads ( id, session_id, git_branch, title, description, created_at, updated_at, message_count, is_active, files_changed, lines_added, lines_deleted, tags ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) `); stmt.run(thread.id, thread.sessionId, thread.gitBranch || null, thread.title, thread.description || null, thread.createdAt.getTime(), thread.updatedAt.getTime(), thread.messageCount, thread.isActive ? 1 : 0, thread.metadata.filesChanged, thread.metadata.linesAdded, thread.metadata.linesDeleted, JSON.stringify(thread.metadata.tags || [])); return thread; } findById(id) { const stmt = this.db.prepare('SELECT * FROM threads WHERE id = ?'); const row = stmt.get(id); if (!row) return null; return this.mapRowToThread(row); } findAll(options) { const { limit = 50, offset = 0, sortBy = 'updatedAt', order = 'desc', tags } = options || {}; let query = 'SELECT * FROM threads'; let countQuery = 'SELECT COUNT(*) as total FROM threads'; const params = []; const conditions = []; if (tags && tags.length > 0) { // Note: This is a simple implementation. Ideally use FTS or separate tags table. // For now, using LIKE on JSON string which is suboptimal but works for MVP. const tagConditions = tags.map(tag => { params.push(`%"${tag}"%`); return 'tags LIKE ?'; }); conditions.push(`(${tagConditions.join(' OR ')})`); } if (conditions.length > 0) { const whereClause = ` WHERE ${conditions.join(' AND ')}`; query += whereClause; countQuery += whereClause; } const sortColumn = sortBy === 'updatedAt' ? 'updated_at' : sortBy === 'createdAt' ? 'created_at' : 'message_count'; query += ` ORDER BY ${sortColumn} ${order.toUpperCase()}`; query += ` LIMIT ? OFFSET ?`; // params for where clause + limit + offset const queryParams = [...params, limit, offset]; const rows = this.db.prepare(query).all(...queryParams); const totalRow = this.db.prepare(countQuery).get(...params); return { threads: rows.map(this.mapRowToThread), total: totalRow.total }; } update(id, updates) { const current = this.findById(id); if (!current) return null; // Merge updates const updated = { ...current, ...updates }; updated.updatedAt = new Date(); // Always update updatedAt // Ensure metadata is merged correctly if provided if (updates.metadata) { updated.metadata = { ...current.metadata, ...updates.metadata }; } const stmt = this.db.prepare(` UPDATE threads SET title = ?, description = ?, git_branch = ?, updated_at = ?, message_count = ?, is_active = ?, files_changed = ?, lines_added = ?, lines_deleted = ?, tags = ? WHERE id = ? `); stmt.run(updated.title, updated.description || null, updated.gitBranch || null, updated.updatedAt.getTime(), updated.messageCount, updated.isActive ? 1 : 0, updated.metadata.filesChanged, updated.metadata.linesAdded, updated.metadata.linesDeleted, JSON.stringify(updated.metadata.tags || []), id); return updated; } delete(id) { const stmt = this.db.prepare('DELETE FROM threads WHERE id = ?'); const result = stmt.run(id); return result.changes > 0; } setActive(id) { const trx = this.db.transaction(() => { // Deactivate all this.db.prepare('UPDATE threads SET is_active = 0').run(); // Activate target const result = this.db.prepare('UPDATE threads SET is_active = 1 WHERE id = ?').run(id); return result.changes > 0; }); return trx(); } getActive() { const stmt = this.db.prepare('SELECT * FROM threads WHERE is_active = 1 LIMIT 1'); const row = stmt.get(); if (!row) return null; return this.mapRowToThread(row); } findByPrefix(prefix) { const stmt = this.db.prepare(`SELECT * FROM threads WHERE id LIKE ? || '%'`); const rows = stmt.all(prefix); return rows.map(this.mapRowToThread); } mapRowToThread(row) { return { id: row.id, sessionId: row.session_id || row.id, title: row.title, description: row.description || undefined, gitBranch: row.git_branch || undefined, createdAt: new Date(row.created_at), updatedAt: new Date(row.updated_at), messageCount: row.message_count, isActive: Boolean(row.is_active), metadata: { filesChanged: row.files_changed, linesAdded: row.lines_added, linesDeleted: row.lines_deleted, tags: JSON.parse(row.tags || '[]') } }; } } exports.ThreadsDAO = ThreadsDAO;