From b84b27692cb6f49e8d5e9d1c4b1d7622a68091b5 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Tue, 2 Apr 2024 23:00:04 +0300 Subject: [PATCH] server-ts: Fix some issues from self-review --- src/becca/becca-interface.ts | 12 +- src/becca/becca.ts | 2 +- src/becca/entities/abstract_becca_entity.ts | 12 +- src/becca/entities/bblob.ts | 22 +++- src/becca/entities/brecent_note.ts | 1 + src/becca/entities/rows.ts | 4 - src/becca/entity_constructor.ts | 6 +- src/services/migration.js | 137 -------------------- src/services/window.js | 12 +- 9 files changed, 40 insertions(+), 168 deletions(-) delete mode 100644 src/services/migration.js diff --git a/src/becca/becca-interface.ts b/src/becca/becca-interface.ts index 10495fc7a..5a454335c 100644 --- a/src/becca/becca-interface.ts +++ b/src/becca/becca-interface.ts @@ -21,7 +21,7 @@ interface AttachmentOpts { * Becca is a backend cache of all notes, branches, and attributes. * There's a similar frontend cache Froca, and share cache Shaca. */ -class Becca { +export default class Becca { loaded!: boolean; notes!: Record; @@ -280,4 +280,12 @@ class Becca { } } -export = Becca; \ No newline at end of file +/** + * This interface contains the data that is shared across all the objects of a given derived class of {@link AbstractBeccaEntity}. + * For example, all BAttributes will share their content, but all BBranches will have another set of this data. + */ +export interface ConstructorData> { + primaryKeyName: string; + entityName: string; + hashedProperties: (keyof T)[]; +} \ No newline at end of file diff --git a/src/becca/becca.ts b/src/becca/becca.ts index 8ea1a6575..a66dc442d 100644 --- a/src/becca/becca.ts +++ b/src/becca/becca.ts @@ -1,6 +1,6 @@ "use strict"; -import Becca = require("./becca-interface"); +import Becca from "./becca-interface"; const becca = new Becca(); diff --git a/src/becca/entities/abstract_becca_entity.ts b/src/becca/entities/abstract_becca_entity.ts index 874fecd99..0edcd04ea 100644 --- a/src/becca/entities/abstract_becca_entity.ts +++ b/src/becca/entities/abstract_becca_entity.ts @@ -9,7 +9,7 @@ import cls = require('../../services/cls'); import log = require('../../services/log'); import protectedSessionService = require('../../services/protected_session'); import blobService = require('../../services/blob'); -import Becca = require('../becca-interface'); +import Becca, { ConstructorData } from '../becca-interface'; let becca: Becca | null = null; @@ -18,16 +18,6 @@ interface ContentOpts { forceFrontendReload?: boolean; } -/** - * This interface contains the data that is shared across all the objects of a given derived class of {@link AbstractBeccaEntity}. - * For example, all BAttributes will share their content, but all BBranches will have another set of this data. - */ -interface ConstructorData> { - primaryKeyName: string; - entityName: string; - hashedProperties: (keyof T)[]; -} - /** * Base class for all backend entities. * diff --git a/src/becca/entities/bblob.ts b/src/becca/entities/bblob.ts index 149b9070a..cb2301a5b 100644 --- a/src/becca/entities/bblob.ts +++ b/src/becca/entities/bblob.ts @@ -1,18 +1,24 @@ +import AbstractBeccaEntity = require("./abstract_becca_entity"); import { BlobRow } from "./rows"; // TODO: Why this does not extend the abstract becca? -class BBlob { +class BBlob extends AbstractBeccaEntity { static get entityName() { return "blobs"; } static get primaryKeyName() { return "blobId"; } static get hashedProperties() { return ["blobId", "content"]; } - blobId: string; - content: string | Buffer; - contentLength: number; - dateModified: string; - utcDateModified: string; + blobId!: string; + content!: string | Buffer; + contentLength!: number; + dateModified!: string; + utcDateModified!: string; constructor(row: BlobRow) { + super(); + this.updateFromRow(row); + } + + updateFromRow(row: BlobRow): void { this.blobId = row.blobId; this.content = row.content; this.contentLength = row.contentLength; @@ -20,6 +26,10 @@ class BBlob { this.utcDateModified = row.utcDateModified; } + init() { + // Nothing to do. + } + getPojo() { return { blobId: this.blobId, diff --git a/src/becca/entities/brecent_note.ts b/src/becca/entities/brecent_note.ts index 338dae3c5..da94feaa9 100644 --- a/src/becca/entities/brecent_note.ts +++ b/src/becca/entities/brecent_note.ts @@ -11,6 +11,7 @@ import AbstractBeccaEntity = require('./abstract_becca_entity'); class BRecentNote extends AbstractBeccaEntity { static get entityName() { return "recent_notes"; } static get primaryKeyName() { return "noteId"; } + static get hashedProperties() { return ["noteId", "notePath"]; } noteId!: string; notePath!: string; diff --git a/src/becca/entities/rows.ts b/src/becca/entities/rows.ts index 3429676c0..4f2c089bd 100644 --- a/src/becca/entities/rows.ts +++ b/src/becca/entities/rows.ts @@ -107,7 +107,3 @@ export interface NoteRow { utcDateCreated: string; utcDateModified: string; } - -export interface AttributeRow { - -} \ No newline at end of file diff --git a/src/becca/entity_constructor.ts b/src/becca/entity_constructor.ts index 18c012078..01c51363a 100644 --- a/src/becca/entity_constructor.ts +++ b/src/becca/entity_constructor.ts @@ -1,3 +1,5 @@ +import { ConstructorData } from './becca-interface'; +import AbstractBeccaEntity = require('./entities/abstract_becca_entity'); import BAttachment = require('./entities/battachment'); import BAttribute = require('./entities/battribute'); import BBlob = require('./entities/bblob'); @@ -8,7 +10,9 @@ import BOption = require('./entities/boption'); import BRecentNote = require('./entities/brecent_note'); import BRevision = require('./entities/brevision'); -const ENTITY_NAME_TO_ENTITY: Record = { +type EntityClass = new (row?: any) => AbstractBeccaEntity; + +const ENTITY_NAME_TO_ENTITY: Record & EntityClass> = { "attachments": BAttachment, "attributes": BAttribute, "blobs": BBlob, diff --git a/src/services/migration.js b/src/services/migration.js deleted file mode 100644 index fc6c04443..000000000 --- a/src/services/migration.js +++ /dev/null @@ -1,137 +0,0 @@ -const backupService = require('./backup'); -const sql = require('./sql'); -const fs = require('fs-extra'); -const log = require('./log'); -const utils = require('./utils'); -const resourceDir = require('./resource_dir'); -const appInfo = require('./app_info'); -const cls = require('./cls'); - -async function migrate() { - const currentDbVersion = getDbVersion(); - - if (currentDbVersion < 214) { - log.error("Direct migration from your current version is not supported. Please upgrade to the latest v0.60.4 first and only then to this version."); - - utils.crash(); - return; - } - - // backup before attempting migration - await backupService.backupNow( - // creating a special backup for version 0.60.4, the changes in 0.61 are major. - currentDbVersion === 214 - ? `before-migration-v060` - : 'before-migration' - ); - - const migrations = fs.readdirSync(resourceDir.MIGRATIONS_DIR).map(file => { - const match = file.match(/^([0-9]{4})__([a-zA-Z0-9_ ]+)\.(sql|js)$/); - if (!match) { - return null; - } - - const dbVersion = parseInt(match[1]); - if (dbVersion > currentDbVersion) { - const name = match[2]; - const type = match[3]; - - return { - dbVersion: dbVersion, - name: name, - file: file, - type: type - }; - } else { - return null; - } - }).filter(el => !!el); - - migrations.sort((a, b) => a.dbVersion - b.dbVersion); - - // all migrations are executed in one transaction - upgrade either succeeds, or the user can stay at the old version - // otherwise if half of the migrations succeed, user can't use any version - DB is too "new" for the old app, - // and too old for the new app version. - - cls.setMigrationRunning(true); - - sql.transactional(() => { - for (const mig of migrations) { - try { - log.info(`Attempting migration to version ${mig.dbVersion}`); - - executeMigration(mig); - - sql.execute(`UPDATE options - SET value = ? - WHERE name = ?`, [mig.dbVersion.toString(), "dbVersion"]); - - log.info(`Migration to version ${mig.dbVersion} has been successful.`); - } catch (e) { - log.error(`error during migration to version ${mig.dbVersion}: ${e.stack}`); - log.error("migration failed, crashing hard"); // this is not very user-friendly :-/ - - utils.crash(); - break; // crash() above does not seem to work right away - } - } - }); - - if (currentDbVersion === 214) { - // special VACUUM after the big migration - log.info("VACUUMing database, this might take a while ..."); - sql.execute("VACUUM"); - } -} - -function executeMigration(mig) { - if (mig.type === 'sql') { - const migrationSql = fs.readFileSync(`${resourceDir.MIGRATIONS_DIR}/${mig.file}`).toString('utf8'); - - console.log(`Migration with SQL script: ${migrationSql}`); - - sql.executeScript(migrationSql); - } else if (mig.type === 'js') { - console.log("Migration with JS module"); - - const migrationModule = require(`${resourceDir.MIGRATIONS_DIR}/${mig.file}`); - migrationModule(); - } else { - throw new Error(`Unknown migration type '${mig.type}'`); - } -} - -function getDbVersion() { - return parseInt(sql.getValue("SELECT value FROM options WHERE name = 'dbVersion'")); -} - -function isDbUpToDate() { - const dbVersion = getDbVersion(); - - const upToDate = dbVersion >= appInfo.dbVersion; - - if (!upToDate) { - log.info(`App db version is ${appInfo.dbVersion}, while db version is ${dbVersion}. Migration needed.`); - } - - return upToDate; -} - -async function migrateIfNecessary() { - const currentDbVersion = getDbVersion(); - - if (currentDbVersion > appInfo.dbVersion && process.env.TRILIUM_IGNORE_DB_VERSION !== 'true') { - log.error(`Current DB version ${currentDbVersion} is newer than the current DB version ${appInfo.dbVersion}, which means that it was created by a newer and incompatible version of Trilium. Upgrade to the latest version of Trilium to resolve this issue.`); - - utils.crash(); - } - - if (!isDbUpToDate()) { - await migrate(); - } -} - -module.exports = { - migrateIfNecessary, - isDbUpToDate -}; diff --git a/src/services/window.js b/src/services/window.js index 0e0fbef45..31bf373c5 100644 --- a/src/services/window.js +++ b/src/services/window.js @@ -1,13 +1,13 @@ const path = require('path'); const url = require("url"); -const port = require('./port.ts'); +const port = require('./port'); const optionService = require('./options'); const env = require('./env'); const log = require('./log'); const sqlInit = require('./sql_init'); const cls = require('./cls'); const keyboardActionsService = require('./keyboard_actions'); -const {ipcMain} = require('electron'); +const { ipcMain } = require('electron'); // Prevent the window being garbage collected /** @type {Electron.BrowserWindow} */ @@ -18,7 +18,7 @@ let setupWindow; async function createExtraWindow(extraWindowHash) { const spellcheckEnabled = optionService.getOptionBool('spellCheckEnabled'); - const {BrowserWindow} = require('electron'); + const { BrowserWindow } = require('electron'); const win = new BrowserWindow({ width: 1000, @@ -55,7 +55,7 @@ async function createMainWindow(app) { const spellcheckEnabled = optionService.getOptionBool('spellCheckEnabled'); - const {BrowserWindow} = require('electron'); // should not be statically imported + const { BrowserWindow } = require('electron'); // should not be statically imported mainWindow = new BrowserWindow({ x: mainWindowState.x, @@ -128,7 +128,7 @@ function getIcon() { } async function createSetupWindow() { - const {BrowserWindow} = require('electron'); // should not be statically imported + const { BrowserWindow } = require('electron'); // should not be statically imported setupWindow = new BrowserWindow({ width: 800, height: 800, @@ -152,7 +152,7 @@ function closeSetupWindow() { } async function registerGlobalShortcuts() { - const {globalShortcut} = require('electron'); + const { globalShortcut } = require('electron'); await sqlInit.dbReady;