From bd2a5f6d82f04251aeb50949113394ca1a92d71f Mon Sep 17 00:00:00 2001 From: azivner Date: Sat, 23 Dec 2017 11:02:38 -0500 Subject: [PATCH] change in naming of SQL methods added assert methods to note tree --- migrations/0031__change_encryption_to_CBC.js | 4 +- public/javascripts/note_tree.js | 42 ++++++++++++++++++++ public/javascripts/utils.js | 12 ++++++ routes/api/cleanup.js | 2 +- routes/api/event_log.js | 4 +- routes/api/export.js | 8 ++-- routes/api/import.js | 4 +- routes/api/note_history.js | 2 +- routes/api/notes.js | 4 +- routes/api/notes_move.js | 16 ++++---- routes/api/recent_changes.js | 2 +- routes/api/recent_notes.js | 2 +- routes/api/sql.js | 2 +- routes/api/sync.js | 14 +++---- routes/api/tree.js | 2 +- routes/index.js | 2 +- services/consistency_checks.js | 2 +- services/content_hash.js | 10 ++--- services/messaging.js | 4 +- services/notes.js | 20 +++++----- services/options.js | 2 +- services/source_id.js | 2 +- services/sql.js | 32 +++++++-------- services/sync.js | 14 +++---- services/sync_table.js | 4 +- services/sync_update.js | 10 ++--- views/index.ejs | 2 +- 27 files changed, 139 insertions(+), 85 deletions(-) diff --git a/migrations/0031__change_encryption_to_CBC.js b/migrations/0031__change_encryption_to_CBC.js index ac79e3215..a891f1576 100644 --- a/migrations/0031__change_encryption_to_CBC.js +++ b/migrations/0031__change_encryption_to_CBC.js @@ -17,7 +17,7 @@ module.exports = async () => { const password = await question("Enter password: "); const dataKey = await password_encryption.getDecryptedDataKey(password); - const protectedNotes = await sql.getResults("SELECT * FROM notes WHERE is_protected = 1"); + const protectedNotes = await sql.getAll("SELECT * FROM notes WHERE is_protected = 1"); for (const note of protectedNotes) { const decryptedTitle = data_encryption.decrypt(dataKey, note.note_title); @@ -30,7 +30,7 @@ module.exports = async () => { await sql.execute("UPDATE notes SET note_title = ?, note_text = ? WHERE note_id = ?", [note.note_title, note.note_text, note.note_id]); } - const protectedNotesHistory = await sql.getResults("SELECT * FROM notes_history WHERE is_protected = 1"); + const protectedNotesHistory = await sql.getAll("SELECT * FROM notes_history WHERE is_protected = 1"); for (const noteHistory of protectedNotesHistory) { const decryptedTitle = data_encryption.decrypt(dataKey, noteHistory.note_title); diff --git a/public/javascripts/note_tree.js b/public/javascripts/note_tree.js index 7d4a63230..0746cac43 100644 --- a/public/javascripts/note_tree.js +++ b/public/javascripts/note_tree.js @@ -15,6 +15,8 @@ const noteTree = (function() { let noteIdToTitle = {}; function getNoteTreeId(parentNoteId, childNoteId) { + assertArguments(parentNoteId, childNoteId); + const key = parentNoteId + "-" + childNoteId; // this can return undefined and client code should deal with it somehow @@ -23,6 +25,8 @@ const noteTree = (function() { } function getNoteTitle(noteId, parentNoteId = null) { + assertArguments(noteId); + let title = noteIdToTitle[noteId]; if (!title) { @@ -73,17 +77,23 @@ const noteTree = (function() { } function getNodesByNoteTreeId(noteTreeId) { + assertArguments(noteTreeId); + const noteTree = notesTreeMap[noteTreeId]; return getNodesByNoteId(noteTree.note_id).filter(node => node.data.note_tree_id === noteTreeId); } function getNodesByNoteId(noteId) { + assertArguments(noteId); + const list = getTree().getNodesByRef(noteId); return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null } function setPrefix(noteTreeId, prefix) { + assertArguments(noteTreeId); + notesTreeMap[noteTreeId].prefix = prefix; getNodesByNoteTreeId(noteTreeId).map(node => { @@ -94,6 +104,8 @@ const noteTree = (function() { } function removeParentChildRelation(parentNoteId, childNoteId) { + assertArguments(parentNoteId, childNoteId); + const key = parentNoteId + "-" + childNoteId; delete parentChildToNoteTreeId[key]; @@ -103,6 +115,8 @@ const noteTree = (function() { } function setParentChildRelation(noteTreeId, parentNoteId, childNoteId) { + assertArguments(noteTreeId, parentNoteId, childNoteId); + const key = parentNoteId + "-" + childNoteId; parentChildToNoteTreeId[key] = noteTreeId; @@ -121,6 +135,8 @@ const noteTree = (function() { } function prepareNoteTree(notes) { + assertArguments(notes); + parentToChildren = {}; childToParents = {}; notesTreeMap = {}; @@ -139,6 +155,8 @@ const noteTree = (function() { } function getExtraClasses(note) { + assertArguments(note); + let extraClasses = ''; if (note.is_protected) { @@ -157,6 +175,8 @@ const noteTree = (function() { } function prepareNoteTreeInner(parentNoteId) { + assertArguments(parentNoteId); + const childNoteIds = parentToChildren[parentNoteId]; if (!childNoteIds) { messaging.logError("No children for " + parentNoteId + ". This shouldn't happen."); @@ -199,6 +219,8 @@ const noteTree = (function() { } async function activateNode(notePath) { + assertArguments(notePath); + const runPath = getRunPath(notePath); const noteId = treeUtils.getNoteIdFromNotePath(notePath); @@ -225,6 +247,8 @@ const noteTree = (function() { * path change) or other corruption, in that case this will try to get some other valid path to the correct note. */ function getRunPath(notePath) { + assertArguments(notePath); + const path = notePath.split("/").reverse(); path.push('root'); @@ -251,6 +275,8 @@ const noteTree = (function() { console.log(now(), "Did not find parent " + parentNoteId + " for child " + childNoteId); if (parents.length > 0) { + console.log(now(), "Available parents:", parents); + const pathToRoot = getSomeNotePath(parents[0]).split("/").reverse(); for (const noteId of pathToRoot) { @@ -279,6 +305,8 @@ const noteTree = (function() { } function showParentList(noteId, node) { + assertArguments(noteId, node); + const parents = childToParents[noteId]; if (!parents) { @@ -313,6 +341,8 @@ const noteTree = (function() { } function getNotePathTitle(notePath) { + assertArguments(notePath); + const titlePath = []; let parentNoteId = 'root'; @@ -327,6 +357,8 @@ const noteTree = (function() { } function getSomeNotePath(noteId) { + assertArguments(noteId); + const path = []; let cur = noteId; @@ -345,12 +377,16 @@ const noteTree = (function() { } async function setExpandedToServer(noteTreeId, isExpanded) { + assertArguments(noteTreeId); + const expandedNum = isExpanded ? 1 : 0; await server.put('notes/' + noteTreeId + '/expanded/' + expandedNum); } function setCurrentNotePathToHash(node) { + assertArguments(node); + const currentNotePath = treeUtils.getNotePath(node); const currentNoteTreeId = node.data.note_tree_id; @@ -360,6 +396,8 @@ const noteTree = (function() { } function initFancyTree(noteTree) { + assertArguments(noteTree); + const keybindings = { "del": node => { treeChanges.deleteNode(node); @@ -601,6 +639,8 @@ const noteTree = (function() { } function setNoteTitle(noteId, title) { + assertArguments(noteId); + noteIdToTitle[noteId] = title; getNodesByNoteId(noteId).map(clone => treeUtils.setNodeTitleWithPrefix(clone)); @@ -613,6 +653,8 @@ const noteTree = (function() { } async function createNote(node, parentNoteId, target, isProtected) { + assertArguments(node, parentNoteId, target); + // if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted // but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often if (!isProtected || !protected_session.isProtectedSessionAvailable()) { diff --git a/public/javascripts/utils.js b/public/javascripts/utils.js index 3c17a4269..384c5999f 100644 --- a/public/javascripts/utils.js +++ b/public/javascripts/utils.js @@ -71,4 +71,16 @@ function now() { function isElectron() { return window && window.process && window.process.type; +} + +function assertArguments() { + for (const i in arguments) { + assert(arguments[i], `argument ${i} should not be falsy. Argument list: ${arguments}`); + } +} + +function assert(expr, message) { + if (!expr) { + throwError(message); + } } \ No newline at end of file diff --git a/routes/api/cleanup.js b/routes/api/cleanup.js index 236e80e5c..8acc75c54 100644 --- a/routes/api/cleanup.js +++ b/routes/api/cleanup.js @@ -9,7 +9,7 @@ const auth = require('../../services/auth'); router.post('/cleanup-soft-deleted-items', auth.checkApiAuth, async (req, res, next) => { await sql.doInTransaction(async () => { - const noteIdsToDelete = await sql.getFlattenedResults("SELECT note_id FROM notes WHERE is_deleted = 1"); + const noteIdsToDelete = await sql.getFirstColumn("SELECT note_id FROM notes WHERE is_deleted = 1"); const noteIdsSql = noteIdsToDelete .map(noteId => "'" + utils.sanitizeSql(noteId) + "'") .join(', '); diff --git a/routes/api/event_log.js b/routes/api/event_log.js index a7560542b..037be7460 100644 --- a/routes/api/event_log.js +++ b/routes/api/event_log.js @@ -8,13 +8,13 @@ const auth = require('../../services/auth'); router.get('', auth.checkApiAuth, async (req, res, next) => { await deleteOld(); - const result = await sql.getResults("SELECT * FROM event_log ORDER BY date_added DESC"); + const result = await sql.getAll("SELECT * FROM event_log ORDER BY date_added DESC"); res.send(result); }); async function deleteOld() { - const cutoffId = await sql.getSingleValue("SELECT id FROM event_log ORDER BY id DESC LIMIT 1000, 1"); + const cutoffId = await sql.getFirstValue("SELECT id FROM event_log ORDER BY id DESC LIMIT 1000, 1"); if (cutoffId) { await sql.doInTransaction(async () => { diff --git a/routes/api/export.js b/routes/api/export.js index 28f453950..d5c7b46f8 100644 --- a/routes/api/export.js +++ b/routes/api/export.js @@ -25,7 +25,7 @@ router.get('/:noteId/to/:directory', auth.checkApiAuth, async (req, res, next) = fs.mkdirSync(completeExportDir); - const noteTreeId = await sql.getSingleValue('SELECT note_tree_id FROM notes_tree WHERE note_id = ?', [noteId]); + const noteTreeId = await sql.getFirstValue('SELECT note_tree_id FROM notes_tree WHERE note_id = ?', [noteId]); await exportNote(noteTreeId, completeExportDir); @@ -33,14 +33,14 @@ router.get('/:noteId/to/:directory', auth.checkApiAuth, async (req, res, next) = }); async function exportNote(noteTreeId, dir) { - const noteTree = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [noteTreeId]); - const note = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteTree.note_id]); + const noteTree = await sql.getFirst("SELECT * FROM notes_tree WHERE note_tree_id = ?", [noteTreeId]); + const note = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteTree.note_id]); const pos = (noteTree.note_position + '').padStart(4, '0'); fs.writeFileSync(dir + '/' + pos + '-' + note.note_title + '.html', html.prettyPrint(note.note_text, {indent_size: 2})); - const children = await sql.getResults("SELECT * FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0", [note.note_id]); + const children = await sql.getAll("SELECT * FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0", [note.note_id]); if (children.length > 0) { const childrenDir = dir + '/' + pos + '-' + note.note_title; diff --git a/routes/api/import.js b/routes/api/import.js index 83dd81f5e..9b6a92767 100644 --- a/routes/api/import.js +++ b/routes/api/import.js @@ -21,7 +21,7 @@ router.get('/:directory/to/:parentNoteId', auth.checkApiAuth, async (req, res, n }); async function importNotes(dir, parentNoteId) { - const parent = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [parentNoteId]); + const parent = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [parentNoteId]); if (!parent) { return; @@ -51,7 +51,7 @@ async function importNotes(dir, parentNoteId) { noteTitle = match[2]; } else { - let maxPos = await sql.getSingleValue("SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0", [parentNoteId]); + let maxPos = await sql.getFirstValue("SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0", [parentNoteId]); if (maxPos) { notePos = maxPos + 1; } diff --git a/routes/api/note_history.js b/routes/api/note_history.js index c39b83d43..49a006d2b 100644 --- a/routes/api/note_history.js +++ b/routes/api/note_history.js @@ -10,7 +10,7 @@ const sync_table = require('../../services/sync_table'); router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { const noteId = req.params.noteId; - const history = await sql.getResults("SELECT * FROM notes_history WHERE note_id = ? order by date_modified_to desc", [noteId]); + const history = await sql.getAll("SELECT * FROM notes_history WHERE note_id = ? order by date_modified_to desc", [noteId]); const dataKey = protected_session.getDataKey(req); diff --git a/routes/api/notes.js b/routes/api/notes.js index 836934410..1c4ce2fd8 100644 --- a/routes/api/notes.js +++ b/routes/api/notes.js @@ -12,7 +12,7 @@ const data_encryption = require('../../services/data_encryption'); router.get('/:noteId', auth.checkApiAuth, async (req, res, next) => { const noteId = req.params.noteId; - const detail = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteId]); + const detail = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteId]); if (!detail) { log.info("Note " + noteId + " has not been found."); @@ -67,7 +67,7 @@ router.delete('/:noteTreeId', auth.checkApiAuth, async (req, res, next) => { router.get('/', auth.checkApiAuth, async (req, res, next) => { const search = '%' + req.query.search + '%'; - const result = await sql.getResults("SELECT note_id FROM notes WHERE note_title liKE ? OR note_text LIKE ?", [search, search]); + const result = await sql.getAll("SELECT note_id FROM notes WHERE note_title liKE ? OR note_text LIKE ?", [search, search]); const noteIdList = []; diff --git a/routes/api/notes_move.js b/routes/api/notes_move.js index 0c4e5ea23..02f8d17f3 100644 --- a/routes/api/notes_move.js +++ b/routes/api/notes_move.js @@ -12,7 +12,7 @@ router.put('/:noteTreeId/move-to/:parentNoteId', auth.checkApiAuth, async (req, const parentNoteId = req.params.parentNoteId; const sourceId = req.headers.source_id; - const maxNotePos = await sql.getSingleValue('SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0', [parentNoteId]); + const maxNotePos = await sql.getFirstValue('SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0', [parentNoteId]); const newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; const now = utils.nowDate(); @@ -32,7 +32,7 @@ router.put('/:noteTreeId/move-before/:beforeNoteTreeId', auth.checkApiAuth, asyn const beforeNoteTreeId = req.params.beforeNoteTreeId; const sourceId = req.headers.source_id; - const beforeNote = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [beforeNoteTreeId]); + const beforeNote = await sql.getFirst("SELECT * FROM notes_tree WHERE note_tree_id = ?", [beforeNoteTreeId]); if (beforeNote) { await sql.doInTransaction(async () => { @@ -63,7 +63,7 @@ router.put('/:noteTreeId/move-after/:afterNoteTreeId', auth.checkApiAuth, async const afterNoteTreeId = req.params.afterNoteTreeId; const sourceId = req.headers.source_id; - const afterNote = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]); + const afterNote = await sql.getFirst("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]); if (afterNote) { await sql.doInTransaction(async () => { @@ -93,7 +93,7 @@ router.put('/:childNoteId/clone-to/:parentNoteId', auth.checkApiAuth, async (req const prefix = req.body.prefix; const sourceId = req.headers.source_id; - const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND parent_note_id = ?', [childNoteId, parentNoteId]); + const existing = await sql.getFirstValue('SELECT * FROM notes_tree WHERE note_id = ? AND parent_note_id = ?', [childNoteId, parentNoteId]); if (existing && !existing.is_deleted) { return res.send({ @@ -109,7 +109,7 @@ router.put('/:childNoteId/clone-to/:parentNoteId', auth.checkApiAuth, async (req }); } - const maxNotePos = await sql.getSingleValue('SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0', [parentNoteId]); + const maxNotePos = await sql.getFirstValue('SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0', [parentNoteId]); const newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; await sql.doInTransaction(async () => { @@ -141,7 +141,7 @@ router.put('/:noteId/clone-after/:afterNoteTreeId', auth.checkApiAuth, async (re const afterNoteTreeId = req.params.afterNoteTreeId; const sourceId = req.headers.source_id; - const afterNote = await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]); + const afterNote = await sql.getFirst("SELECT * FROM notes_tree WHERE note_tree_id = ?", [afterNoteTreeId]); if (!afterNote) { return res.status(500).send("After note " + afterNoteTreeId + " doesn't exist."); @@ -154,7 +154,7 @@ router.put('/:noteId/clone-after/:afterNoteTreeId', auth.checkApiAuth, async (re }); } - const existing = await sql.getSingleValue('SELECT * FROM notes_tree WHERE note_id = ? AND parent_note_id = ?', [noteId, afterNote.parent_note_id]); + const existing = await sql.getFirstValue('SELECT * FROM notes_tree WHERE note_id = ? AND parent_note_id = ?', [noteId, afterNote.parent_note_id]); if (existing && !existing.is_deleted) { return res.send({ @@ -200,7 +200,7 @@ async function checkCycle(parentNoteId, childNoteId) { return false; } - const parentNoteIds = await sql.getFlattenedResults("SELECT DISTINCT parent_note_id FROM notes_tree WHERE note_id = ?", [parentNoteId]); + const parentNoteIds = await sql.getFirstColumn("SELECT DISTINCT parent_note_id FROM notes_tree WHERE note_id = ?", [parentNoteId]); for (const pid of parentNoteIds) { if (!await checkCycle(pid, childNoteId)) { diff --git a/routes/api/recent_changes.js b/routes/api/recent_changes.js index 873587700..d1069d2ce 100644 --- a/routes/api/recent_changes.js +++ b/routes/api/recent_changes.js @@ -6,7 +6,7 @@ const sql = require('../../services/sql'); const auth = require('../../services/auth'); router.get('/', auth.checkApiAuth, async (req, res, next) => { - const recentChanges = await sql.getResults( + const recentChanges = await sql.getAll( `SELECT notes.is_deleted AS current_is_deleted, notes.note_title AS current_note_title, diff --git a/routes/api/recent_notes.js b/routes/api/recent_notes.js index cbf50cf5d..4cf4003d6 100644 --- a/routes/api/recent_notes.js +++ b/routes/api/recent_notes.js @@ -34,7 +34,7 @@ router.put('/:noteTreeId/:notePath', auth.checkApiAuth, async (req, res, next) = }); async function getRecentNotes() { - return await sql.getResults(` + return await sql.getAll(` SELECT recent_notes.* FROM diff --git a/routes/api/sql.js b/routes/api/sql.js index 9aab0a140..38ce81171 100644 --- a/routes/api/sql.js +++ b/routes/api/sql.js @@ -11,7 +11,7 @@ router.post('/execute', auth.checkApiAuth, async (req, res, next) => { try { res.send({ success: true, - rows: await sql.getResults(query) + rows: await sql.getAll(query) }); } catch (e) { diff --git a/routes/api/sync.js b/routes/api/sync.js index 86a16a561..51ae446e3 100644 --- a/routes/api/sync.js +++ b/routes/api/sync.js @@ -13,7 +13,7 @@ const content_hash = require('../../services/content_hash'); router.get('/check', auth.checkApiAuth, async (req, res, next) => { res.send({ 'hashes': await content_hash.getHashes(), - 'max_sync_id': await sql.getSingleValue('SELECT MAX(id) FROM sync') + 'max_sync_id': await sql.getFirstValue('SELECT MAX(id) FROM sync') }); }); @@ -47,27 +47,27 @@ router.post('/force-full-sync', auth.checkApiAuth, async (req, res, next) => { router.get('/changed', auth.checkApiAuth, async (req, res, next) => { const lastSyncId = parseInt(req.query.lastSyncId); - res.send(await sql.getResults("SELECT * FROM sync WHERE id > ?", [lastSyncId])); + res.send(await sql.getAll("SELECT * FROM sync WHERE id > ?", [lastSyncId])); }); router.get('/notes/:noteId', auth.checkApiAuth, async (req, res, next) => { const noteId = req.params.noteId; res.send({ - entity: await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteId]) + entity: await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteId]) }); }); router.get('/notes_tree/:noteTreeId', auth.checkApiAuth, async (req, res, next) => { const noteTreeId = req.params.noteTreeId; - res.send(await sql.getSingleResult("SELECT * FROM notes_tree WHERE note_tree_id = ?", [noteTreeId])); + res.send(await sql.getFirst("SELECT * FROM notes_tree WHERE note_tree_id = ?", [noteTreeId])); }); router.get('/notes_history/:noteHistoryId', auth.checkApiAuth, async (req, res, next) => { const noteHistoryId = req.params.noteHistoryId; - res.send(await sql.getSingleResult("SELECT * FROM notes_history WHERE note_history_id = ?", [noteHistoryId])); + res.send(await sql.getFirst("SELECT * FROM notes_history WHERE note_history_id = ?", [noteHistoryId])); }); router.get('/options/:optName', auth.checkApiAuth, async (req, res, next) => { @@ -77,7 +77,7 @@ router.get('/options/:optName', auth.checkApiAuth, async (req, res, next) => { res.send("This option can't be synced."); } else { - res.send(await sql.getSingleResult("SELECT * FROM options WHERE opt_name = ?", [optName])); + res.send(await sql.getFirst("SELECT * FROM options WHERE opt_name = ?", [optName])); } }); @@ -93,7 +93,7 @@ router.get('/notes_reordering/:noteTreeParentId', auth.checkApiAuth, async (req, router.get('/recent_notes/:noteTreeId', auth.checkApiAuth, async (req, res, next) => { const noteTreeId = req.params.noteTreeId; - res.send(await sql.getSingleResult("SELECT * FROM recent_notes WHERE note_tree_id = ?", [noteTreeId])); + res.send(await sql.getFirst("SELECT * FROM recent_notes WHERE note_tree_id = ?", [noteTreeId])); }); router.put('/notes', auth.checkApiAuth, async (req, res, next) => { diff --git a/routes/api/tree.js b/routes/api/tree.js index ddef3ff09..fc1fd54ae 100644 --- a/routes/api/tree.js +++ b/routes/api/tree.js @@ -12,7 +12,7 @@ const notes = require('../../services/notes'); const sync_table = require('../../services/sync_table'); router.get('/', auth.checkApiAuth, async (req, res, next) => { - const notes = await sql.getResults("SELECT " + const notes = await sql.getAll("SELECT " + "notes_tree.*, " + "notes.note_title, " + "notes.is_protected " diff --git a/routes/index.js b/routes/index.js index a420ffc4b..efe70b318 100644 --- a/routes/index.js +++ b/routes/index.js @@ -9,7 +9,7 @@ const sql = require('../services/sql'); router.get('', auth.checkAuth, async (req, res, next) => { res.render('index', { sourceId: await source_id.generateSourceId(), - maxSyncIdAtLoad: await sql.getSingleValue("SELECT MAX(id) FROM sync") + maxSyncIdAtLoad: await sql.getFirstValue("SELECT MAX(id) FROM sync") }); }); diff --git a/services/consistency_checks.js b/services/consistency_checks.js index 063bb36ab..2f72d5d95 100644 --- a/services/consistency_checks.js +++ b/services/consistency_checks.js @@ -5,7 +5,7 @@ const log = require('./log'); const messaging = require('./messaging'); async function runCheck(query, errorText, errorList) { - const result = await sql.getFlattenedResults(query); + const result = await sql.getFirstColumn(query); if (result.length > 0) { const err = errorText + ": " + result; diff --git a/services/content_hash.js b/services/content_hash.js index 3c15099c6..35829ae46 100644 --- a/services/content_hash.js +++ b/services/content_hash.js @@ -16,7 +16,7 @@ async function getHashes() { const optionsQuestionMarks = Array(options.SYNCED_OPTIONS.length).fill('?').join(','); return { - notes: getHash(await sql.getResults(`SELECT + notes: getHash(await sql.getAll(`SELECT note_id, note_title, note_text, @@ -26,7 +26,7 @@ async function getHashes() { FROM notes ORDER BY note_id`)), - notes_tree: getHash(await sql.getResults(`SELECT + notes_tree: getHash(await sql.getAll(`SELECT note_tree_id, note_id, parent_note_id, @@ -37,7 +37,7 @@ async function getHashes() { FROM notes_tree ORDER BY note_tree_id`)), - notes_history: getHash(await sql.getResults(`SELECT + notes_history: getHash(await sql.getAll(`SELECT note_history_id, note_id, note_title, @@ -47,7 +47,7 @@ async function getHashes() { FROM notes_history ORDER BY note_history_id`)), - recent_notes: getHash(await sql.getResults(`SELECT + recent_notes: getHash(await sql.getAll(`SELECT note_tree_id, note_path, date_accessed, @@ -55,7 +55,7 @@ async function getHashes() { FROM recent_notes ORDER BY note_path`)), - options: getHash(await sql.getResults(`SELECT + options: getHash(await sql.getAll(`SELECT opt_name, opt_value FROM options diff --git a/services/messaging.js b/services/messaging.js index 5773070a3..3f56607d9 100644 --- a/services/messaging.js +++ b/services/messaging.js @@ -62,11 +62,11 @@ async function sendMessageToAllClients(message) { } async function sendPing(client, lastSentSyncId) { - const syncData = await sql.getResults("SELECT * FROM sync WHERE id > ?", [lastSentSyncId]); + const syncData = await sql.getAll("SELECT * FROM sync WHERE id > ?", [lastSentSyncId]); const lastSyncedPush = await options.getOption('last_synced_push'); - const changesToPushCount = await sql.getSingleValue("SELECT COUNT(*) FROM sync WHERE id > ?", [lastSyncedPush]); + const changesToPushCount = await sql.getFirstValue("SELECT COUNT(*) FROM sync WHERE id > ?", [lastSyncedPush]); await sendMessage(client, { type: 'sync', diff --git a/services/notes.js b/services/notes.js index 88c0f3315..b49f5078b 100644 --- a/services/notes.js +++ b/services/notes.js @@ -13,12 +13,12 @@ async function createNewNote(parentNoteId, note, sourceId) { await sql.doInTransaction(async () => { if (note.target === 'into') { - const maxNotePos = await sql.getSingleValue('SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0', [parentNoteId]); + const maxNotePos = await sql.getFirstValue('SELECT MAX(note_position) FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0', [parentNoteId]); newNotePos = maxNotePos === null ? 0 : maxNotePos + 1; } else if (note.target === 'after') { - const afterNote = await sql.getSingleResult('SELECT note_position FROM notes_tree WHERE note_tree_id = ?', [note.target_note_tree_id]); + const afterNote = await sql.getFirst('SELECT note_position FROM notes_tree WHERE note_tree_id = ?', [note.target_note_tree_id]); newNotePos = afterNote.note_position + 1; @@ -70,11 +70,11 @@ async function encryptNote(note, dataKey) { } async function protectNoteRecursively(noteId, dataKey, protect, sourceId) { - const note = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteId]); + const note = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteId]); await protectNote(note, dataKey, protect, sourceId); - const children = await sql.getFlattenedResults("SELECT note_id FROM notes_tree WHERE parent_note_id = ?", [noteId]); + const children = await sql.getFirstColumn("SELECT note_id FROM notes_tree WHERE parent_note_id = ?", [noteId]); for (const childNoteId of children) { await protectNoteRecursively(childNoteId, dataKey, protect, sourceId); @@ -116,7 +116,7 @@ async function protectNote(note, dataKey, protect, sourceId) { } async function protectNoteHistory(noteId, dataKey, protect, sourceId) { - const historyToChange = await sql.getResults("SELECT * FROM notes_history WHERE note_id = ? AND is_protected != ?", [noteId, protect]); + const historyToChange = await sql.getAll("SELECT * FROM notes_history WHERE note_id = ? AND is_protected != ?", [noteId, protect]); for (const history of historyToChange) { if (protect) { @@ -149,14 +149,14 @@ async function updateNote(noteId, newNote, dataKey, sourceId) { const historyCutoff = utils.dateStr(new Date(now.getTime() - historySnapshotTimeInterval * 1000)); - const existingNoteHistoryId = await sql.getSingleValue( + const existingNoteHistoryId = await sql.getFirstValue( "SELECT note_history_id FROM notes_history WHERE note_id = ? AND date_modified_to >= ?", [noteId, historyCutoff]); await sql.doInTransaction(async () => { const msSinceDateCreated = now.getTime() - utils.parseDate(newNote.detail.date_created).getTime(); if (!existingNoteHistoryId && msSinceDateCreated >= historySnapshotTimeInterval * 1000) { - const oldNote = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [noteId]); + const oldNote = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [noteId]); if (oldNote.is_protected) { decryptNote(oldNote, dataKey); @@ -197,15 +197,15 @@ async function deleteNote(noteTreeId, sourceId) { await sql.execute("UPDATE notes_tree SET is_deleted = 1, date_modified = ? WHERE note_tree_id = ?", [now, noteTreeId]); await sync_table.addNoteTreeSync(noteTreeId, sourceId); - const noteId = await sql.getSingleValue("SELECT note_id FROM notes_tree WHERE note_tree_id = ?", [noteTreeId]); + const noteId = await sql.getFirstValue("SELECT note_id FROM notes_tree WHERE note_tree_id = ?", [noteTreeId]); - const notDeletedNoteTreesCount = await sql.getSingleValue("SELECT COUNT(*) FROM notes_tree WHERE note_id = ? AND is_deleted = 0", [noteId]); + const notDeletedNoteTreesCount = await sql.getFirstValue("SELECT COUNT(*) FROM notes_tree WHERE note_id = ? AND is_deleted = 0", [noteId]); if (!notDeletedNoteTreesCount) { await sql.execute("UPDATE notes SET is_deleted = 1, date_modified = ? WHERE note_id = ?", [now, noteId]); await sync_table.addNoteSync(noteId, sourceId); - const children = await sql.getResults("SELECT note_tree_id FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0", [noteId]); + const children = await sql.getAll("SELECT note_tree_id FROM notes_tree WHERE parent_note_id = ? AND is_deleted = 0", [noteId]); for (const child of children) { await deleteNote(child.note_tree_id, sourceId); diff --git a/services/options.js b/services/options.js index 5bacbcdee..7355aeeb4 100644 --- a/services/options.js +++ b/services/options.js @@ -7,7 +7,7 @@ const SYNCED_OPTIONS = [ 'username', 'password_verification_hash', 'encrypted_da 'history_snapshot_time_interval' ]; async function getOption(optName) { - const row = await sql.getSingleResultOrNull("SELECT opt_value FROM options WHERE opt_name = ?", [optName]); + const row = await sql.getFirstOrNull("SELECT opt_value FROM options WHERE opt_name = ?", [optName]); if (!row) { throw new Error("Option " + optName + " doesn't exist"); diff --git a/services/source_id.js b/services/source_id.js index 07c2a3410..6cb8712f7 100644 --- a/services/source_id.js +++ b/services/source_id.js @@ -20,7 +20,7 @@ async function generateSourceId() { } async function refreshSourceIds() { - allSourceIds = await sql.getFlattenedResults("SELECT source_id FROM source_ids ORDER BY date_created DESC"); + allSourceIds = await sql.getFirstColumn("SELECT source_id FROM source_ids ORDER BY date_created DESC"); } let allSourceIds = []; diff --git a/services/sql.js b/services/sql.js index 03686a0dd..ff930cac7 100644 --- a/services/sql.js +++ b/services/sql.js @@ -24,7 +24,7 @@ const dbReady = new Promise((resolve, reject) => { resolve(db); }; - const tableResults = await getResults("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'"); + const tableResults = await getAll("SELECT name FROM sqlite_master WHERE type='table' AND name='notes'"); if (tableResults.length !== 1) { log.info("Connected to db, but schema doesn't exist. Initializing schema ..."); @@ -62,7 +62,7 @@ const dbReady = new Promise((resolve, reject) => { // the database } else { - const username = await getSingleValue("SELECT opt_value FROM options WHERE opt_name = 'username'"); + const username = await getFirstValue("SELECT opt_value FROM options WHERE opt_name = 'username'"); if (!username) { log.info("Login/password not initialized. DB not ready."); @@ -120,18 +120,18 @@ async function rollback() { return await wrap(async db => db.run("ROLLBACK")); } -async function getSingleResult(query, params = []) { +async function getFirst(query, params = []) { return await wrap(async db => db.get(query, ...params)); } -async function getSingleResultOrNull(query, params = []) { +async function getFirstOrNull(query, params = []) { const all = await wrap(async db => db.all(query, ...params)); return all.length > 0 ? all[0] : null; } -async function getSingleValue(query, params = []) { - const row = await getSingleResultOrNull(query, params); +async function getFirstValue(query, params = []) { + const row = await getFirstOrNull(query, params); if (!row) { return null; @@ -140,13 +140,13 @@ async function getSingleValue(query, params = []) { return row[Object.keys(row)[0]]; } -async function getResults(query, params = []) { +async function getAll(query, params = []) { return await wrap(async db => db.all(query, ...params)); } async function getMap(query, params = []) { const map = {}; - const results = await getResults(query, params); + const results = await getAll(query, params); for (const row of results) { const keys = Object.keys(row); @@ -157,9 +157,9 @@ async function getMap(query, params = []) { return map; } -async function getFlattenedResults(query, params = []) { +async function getFirstColumn(query, params = []) { const list = []; - const result = await getResults(query, params); + const result = await getAll(query, params); if (result.length === 0) { return list; @@ -237,7 +237,7 @@ async function doInTransaction(func) { } async function isDbUpToDate() { - const dbVersion = parseInt(await getSingleValue("SELECT opt_value FROM options WHERE opt_name = 'db_version'")); + const dbVersion = parseInt(await getFirstValue("SELECT opt_value FROM options WHERE opt_name = 'db_version'")); const upToDate = dbVersion >= app_info.db_version; @@ -252,12 +252,12 @@ module.exports = { dbReady, insert, replace, - getSingleValue, - getSingleResult, - getSingleResultOrNull, - getResults, + getFirstValue, + getFirst, + getFirstOrNull, + getAll, getMap, - getFlattenedResults, + getFirstColumn, execute, executeScript, doInTransaction, diff --git a/services/sync.js b/services/sync.js index 08eb1026a..479c17606 100644 --- a/services/sync.js +++ b/services/sync.js @@ -176,7 +176,7 @@ async function pushSync(syncContext) { let lastSyncedPush = await getLastSyncedPush(); while (true) { - const sync = await sql.getSingleResultOrNull('SELECT * FROM sync WHERE id > ? LIMIT 1', [lastSyncedPush]); + const sync = await sql.getFirstOrNull('SELECT * FROM sync WHERE id > ? LIMIT 1', [lastSyncedPush]); if (sync === null) { // nothing to sync @@ -203,13 +203,13 @@ async function pushEntity(sync, syncContext) { let entity; if (sync.entity_name === 'notes') { - entity = await sql.getSingleResult('SELECT * FROM notes WHERE note_id = ?', [sync.entity_id]); + entity = await sql.getFirst('SELECT * FROM notes WHERE note_id = ?', [sync.entity_id]); } else if (sync.entity_name === 'notes_tree') { - entity = await sql.getSingleResult('SELECT * FROM notes_tree WHERE note_tree_id = ?', [sync.entity_id]); + entity = await sql.getFirst('SELECT * FROM notes_tree WHERE note_tree_id = ?', [sync.entity_id]); } else if (sync.entity_name === 'notes_history') { - entity = await sql.getSingleResult('SELECT * FROM notes_history WHERE note_history_id = ?', [sync.entity_id]); + entity = await sql.getFirst('SELECT * FROM notes_history WHERE note_history_id = ?', [sync.entity_id]); } else if (sync.entity_name === 'notes_reordering') { entity = { @@ -218,10 +218,10 @@ async function pushEntity(sync, syncContext) { }; } else if (sync.entity_name === 'options') { - entity = await sql.getSingleResult('SELECT * FROM options WHERE opt_name = ?', [sync.entity_id]); + entity = await sql.getFirst('SELECT * FROM options WHERE opt_name = ?', [sync.entity_id]); } else if (sync.entity_name === 'recent_notes') { - entity = await sql.getSingleResult('SELECT * FROM recent_notes WHERE note_tree_id = ?', [sync.entity_id]); + entity = await sql.getFirst('SELECT * FROM recent_notes WHERE note_tree_id = ?', [sync.entity_id]); } else { throw new Error(`Unrecognized entity type ${sync.entity_name} in sync #${sync.id}`); @@ -252,7 +252,7 @@ async function checkContentHash(syncContext) { } const lastSyncedPush = await getLastSyncedPush(); - const notPushedSyncs = await sql.getSingleValue("SELECT COUNT(*) FROM sync WHERE id > ?", [lastSyncedPush]); + const notPushedSyncs = await sql.getFirstValue("SELECT COUNT(*) FROM sync WHERE id > ?", [lastSyncedPush]); if (notPushedSyncs > 0) { log.info("There's " + notPushedSyncs + " outstanding pushes, skipping content check."); diff --git a/services/sync_table.js b/services/sync_table.js index be95a8e11..95fb26dd3 100644 --- a/services/sync_table.js +++ b/services/sync_table.js @@ -54,10 +54,10 @@ async function cleanupSyncRowsForMissingEntities(entityName, entityKey) { async function fillSyncRows(entityName, entityKey) { await cleanupSyncRowsForMissingEntities(entityName, entityKey); - const entityIds = await sql.getFlattenedResults(`SELECT ${entityKey} FROM ${entityName}`); + const entityIds = await sql.getFirstColumn(`SELECT ${entityKey} FROM ${entityName}`); for (const entityId of entityIds) { - const existingRows = await sql.getSingleValue("SELECT COUNT(id) FROM sync WHERE entity_name = ? AND entity_id = ?", [entityName, entityId]); + const existingRows = await sql.getFirstValue("SELECT COUNT(id) FROM sync WHERE entity_name = ? AND entity_id = ?", [entityName, entityId]); // we don't want to replace existing entities (which would effectively cause full resync) if (existingRows === 0) { diff --git a/services/sync_update.js b/services/sync_update.js index 3306cd87a..2201564ac 100644 --- a/services/sync_update.js +++ b/services/sync_update.js @@ -6,7 +6,7 @@ const notes = require('./notes'); const sync_table = require('./sync_table'); async function updateNote(entity, sourceId) { - const origNote = await sql.getSingleResult("SELECT * FROM notes WHERE note_id = ?", [entity.note_id]); + const origNote = await sql.getFirst("SELECT * FROM notes WHERE note_id = ?", [entity.note_id]); if (!origNote || origNote.date_modified <= entity.date_modified) { await sql.doInTransaction(async () => { @@ -21,7 +21,7 @@ async function updateNote(entity, sourceId) { } async function updateNoteTree(entity, sourceId) { - const orig = await sql.getSingleResultOrNull("SELECT * FROM notes_tree WHERE note_tree_id = ?", [entity.note_tree_id]); + const orig = await sql.getFirstOrNull("SELECT * FROM notes_tree WHERE note_tree_id = ?", [entity.note_tree_id]); await sql.doInTransaction(async () => { if (orig === null || orig.date_modified < entity.date_modified) { @@ -37,7 +37,7 @@ async function updateNoteTree(entity, sourceId) { } async function updateNoteHistory(entity, sourceId) { - const orig = await sql.getSingleResultOrNull("SELECT * FROM notes_history WHERE note_history_id = ?", [entity.note_history_id]); + const orig = await sql.getFirstOrNull("SELECT * FROM notes_history WHERE note_history_id = ?", [entity.note_history_id]); await sql.doInTransaction(async () => { if (orig === null || orig.date_modified_to < entity.date_modified_to) { @@ -65,7 +65,7 @@ async function updateOptions(entity, sourceId) { return; } - const orig = await sql.getSingleResultOrNull("SELECT * FROM options WHERE opt_name = ?", [entity.opt_name]); + const orig = await sql.getFirstOrNull("SELECT * FROM options WHERE opt_name = ?", [entity.opt_name]); await sql.doInTransaction(async () => { if (orig === null || orig.date_modified < entity.date_modified) { @@ -79,7 +79,7 @@ async function updateOptions(entity, sourceId) { } async function updateRecentNotes(entity, sourceId) { - const orig = await sql.getSingleResultOrNull("SELECT * FROM recent_notes WHERE note_tree_id = ?", [entity.note_tree_id]); + const orig = await sql.getFirstOrNull("SELECT * FROM recent_notes WHERE note_tree_id = ?", [entity.note_tree_id]); if (orig === null || orig.date_accessed < entity.date_accessed) { await sql.doInTransaction(async () => { diff --git a/views/index.ejs b/views/index.ejs index 1af957a74..3158e4f96 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -249,7 +249,7 @@

Cleanup

- + (should be executed in all synced instances)