From 972f2f40bf60a3418603df14abee85ed68d3634e Mon Sep 17 00:00:00 2001
From: zadam <zadam.apps@gmail.com>
Date: Thu, 23 Dec 2021 12:54:21 +0100
Subject: [PATCH] share improvements/cleanup

---
 src/public/stylesheets/share.css |   2 +-
 src/services/sql.js              |  31 ++-----
 src/share/shaca/shaca_loader.js  |  23 +++--
 src/share/sql.js                 | 143 ++-----------------------------
 4 files changed, 30 insertions(+), 169 deletions(-)

diff --git a/src/public/stylesheets/share.css b/src/public/stylesheets/share.css
index 084056353..4adf7539b 100644
--- a/src/public/stylesheets/share.css
+++ b/src/public/stylesheets/share.css
@@ -43,7 +43,7 @@ body {
     padding: 20px;
 }
 
-.type-image img {
+img {
     max-width: 100%;
 }
 
diff --git a/src/services/sql.js b/src/services/sql.js
index ac07ad966..76ebb52ef 100644
--- a/src/services/sql.js
+++ b/src/services/sql.js
@@ -2,6 +2,8 @@
 
 /**
  * @module sql
+ *
+ * TODO: some methods (like getValue()) could use raw rows
  */
 
 const log = require('./log');
@@ -89,13 +91,7 @@ function getRowOrNull(query, params = []) {
 }
 
 function getValue(query, params = []) {
-    const row = getRowOrNull(query, params);
-
-    if (!row) {
-        return null;
-    }
-
-    return row[Object.keys(row)[0]];
+    return wrap(query, s => s.pluck().get(params));
 }
 
 // smaller values can result in better performance due to better usage of statement cache
@@ -144,32 +140,17 @@ function iterateRows(query, params = []) {
 
 function getMap(query, params = []) {
     const map = {};
-    const results = getRows(query, params);
+    const results = getRawRows(query, params);
 
     for (const row of results) {
-        const keys = Object.keys(row);
-
-        map[row[keys[0]]] = row[keys[1]];
+        map[row[0]] = row[1];
     }
 
     return map;
 }
 
 function getColumn(query, params = []) {
-    const list = [];
-    const result = getRows(query, params);
-
-    if (result.length === 0) {
-        return list;
-    }
-
-    const key = Object.keys(result[0])[0];
-
-    for (const row of result) {
-        list.push(row[key]);
-    }
-
-    return list;
+    return wrap(query, s => s.pluck().all(params));
 }
 
 function execute(query, params = []) {
diff --git a/src/share/shaca/shaca_loader.js b/src/share/shaca/shaca_loader.js
index 39e541809..4f849eaf8 100644
--- a/src/share/shaca/shaca_loader.js
+++ b/src/share/shaca/shaca_loader.js
@@ -34,15 +34,28 @@ function load() {
 
     const noteIdStr = noteIds.map(noteId => `'${noteId}'`).join(",");
 
-    for (const row of sql.getRawRows(`SELECT noteId, title, type, mime, utcDateModified FROM notes WHERE isDeleted = 0 AND noteId IN (${noteIdStr})`)) {
+    const rawNoteRows = sql.getRawRows(`
+        SELECT noteId, title, type, mime, utcDateModified 
+        FROM notes 
+        WHERE isDeleted = 0 
+          AND noteId IN (${noteIdStr})`);
+
+    for (const row of rawNoteRows) {
         new Note(row);
     }
 
-    for (const row of sql.getRawRows(`SELECT branchId, noteId, parentNoteId, prefix, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0 AND parentNoteId IN (${noteIdStr}) ORDER BY notePosition`)) {
+    const rawBranchRows = sql.getRawRows(`
+        SELECT branchId, noteId, parentNoteId, prefix, isExpanded, utcDateModified 
+        FROM branches 
+        WHERE isDeleted = 0 
+          AND parentNoteId IN (${noteIdStr}) 
+        ORDER BY notePosition`);
+
+    for (const row of rawBranchRows) {
         new Branch(row);
     }
 
-    const attributes = sql.getRawRows(`
+    const rawAttributeRows = sql.getRawRows(`
         SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified 
         FROM attributes 
         WHERE isDeleted = 0 
@@ -52,13 +65,13 @@ function load() {
               OR (type = 'relation' AND name IN ('imageLink', 'template', 'shareCss'))
           )`, []);
 
-    for (const row of attributes) {
+    for (const row of rawAttributeRows) {
         new Attribute(row);
     }
 
     shaca.loaded = true;
 
-    log.info(`Shaca load took ${Date.now() - start}ms`);
+    log.info(`Shaca loaded ${rawNoteRows.length} notes, ${rawBranchRows.length} branches, ${rawAttributeRows.length} attributes took ${Date.now() - start}ms`);
 }
 
 function ensureLoad() {
diff --git a/src/share/sql.js b/src/share/sql.js
index 49849da76..485c87921 100644
--- a/src/share/sql.js
+++ b/src/share/sql.js
@@ -1,6 +1,5 @@
 "use strict";
 
-const log = require('../services/log');
 const Database = require('better-sqlite3');
 const dataDir = require('../services/data_dir');
 
@@ -16,152 +15,20 @@ const dbConnection = new Database(dataDir.DOCUMENT_PATH, { readonly: true });
     });
 });
 
-const statementCache = {};
-
-function stmt(sql) {
-    if (!(sql in statementCache)) {
-        statementCache[sql] = dbConnection.prepare(sql);
-    }
-
-    return statementCache[sql];
+function getRawRows(query, params = []) {
+    return dbConnection.prepare(query).raw().all(params);
 }
 
 function getRow(query, params = []) {
-    return wrap(query, s => s.get(params));
-}
-
-function getRowOrNull(query, params = []) {
-    const all = getRows(query, params);
-
-    return all.length > 0 ? all[0] : null;
-}
-
-function getValue(query, params = []) {
-    const row = getRowOrNull(query, params);
-
-    if (!row) {
-        return null;
-    }
-
-    return row[Object.keys(row)[0]];
-}
-
-// smaller values can result in better performance due to better usage of statement cache
-const PARAM_LIMIT = 100;
-
-function getManyRows(query, params) {
-    let results = [];
-
-    while (params.length > 0) {
-        const curParams = params.slice(0, Math.min(params.length, PARAM_LIMIT));
-        params = params.slice(curParams.length);
-
-        const curParamsObj = {};
-
-        let j = 1;
-        for (const param of curParams) {
-            curParamsObj['param' + j++] = param;
-        }
-
-        let i = 1;
-        const questionMarks = curParams.map(() => ":param" + i++).join(",");
-        const curQuery = query.replace(/\?\?\?/g, questionMarks);
-
-        const statement = curParams.length === PARAM_LIMIT
-            ? stmt(curQuery)
-            : dbConnection.prepare(curQuery);
-
-        const subResults = statement.all(curParamsObj);
-        results = results.concat(subResults);
-    }
-
-    return results;
-}
-
-function getRows(query, params = []) {
-    return wrap(query, s => s.all(params));
-}
-
-function getRawRows(query, params = []) {
-    return wrap(query, s => s.raw().all(params));
-}
-
-function iterateRows(query, params = []) {
-    return stmt(query).iterate(params);
-}
-
-function getMap(query, params = []) {
-    const map = {};
-    const results = getRows(query, params);
-
-    for (const row of results) {
-        const keys = Object.keys(row);
-
-        map[row[keys[0]]] = row[keys[1]];
-    }
-
-    return map;
+    return dbConnection.prepare(query).get(params);
 }
 
 function getColumn(query, params = []) {
-    const list = [];
-    const result = getRows(query, params);
-
-    if (result.length === 0) {
-        return list;
-    }
-
-    const key = Object.keys(result[0])[0];
-
-    for (const row of result) {
-        list.push(row[key]);
-    }
-
-    return list;
-}
-
-function wrap(query, func) {
-    const startTimestamp = Date.now();
-    let result;
-
-    try {
-        result = func(stmt(query));
-    }
-    catch (e) {
-        if (e.message.includes("The database connection is not open")) {
-            // this often happens on killing the app which puts these alerts in front of user
-            // in these cases error should be simply ignored.
-            console.log(e.message);
-
-            return null
-        }
-
-        throw e;
-    }
-
-    const milliseconds = Date.now() - startTimestamp;
-
-    if (milliseconds >= 20) {
-        if (query.includes("WITH RECURSIVE")) {
-            log.info(`Slow recursive query took ${milliseconds}ms.`);
-        }
-        else {
-            log.info(`Slow query took ${milliseconds}ms: ${query.trim().replace(/\s+/g, " ")}`);
-        }
-    }
-
-    return result;
+    return dbConnection.prepare(query).pluck().all(params);
 }
 
 module.exports = {
-    dbConnection,
-    getValue,
-    getRow,
-    getRowOrNull,
-    getRows,
     getRawRows,
-    iterateRows,
-    getManyRows,
-    getMap,
+    getRow,
     getColumn
 };