Files
RedditBot/src/database/client.ts
T
2026-01-05 00:17:06 +00:00

116 lines
3.9 KiB
TypeScript

import Database from 'better-sqlite3';
import type { Config } from '../config/index.js';
import path from 'path';
import fs from 'fs';
export function createDatabase(config: Config): Database.Database {
const dbPath = path.resolve(process.cwd(), config.database.path);
const dbDir = path.dirname(dbPath);
// Ensure directory exists
if (!fs.existsSync(dbDir)) {
fs.mkdirSync(dbDir, { recursive: true });
}
const db = new Database(dbPath);
// Enable WAL mode for better concurrency
db.pragma('journal_mode = WAL');
db.pragma('foreign_keys = ON');
return db;
}
export function runMigrations(db: Database.Database): void {
// Create tables if they don't exist
db.exec(`
CREATE TABLE IF NOT EXISTS processed_posts (
id TEXT PRIMARY KEY,
subreddit TEXT NOT NULL,
author TEXT NOT NULL,
title TEXT NOT NULL,
image_url TEXT,
image_analysis TEXT,
generated_message TEXT,
processed_at INTEGER NOT NULL,
message_sent INTEGER DEFAULT 0,
error TEXT
);
CREATE TABLE IF NOT EXISTS sent_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
post_id TEXT NOT NULL,
recipient TEXT NOT NULL,
subject TEXT NOT NULL,
message TEXT NOT NULL,
sent_at INTEGER NOT NULL,
FOREIGN KEY (post_id) REFERENCES processed_posts(id)
);
CREATE TABLE IF NOT EXISTS successful_messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sent_message_id INTEGER,
original_message TEXT NOT NULL,
image_analysis TEXT,
post_title TEXT,
response_snippet TEXT,
created_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_posts_subreddit
ON processed_posts(subreddit);
CREATE INDEX IF NOT EXISTS idx_posts_processed_at
ON processed_posts(processed_at);
CREATE INDEX IF NOT EXISTS idx_posts_message_sent
ON processed_posts(message_sent);
`);
// Add new columns to existing tables (safe to run multiple times)
const addColumnIfNotExists = (table: string, column: string, definition: string) => {
const columns = db.prepare(`PRAGMA table_info(${table})`).all() as { name: string }[];
const exists = columns.some((c) => c.name === column);
if (!exists) {
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`);
}
};
addColumnIfNotExists('sent_messages', 'got_response', 'INTEGER DEFAULT 0');
addColumnIfNotExists('sent_messages', 'response_checked_at', 'INTEGER');
// Create index for response checking
db.exec(`CREATE INDEX IF NOT EXISTS idx_sent_messages_response ON sent_messages(got_response)`);
db.exec(`CREATE INDEX IF NOT EXISTS idx_sent_messages_recipient ON sent_messages(recipient)`);
// Migration: Make sent_message_id nullable in successful_messages
// SQLite doesn't support ALTER COLUMN, so we need to recreate the table
const successfulMsgColumns = db.prepare(`PRAGMA table_info(successful_messages)`).all() as { name: string; notnull: number }[];
const sentMsgIdCol = successfulMsgColumns.find((c) => c.name === 'sent_message_id');
if (sentMsgIdCol && sentMsgIdCol.notnull === 1) {
// Column is currently NOT NULL, we need to migrate
db.exec(`
-- Create new table with nullable sent_message_id
CREATE TABLE successful_messages_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sent_message_id INTEGER,
original_message TEXT NOT NULL,
image_analysis TEXT,
post_title TEXT,
response_snippet TEXT,
created_at INTEGER NOT NULL
);
-- Copy existing data
INSERT INTO successful_messages_new
SELECT id, sent_message_id, original_message, image_analysis, post_title, response_snippet, created_at
FROM successful_messages;
-- Drop old table
DROP TABLE successful_messages;
-- Rename new table
ALTER TABLE successful_messages_new RENAME TO successful_messages;
`);
}
}