From d35613f5106d3010894d26732b54fc954c633f69 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sat, 17 Feb 2024 20:45:31 +0200 Subject: [PATCH] server-ts: Port becca_loader --- .../0220__migrate_images_to_attachments.js | 2 +- src/app.js | 2 +- .../{becca_loader.js => becca_loader.ts} | 81 ++++++++++--------- src/becca/entities/battribute.ts | 4 +- src/becca/entities/bbranch.ts | 2 +- src/becca/entities/betapi_token.ts | 2 +- src/becca/entities/bnote.ts | 4 +- src/becca/entities/boption.ts | 6 +- src/routes/api/import.js | 2 +- src/services/consistency_checks.js | 2 +- src/services/sql.ts | 6 +- src/services/sql_init.ts | 2 +- src/services/sync.js | 2 +- 13 files changed, 61 insertions(+), 56 deletions(-) rename src/becca/{becca_loader.js => becca_loader.ts} (76%) diff --git a/db/migrations/0220__migrate_images_to_attachments.js b/db/migrations/0220__migrate_images_to_attachments.js index e949626ef..7c1076f64 100644 --- a/db/migrations/0220__migrate_images_to_attachments.js +++ b/db/migrations/0220__migrate_images_to_attachments.js @@ -1,5 +1,5 @@ module.exports = () => { - const beccaLoader = require('../../src/becca/becca_loader.js'); + const beccaLoader = require('../../src/becca/becca_loader'); const becca = require('../../src/becca/becca.js'); const cls = require('../../src/services/cls'); const log = require('../../src/services/log'); diff --git a/src/app.js b/src/app.js index 5ef616538..c6afc27f8 100644 --- a/src/app.js +++ b/src/app.js @@ -8,7 +8,7 @@ const sessionParser = require('./routes/session_parser.js'); const utils = require('./services/utils'); require('./services/handlers.js'); -require('./becca/becca_loader.js'); +require('./becca/becca_loader'); const app = express(); diff --git a/src/becca/becca_loader.js b/src/becca/becca_loader.ts similarity index 76% rename from src/becca/becca_loader.js rename to src/becca/becca_loader.ts index f0f0ccccd..23ee9fdd3 100644 --- a/src/becca/becca_loader.js +++ b/src/becca/becca_loader.ts @@ -1,19 +1,20 @@ "use strict"; -const sql = require('../services/sql'); -const eventService = require('../services/events'); -const becca = require('./becca'); -const sqlInit = require('../services/sql_init'); -const log = require('../services/log'); -const BNote = require('./entities/bnote'); -const BBranch = require('./entities/bbranch'); -const BAttribute = require('./entities/battribute'); -const BOption = require('./entities/boption'); -const BEtapiToken = require('./entities/betapi_token'); -const cls = require('../services/cls'); -const entityConstructor = require('../becca/entity_constructor'); +import sql = require('../services/sql'); +import eventService = require('../services/events'); +import becca = require('./becca'); +import sqlInit = require('../services/sql_init'); +import log = require('../services/log'); +import BNote = require('./entities/bnote'); +import BBranch = require('./entities/bbranch'); +import BAttribute = require('./entities/battribute'); +import BOption = require('./entities/boption'); +import BEtapiToken = require('./entities/betapi_token'); +import cls = require('../services/cls'); +import entityConstructor = require('../becca/entity_constructor'); +import { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from './entities/rows'; -const beccaLoaded = new Promise((res, rej) => { +const beccaLoaded = new Promise((res, rej) => { sqlInit.dbReady.then(() => { cls.init(() => { load(); @@ -38,7 +39,7 @@ function load() { new BNote().update(row).init(); } - const branchRows = sql.getRawRows(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0`); + const branchRows = sql.getRawRows<{ notePosition: number}>(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified FROM branches WHERE isDeleted = 0`); // in-memory sort is faster than in the DB branchRows.sort((a, b) => a.notePosition - b.notePosition); @@ -46,15 +47,15 @@ function load() { new BBranch().update(row).init(); } - for (const row of sql.getRawRows(`SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0`)) { + for (const row of sql.getRawRows(`SELECT attributeId, noteId, type, name, value, isInheritable, position, utcDateModified FROM attributes WHERE isDeleted = 0`)) { new BAttribute().update(row).init(); } - for (const row of sql.getRows(`SELECT name, value, isSynced, utcDateModified FROM options`)) { + for (const row of sql.getRows(`SELECT name, value, isSynced, utcDateModified FROM options`)) { new BOption(row); } - for (const row of sql.getRows(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) { + for (const row of sql.getRows(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) { new BEtapiToken(row); } }); @@ -68,7 +69,7 @@ function load() { log.info(`Becca (note cache) load took ${Date.now() - start}ms`); } -function reload(reason) { +function reload(reason: string) { load(); require('../services/ws').reloadFrontend(reason || "becca reloaded"); @@ -112,7 +113,7 @@ eventService.subscribeBeccaLoader(eventService.ENTITY_CHANGED, ({entityName, en * @param entityRow - can be a becca entity (change comes from this trilium instance) or just a row (from sync). * It should be therefore treated as a row. */ -function postProcessEntityUpdate(entityName, entityRow) { +function postProcessEntityUpdate(entityName: string, entityRow: any) { if (entityName === 'notes') { noteUpdated(entityRow); } else if (entityName === 'branches') { @@ -140,13 +141,13 @@ eventService.subscribeBeccaLoader([eventService.ENTITY_DELETED, eventService.ENT } }); -function noteDeleted(noteId) { +function noteDeleted(noteId: string) { delete becca.notes[noteId]; becca.dirtyNoteSetCache(); } -function branchDeleted(branchId) { +function branchDeleted(branchId: string) { const branch = becca.branches[branchId]; if (!branch) { @@ -173,23 +174,26 @@ function branchDeleted(branchId) { } delete becca.childParentToBranch[`${branch.noteId}-${branch.parentNoteId}`]; - delete becca.branches[branch.branchId]; -} - -function noteUpdated(entityRow) { - const note = becca.notes[entityRow.noteId]; - - if (note) { - // type / mime could have been changed, and they are present in flatTextCache - note.flatTextCache = null; + if (branch.branchId) { + delete becca.branches[branch.branchId]; } } -function branchUpdated(branchRow) { +function noteUpdated(entityRow: NoteRow) { + const note = becca.notes[entityRow.noteId]; + + if (note) { + // FIXME, this wouldn't have worked in the original implementation since the variable was named __flatTextCache. + // type / mime could have been changed, and they are present in flatTextCache + note.__flatTextCache = null; + } +} + +function branchUpdated(branchRow: BranchRow) { const childNote = becca.notes[branchRow.noteId]; if (childNote) { - childNote.flatTextCache = null; + childNote.__flatTextCache = null; childNote.sortParents(); // notes in the subtree can get new inherited attributes @@ -204,7 +208,7 @@ function branchUpdated(branchRow) { } } -function attributeDeleted(attributeId) { +function attributeDeleted(attributeId: string) { const attribute = becca.attributes[attributeId]; if (!attribute) { @@ -239,8 +243,7 @@ function attributeDeleted(attributeId) { } } -/** @param {BAttribute} attributeRow */ -function attributeUpdated(attributeRow) { +function attributeUpdated(attributeRow: BAttribute) { const attribute = becca.attributes[attributeRow.attributeId]; const note = becca.notes[attributeRow.noteId]; @@ -253,7 +256,7 @@ function attributeUpdated(attributeRow) { } } -function noteReorderingUpdated(branchIdList) { +function noteReorderingUpdated(branchIdList: number[]) { const parentNoteIds = new Set(); for (const branchId in branchIdList) { @@ -267,7 +270,7 @@ function noteReorderingUpdated(branchIdList) { } } -function etapiTokenDeleted(etapiTokenId) { +function etapiTokenDeleted(etapiTokenId: string) { delete becca.etapiTokens[etapiTokenId]; } @@ -275,14 +278,14 @@ eventService.subscribeBeccaLoader(eventService.ENTER_PROTECTED_SESSION, () => { try { becca.decryptProtectedNotes(); } - catch (e) { + catch (e: any) { log.error(`Could not decrypt protected notes: ${e.message} ${e.stack}`); } }); eventService.subscribeBeccaLoader(eventService.LEAVE_PROTECTED_SESSION, load); -module.exports = { +export = { load, reload, beccaLoaded diff --git a/src/becca/entities/battribute.ts b/src/becca/entities/battribute.ts index c3d0115fc..b29d3e237 100644 --- a/src/becca/entities/battribute.ts +++ b/src/becca/entities/battribute.ts @@ -28,7 +28,7 @@ class BAttribute extends AbstractBeccaEntity { value!: string; isInheritable!: boolean; - constructor(row: AttributeRow) { + constructor(row?: AttributeRow) { super(); if (!row) { @@ -52,7 +52,7 @@ class BAttribute extends AbstractBeccaEntity { ]); } - update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]: any[]) { + update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]: any) { this.attributeId = attributeId; this.noteId = noteId; this.type = type; diff --git a/src/becca/entities/bbranch.ts b/src/becca/entities/bbranch.ts index bf64d2ac6..6b45a7e7a 100644 --- a/src/becca/entities/bbranch.ts +++ b/src/becca/entities/bbranch.ts @@ -30,7 +30,7 @@ class BBranch extends AbstractBeccaEntity { isExpanded!: boolean; utcDateModified?: string; - constructor(row: BranchRow) { + constructor(row?: BranchRow) { super(); if (!row) { diff --git a/src/becca/entities/betapi_token.ts b/src/becca/entities/betapi_token.ts index a2219f6de..390b580bd 100644 --- a/src/becca/entities/betapi_token.ts +++ b/src/becca/entities/betapi_token.ts @@ -24,7 +24,7 @@ class BEtapiToken extends AbstractBeccaEntity { tokenHash!: string; private _isDeleted?: boolean; - constructor(row: EtapiTokenRow) { + constructor(row?: EtapiTokenRow) { super(); if (!row) { diff --git a/src/becca/entities/bnote.ts b/src/becca/entities/bnote.ts index 26214e608..0a3fb87f1 100644 --- a/src/becca/entities/bnote.ts +++ b/src/becca/entities/bnote.ts @@ -70,7 +70,7 @@ class BNote extends AbstractBeccaEntity { children!: BNote[]; targetRelations!: BAttribute[]; - private __flatTextCache!: string | null; + __flatTextCache!: string | null; private __attributeCache!: BAttribute[] | null; private __inheritableAttributeCache!: BAttribute[] | null; @@ -86,7 +86,7 @@ class BNote extends AbstractBeccaEntity { /** number of note revisions for this note */ private revisionCount!: number | null; - constructor(row: Partial) { + constructor(row?: Partial) { super(); if (!row) { diff --git a/src/becca/entities/boption.ts b/src/becca/entities/boption.ts index afbf5320e..48abee024 100644 --- a/src/becca/entities/boption.ts +++ b/src/becca/entities/boption.ts @@ -16,10 +16,12 @@ class BOption extends AbstractBeccaEntity { value!: string; isSynced!: boolean; - constructor(row: OptionRow) { + constructor(row?: OptionRow) { super(); - this.updateFromRow(row); + if (row) { + this.updateFromRow(row); + } this.becca.options[this.name] = this; } diff --git a/src/routes/api/import.js b/src/routes/api/import.js index 115546cae..19b54e8e9 100644 --- a/src/routes/api/import.js +++ b/src/routes/api/import.js @@ -7,7 +7,7 @@ const singleImportService = require('../../services/import/single.js'); const cls = require('../../services/cls'); const path = require('path'); const becca = require('../../becca/becca'); -const beccaLoader = require('../../becca/becca_loader.js'); +const beccaLoader = require('../../becca/becca_loader'); const log = require('../../services/log'); const TaskContext = require('../../services/task_context'); const ValidationError = require('../../errors/validation_error'); diff --git a/src/services/consistency_checks.js b/src/services/consistency_checks.js index 62ea41ca7..9db5994c5 100644 --- a/src/services/consistency_checks.js +++ b/src/services/consistency_checks.js @@ -766,7 +766,7 @@ class ConsistencyChecks { } if (this.reloadNeeded) { - require('../becca/becca_loader.js').reload("consistency checks need becca reload"); + require('../becca/becca_loader').reload("consistency checks need becca reload"); } return !this.unrecoveredConsistencyErrors; diff --git a/src/services/sql.ts b/src/services/sql.ts index f0a9d7d29..1945efa92 100644 --- a/src/services/sql.ts +++ b/src/services/sql.ts @@ -143,8 +143,8 @@ function getRows(query: string, params: Params = []): T[] { return wrap(query, s => s.all(params)) as T[]; } -function getRawRows(query: string, params: Params = []): T[] | null { - return wrap(query, s => s.raw().all(params)) as T[] | null; +function getRawRows(query: string, params: Params = []): T[] { + return (wrap(query, s => s.raw().all(params)) as T[] | null) || []; } function iterateRows(query: string, params: Params = []) { @@ -259,7 +259,7 @@ function transactional(func: (statement: Statement) => T) { if (entityChangeIds.length > 0) { log.info("Transaction rollback dirtied the becca, forcing reload."); - require('../becca/becca_loader.js').load(); + require('../becca/becca_loader').load(); } // the maxEntityChangeId has been incremented during failed transaction, need to recalculate diff --git a/src/services/sql_init.ts b/src/services/sql_init.ts index 400d5ee49..af193d236 100644 --- a/src/services/sql_init.ts +++ b/src/services/sql_init.ts @@ -61,7 +61,7 @@ async function createInitialDatabase() { sql.executeScript(schema); - require('../becca/becca_loader.js').load(); + require('../becca/becca_loader').load(); const BNote = require('../becca/entities/bnote'); const BBranch = require('../becca/entities/bbranch'); diff --git a/src/services/sync.js b/src/services/sync.js index 011ac4d39..a191490cd 100644 --- a/src/services/sync.js +++ b/src/services/sync.js @@ -399,7 +399,7 @@ function getOutstandingPullCount() { return outstandingPullCount; } -require('../becca/becca_loader.js').beccaLoaded.then(() => { +require('../becca/becca_loader').beccaLoaded.then(() => { setInterval(cls.wrap(sync), 60000); // kickoff initial sync immediately, but should happen after initial consistency checks