/** * Database interactions. */ import Database from "better-sqlite3"; import { migrate } from "@blackglory/better-sqlite3-migrations"; import utils from "./utils.mjs"; import config from "./config.mjs"; // Interface. export class DB { /** * Connect to a database and perform migrations. */ constructor() { this.my_db = createDB(); } /** * Fetch information about a site. * @param {!string} site url. * @return {!ObjType} site information. */ siteInfo(site_url) { return getSiteInfo(this.my_db, site_url); } /** * Fetch all comments from a specific site. * @param {!string} site url. * @return {!Array} comment objects. */ siteComments(site_url) { return getSiteComments(this.my_db, site_url); } /** * Fetch comments from a specific page in a specific site. * @param {!string} site url. * @param {!string} page path. * @return {!Array} comment objects. */ pageComments(site_url, page) { return getPageComments(this.my_db, site_url, page); } /** * Insert a comment into the database. * @param {!string} site url. * @param {!string} page path. * @param {!ObjType} comment. * @return {!Array} page comments. */ insertPageComment(site_url, path, comment) { return insertPageComment(this.my_db, site_url, path, comment); } } const db = new DB(); export default db; // Migrations function migrations() { return [ { version: 1, up: ` CREATE TABLE comment ( id integer not null, site integer not null, path text not null, user text not null, user_website text, message text not null, published text default (datetime('now')), reply_to integer, PRIMARY KEY (site, path, id) ); `, down: ` DROP TABLE comment; `, }, ]; } // setup function createDB() { const db = new Database(utils.db_path); db.pragma("journal_mode = WAL"); migrate(db, migrations(), 1); return db; } // queries function getSiteInfo(db, site_url) { const site = config.getSite(site_url); if (!site || !site.info) { throw "Unknown site"; } return site; } function insertPageComment(db, site_url, path, comment) { const site = config.getSite(site_url); if (!site || !site.info.id) { throw "Unknown site"; } let object = { ...comment, site_id: site.info.id, path: path }; const stmt = db.prepare(` INSERT INTO comment(id, site, path, user, user_website, message, reply_to) SELECT ( SELECT count(*) FROM comment WHERE site = @site_id AND path = @path ), @site_id, @path, @user, @user_website, @message, @reply_to RETURNING id, user, user_website, message, published, reply_to ; `); stmt.all(object); // return all comments because a new comment might have been added // since the user loaded the page. return getPageComments(db, site_url, path); } function getPageComments(db, site_url, path) { const site = config.getSite(site_url); if (!site || !site.info.id) { return []; } const stmt = db.prepare(` SELECT id, user, user_website, message, published, reply_to FROM comment WHERE site = @site_id AND path = @path ORDER BY id ;`); return stmt.all({ site_id: site.info.id, path }); } function getSiteComments(db, site_url) { const site = config.getSite(site_url); if (!site || !site.info.id) { return []; } const stmt = db.prepare(` SELECT id, @site_url as site, path, user, user_website, message, published FROM comment WHERE site = @site_id ORDER BY published DESC ; `); return stmt.all({ site_id: site.info.id, site_url }); }