diff --git a/src/db.ts b/src/db.ts index dc78d6b..4636319 100644 --- a/src/db.ts +++ b/src/db.ts @@ -15,11 +15,12 @@ export function initializeDatabase(instance: Database) { instance.exec(`PRAGMA foreign_keys = ON;`); // Create users table first as others depend on it + // Use TEXT for timestamps to store higher precision ISO8601 format easily instance.exec(` CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, -- WhatsApp user ID (normalized) - first_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - last_seen TIMESTAMP DEFAULT CURRENT_TIMESTAMP + first_seen TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')), + last_seen TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')) ); `); @@ -29,7 +30,7 @@ export function initializeDatabase(instance: Database) { id TEXT PRIMARY KEY, -- Group ID (normalized) community_id TEXT NOT NULL, name TEXT, - last_verified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + last_verified TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')), active BOOLEAN DEFAULT TRUE ); `); @@ -39,10 +40,10 @@ export function initializeDatabase(instance: Database) { CREATE TABLE IF NOT EXISTS tasks ( id INTEGER PRIMARY KEY AUTOINCREMENT, description TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - due_date TIMESTAMP NULL, + created_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')), + due_date TEXT NULL, -- Store dates as ISO8601 strings or YYYY-MM-DD completed BOOLEAN DEFAULT FALSE, - completed_at TIMESTAMP NULL, + completed_at TEXT NULL, group_id TEXT NULL, -- Normalized group ID created_by TEXT NOT NULL, -- Normalized user ID FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE CASCADE, @@ -56,7 +57,7 @@ export function initializeDatabase(instance: Database) { task_id INTEGER NOT NULL, user_id TEXT NOT NULL, -- Normalized user ID assigned_by TEXT NOT NULL, -- Normalized user ID - assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + assigned_at TEXT DEFAULT (strftime('%Y-%m-%d %H:%M:%f', 'now')), PRIMARY KEY (task_id, user_id), FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, @@ -70,6 +71,7 @@ export function initializeDatabase(instance: Database) { * If the user exists, updates their last_seen timestamp. * If the user does not exist, creates them. * Uses the normalizeWhatsAppId utility. + * Stores timestamps with millisecond precision. * * @param rawUserId The raw WhatsApp ID (e.g., '12345@s.whatsapp.net'). * @param instance The database instance to use (defaults to the main db). @@ -84,25 +86,24 @@ export function ensureUserExists(rawUserId: string | null | undefined, instance: } try { - // Use INSERT OR IGNORE to add the user only if they don't exist, - // then UPDATE their last_seen timestamp regardless. - // This is often more efficient than SELECT followed by INSERT/UPDATE. + // Use strftime for millisecond precision timestamps const insertStmt = instance.prepare(` INSERT INTO users (id, first_seen, last_seen) - VALUES (?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP) + VALUES (?, strftime('%Y-%m-%d %H:%M:%f', 'now'), strftime('%Y-%m-%d %H:%M:%f', 'now')) ON CONFLICT(id) DO NOTHING; `); const updateStmt = instance.prepare(` UPDATE users - SET last_seen = CURRENT_TIMESTAMP + SET last_seen = strftime('%Y-%m-%d %H:%M:%f', 'now') WHERE id = ?; `); // Run as transaction for atomicity instance.transaction(() => { insertStmt.run(normalizedId); - updateStmt.run(normalizedId); + // Update last_seen even if the user was just inserted or already existed + updateStmt.run(normalizedId); })(); // Immediately invoke the transaction return normalizedId;