import * as config from './config'; import * as sqlite from 'bun:sqlite'; import { EVENT, SESSION } from './enums'; // In-memory views export const sessions = {}; export const desks = {}; export const queries = {}; export let db = null; export function startup() { const path = `${config.DATADIR}/db.sqlite`; db = new sqlite.Database(path, { create: true }); db.query(`CREATE TABLE IF NOT EXISTS desks ( id INTEGER PRIMARY KEY, sn INTEGER, title TEXT );`).run(); db.query(`CREATE TABLE IF NOT EXISTS sessions ( id INTEGER PRIMARY KEY, desk_id INTEGER, lsn INTEGER, color INTEGER, width INTEGER, FOREIGN KEY (desk_id) REFERENCES desks (id) ON DELETE CASCADE ON UPDATE NO ACTION );`).run(); db.query(`CREATE TABLE IF NOT EXISTS strokes ( id INTEGER PRIMARY KEY, width INTEGER, color INTEGER, points BLOB );`).run(); db.query(`CREATE TABLE IF NOT EXISTS events ( id INTEGER PRIMARY KEY, type INTEGER, desk_id INTEGER, session_id INTEGER, stroke_id INTEGER, image_id INTEGER, x INTEGER, y INTEGER, FOREIGN KEY (desk_id) REFERENCES desks (id) ON DELETE CASCADE ON UPDATE NO ACTION FOREIGN KEY (session_id) REFERENCES sessions (id) ON DELETE NO ACTION ON UPDATE NO ACTION FOREIGN KEY (stroke_id) REFERENCES strokes (id) ON DELETE CASCADE ON UPDATE NO ACTION );`).run(); // INSERT queries.insert_desk = db.query('INSERT INTO desks (id, title, sn) VALUES ($id, $title, 0) RETURNING id'); queries.insert_stroke = db.query('INSERT INTO strokes (width, color, points) VALUES ($width, $color, $points) RETURNING id'); queries.insert_session = db.query('INSERT INTO sessions (id, desk_id, lsn) VALUES ($id, $desk_id, 0) RETURNING id'); queries.insert_event = db.query('INSERT INTO events (type, desk_id, session_id, stroke_id, image_id, x, y) VALUES ($type, $desk_id, $session_id, $stroke_id, $image_id, $x, $y) RETURNING id'); // UPDATE queries.update_desk_sn = db.query('UPDATE desks SET sn = $sn WHERE id = $id'); queries.update_session_lsn = db.query('UPDATE sessions SET lsn = $lsn WHERE id = $id'); queries.update_session_color = db.query('UPDATE sessions SET color = $color WHERE id = $id'); queries.update_session_width = db.query('UPDATE sessions SET width = $width WHERE id = $id'); const res1 = db.query('SELECT COUNT(id) as count FROM desks').get(); const res2 = db.query('SELECT COUNT(id) as count FROM events').get(); const res3 = db.query('SELECT COUNT(id) as count FROM strokes').get(); const res4 = db.query('SELECT COUNT(id) as count FROM sessions').get(); console.log(`Storing data in ${path}`); console.log(`Entity count at startup: ${res1.count} desks ${res2.count} events ${res3.count} strokes ${res4.count} sessions `); // Init in-memory view: merge strokes into events, set all sessions to closed const stored_desks = db.query('SELECT * FROM desks').all(); const stored_events = db.query('SELECT * FROM events').all(); const stored_strokes = db.query('SELECT * FROM strokes').all(); const stored_sessions = db.query('SELECT * FROM sessions').all(); const stroke_dict = {}; for (const desk of stored_desks) { desks[desk.id] = desk; desks[desk.id].events = []; desks[desk.id].total_points = 0; } for (const stroke of stored_strokes) { stroke.points = new Float32Array(stroke.points.buffer); stroke_dict[stroke.id] = stroke; } for (const event of stored_events) { if (event.type === EVENT.STROKE) { const stroke = stroke_dict[event.stroke_id]; event.points = stroke.points; event.color = stroke.color; event.width = stroke.width; desks[event.desk_id].total_points += stroke.points.length / 2; } desks[event.desk_id].events.push(event); } for (const session of stored_sessions) { session.state = SESSION.CLOSED; session.ws = null; session.sync_attempts = 0; sessions[session.id] = session; } }