fix: use strftime for millisecond timestamp precision in SQLite

main
borja (aider) 2 months ago
parent d3fd7f144d
commit d0f8442e65

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

Loading…
Cancel
Save