import { createChildLogger, type Logger } from "@bete/shared/logger"; import type { NodePgDatabase } from "drizzle-orm/node-postgres"; import type * as schema from "../../shared/database/schema.js"; import type { MessageQuery, MessageRecord, PageResult, } from "../message-capture/types.js"; import type { AIAnalysisUpdate } from "./messages.analysis.js"; import { MessagesAnalysis } from "./messages.analysis.js"; import { MessagesCleanup } from "./messages.cleanup.js"; import { MessagesCrud } from "./messages.crud.js"; import { MessagesPagination } from "./messages.pagination.js"; import { MessagesSearch } from "./messages.search.js"; // Re-export AIAnalysisUpdate for consumers (messageStore.ts imports it) export type { AIAnalysisUpdate } from "./messages.analysis.js"; // ─── MessagesDb Facade ──────────────────────────────────────────────────────── // Thin facade that delegates to domain-specific sub-modules. export class MessagesDb { private crud: MessagesCrud; private analysis: MessagesAnalysis; private search: MessagesSearch; private pagination: MessagesPagination; private cleanup: MessagesCleanup; constructor(db: NodePgDatabase, _parentLogger?: Logger) { const logger = _parentLogger ?? createChildLogger("messages-db"); this.crud = new MessagesCrud(db, logger); this.analysis = new MessagesAnalysis(db, logger); this.search = new MessagesSearch(db, logger); this.pagination = new MessagesPagination(db, logger); this.cleanup = new MessagesCleanup(db, logger); } // ── CRUD ──────────────────────────────────────────────────────────────── insertMessage(message: MessageRecord): Promise { return this.crud.insertMessage(message); } upsertMessageForCapture(message: MessageRecord): Promise { return this.crud.upsertMessageForCapture(message); } updateMessageAsEdited( messageId: string, editedContent: string, editedAt: number, ): Promise { return this.crud.updateMessageAsEdited(messageId, editedContent, editedAt); } updateMessageAsDeleted(messageId: string, deletedAt: number): Promise { return this.crud.updateMessageAsDeleted(messageId, deletedAt); } getMessagesByChannel( channelId: string, limit?: number, offset?: number, guildId?: string, ): Promise { return this.crud.getMessagesByChannel(channelId, limit, offset, guildId); } getMessageById(messageId: string): Promise { return this.crud.getMessageById(messageId); } // ── AI Analysis ───────────────────────────────────────────────────────── updateMessageAIAnalysis( messageId: string, result: AIAnalysisUpdate, ): Promise { return this.analysis.updateMessageAIAnalysis(messageId, result); } updateMessagesAIAnalysisBulk( updates: Array<{ messageId: string; result: AIAnalysisUpdate }>, ): Promise { return this.analysis.updateMessagesAIAnalysisBulk(updates); } getPendingAIAnalysisMessages(limit?: number): Promise { return this.analysis.getPendingAIAnalysisMessages(limit); } getConversationContextBefore(input: { channelId: string; threadId: string | null; beforeCreatedAt: number; limit: number; }): Promise { return this.analysis.getConversationContextBefore(input); } getPendingMessagesByConversation( conversationKey: string, limit?: number, ): Promise { return this.analysis.getPendingMessagesByConversation( conversationKey, limit, ); } getPendingConversationKeys(limit?: number): Promise { return this.analysis.getPendingConversationKeys(limit); } getConversationKeysWithIncompleteAnalysis(limit?: number): Promise { return this.analysis.getConversationKeysWithIncompleteAnalysis(limit); } getIncompleteMessagesByConversation( conversationKey: string, limit?: number, ): Promise { return this.analysis.getIncompleteMessagesByConversation( conversationKey, limit, ); } // ── Edit History ───────────────────────────────────────────────────────── insertMessageEdit(messageId: string, oldContent: string, editedAt: number): Promise { return this.crud.insertMessageEdit(messageId, oldContent, editedAt); } // ── Search ────────────────────────────────────────────────────────────── searchMessages(input: { query: string; channelId?: string; guildId?: string; limit?: number; }): Promise { return this.search.searchMessages(input); } // ── Pagination ────────────────────────────────────────────────────────── listMessages(query: MessageQuery): Promise> { return this.pagination.listMessages(query); } listReviewMessages( query: Omit, ): Promise> { return this.pagination.listReviewMessages(query); } // ── Cleanup ───────────────────────────────────────────────────────────── getExpiredMessages(retentionDays: number): Promise { return this.cleanup.getExpiredMessages(retentionDays); } revertStuckProcessingMessages(timeoutMs?: number): Promise { return this.cleanup.revertStuckProcessingMessages(timeoutMs); } }