From ccadff50156670e7eb352e188b2906c58109f1b6 Mon Sep 17 00:00:00 2001 From: zadam Date: Fri, 30 Apr 2021 23:10:25 +0200 Subject: [PATCH] becca conversion WIP --- src/entities/option.js | 39 ---- src/services/becca/becca.js | 8 +- src/services/becca/becca_loader.js | 260 ++++++++++++++------------ src/services/becca/entities/option.js | 32 ++++ src/services/options.js | 6 +- 5 files changed, 178 insertions(+), 167 deletions(-) delete mode 100644 src/entities/option.js create mode 100644 src/services/becca/entities/option.js diff --git a/src/entities/option.js b/src/entities/option.js deleted file mode 100644 index 9802e0f2d..000000000 --- a/src/entities/option.js +++ /dev/null @@ -1,39 +0,0 @@ -"use strict"; - -const Entity = require('./entity'); -const dateUtils = require('../services/date_utils'); - -/** - * Option represents name-value pair, either directly configurable by the user or some system property. - * - * @property {string} name - * @property {string} value - * @property {boolean} isSynced - * @property {string} utcDateModified - * @property {string} utcDateCreated - * - * @extends Entity - */ -class Option extends Entity { - static get entityName() { return "options"; } - static get primaryKeyName() { return "name"; } - static get hashedProperties() { return ["name", "value"]; } - - constructor(row) { - super(row); - - this.isSynced = !!this.isSynced; - } - - beforeSaving() { - if (!this.utcDateCreated) { - this.utcDateCreated = dateUtils.utcNowDateTime(); - } - - super.beforeSaving(); - - this.utcDateModified = dateUtils.utcNowDateTime(); - } -} - -module.exports = Option; diff --git a/src/services/becca/becca.js b/src/services/becca/becca.js index 6505191bc..814397ddb 100644 --- a/src/services/becca/becca.js +++ b/src/services/becca/becca.js @@ -10,15 +10,17 @@ class Becca { reset() { /** @type {Object.} */ - this.notes = []; + this.notes = {}; /** @type {Object.} */ - this.branches = []; + this.branches = {}; /** @type {Object.} */ this.childParentToBranch = {}; /** @type {Object.} */ - this.attributes = []; + this.attributes = {}; /** @type {Object.} Points from attribute type-name to list of attributes */ this.attributeIndex = {}; + /** @type {Object.} */ + this.options = {}; this.loaded = false; } diff --git a/src/services/becca/becca_loader.js b/src/services/becca/becca_loader.js index 21f89178e..9a18b5dbb 100644 --- a/src/services/becca/becca_loader.js +++ b/src/services/becca/becca_loader.js @@ -8,6 +8,7 @@ const log = require('../log'); const Note = require('./entities/note'); const Branch = require('./entities/branch'); const Attribute = require('./entities/attribute'); +const Option = require('./entities/option'); sqlInit.dbReady.then(() => { load(); @@ -18,15 +19,19 @@ function load() { becca.reset(); for (const row of sql.iterateRows(`SELECT noteId, title, type, mime, isProtected, dateCreated, dateModified, utcDateCreated, utcDateModified FROM notes`, [])) { - new Note(becca, row); + new Note(row); } for (const row of sql.iterateRows(`SELECT branchId, noteId, parentNoteId, prefix, notePosition, isExpanded FROM branches WHERE isDeleted = 0`, [])) { - new Branch(becca, row); + new Branch(row); } for (const row of sql.iterateRows(`SELECT attributeId, noteId, type, name, value, isInheritable, position FROM attributes WHERE isDeleted = 0`, [])) { - new Attribute(becca, row); + new Attribute(row); + } + + for (const row of sql.getRows(`SELECT name, value, isSynced, utcDateModified FROM options`)) { + new Option(row); } becca.loaded = true; @@ -34,6 +39,129 @@ function load() { log.info(`Becca (note cache) load took ${Date.now() - start}ms`); } +function updateNote(entity) { + const {noteId} = entity; + + if (entity.isDeleted) { + delete becca.notes[noteId]; + } else if (noteId in becca.notes) { + becca.notes[noteId].update(entity); + } else { + const note = new Note(entity); + + note.decrypt(); + } +} + +function updateBranch(entity) { + const {branchId, noteId, parentNoteId} = entity; + const childNote = becca.notes[noteId]; + + if (entity.isDeleted) { + if (childNote) { + childNote.parents = childNote.parents.filter(parent => parent.noteId !== parentNoteId); + childNote.parentBranches = childNote.parentBranches.filter(branch => branch.branchId !== branchId); + + if (childNote.parents.length > 0) { + childNote.invalidateSubTree(); + } + } + + const parentNote = becca.notes[parentNoteId]; + + if (parentNote) { + parentNote.children = parentNote.children.filter(child => child.noteId !== noteId); + } + + delete becca.childParentToBranch[`${noteId}-${parentNoteId}`]; + delete becca.branches[branchId]; + } else if (branchId in becca.branches) { + // only relevant properties which can change in a branch are prefix and isExpanded + becca.branches[branchId].prefix = entity.prefix; + becca.branches[branchId].isExpanded = entity.isExpanded; + + if (childNote) { + childNote.flatTextCache = null; + } + } else { + becca.branches[branchId] = new Branch(entity); + + if (childNote) { + childNote.resortParents(); + } + } +} + +function updateAttribute(entity) { + const {attributeId, noteId} = entity; + const note = becca.notes[noteId]; + const attr = becca.attributes[attributeId]; + + if (entity.isDeleted) { + if (note && attr) { + // first invalidate and only then remove the attribute (otherwise invalidation wouldn't be complete) + if (attr.isAffectingSubtree || note.isTemplate) { + note.invalidateSubTree(); + } else { + note.invalidateThisCache(); + } + + note.ownedAttributes = note.ownedAttributes.filter(attr => attr.attributeId !== attributeId); + + const targetNote = attr.targetNote; + + if (targetNote) { + targetNote.targetRelations = targetNote.targetRelations.filter(rel => rel.attributeId !== attributeId); + } + } + + delete becca.attributes[attributeId]; + + if (attr) { + const key = `${attr.type}-${attr.name.toLowerCase()}`; + + if (key in becca.attributeIndex) { + becca.attributeIndex[key] = becca.attributeIndex[key].filter(attr => attr.attributeId !== attributeId); + } + } + } else if (attributeId in becca.attributes) { + const attr = becca.attributes[attributeId]; + + // attr name and isInheritable are immutable + attr.value = entity.value; + + if (attr.isAffectingSubtree || note.isTemplate) { + note.invalidateSubtreeFlatText(); + } else { + note.invalidateThisCache(); + } + } else { + const attr = new Attribute(entity); + + if (note) { + if (attr.isAffectingSubtree || note.isTemplate) { + note.invalidateSubTree(); + } else { + note.invalidateThisCache(); + } + } + } +} + +function updateNoteReordering(entity) { + const parentNoteIds = new Set(); + + for (const branchId in entity) { + const branch = becca.branches[branchId]; + + if (branch) { + branch.notePosition = entity[branchId]; + + parentNoteIds.add(branch.parentNoteId); + } + } +} + eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED, eventService.ENTITY_SYNCED], ({entityName, entity}) => { // note that entity can also be just POJO without methods if coming from sync @@ -42,131 +170,19 @@ eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED } if (entityName === 'notes') { - const {noteId} = entity; - - if (entity.isDeleted) { - delete becca.notes[noteId]; - } - else if (noteId in becca.notes) { - becca.notes[noteId].update(entity); - } - else { - const note = new Note(becca, entity); - - note.decrypt(); - } + updateNote(entity); } else if (entityName === 'branches') { - const {branchId, noteId, parentNoteId} = entity; - const childNote = becca.notes[noteId]; - - if (entity.isDeleted) { - if (childNote) { - childNote.parents = childNote.parents.filter(parent => parent.noteId !== parentNoteId); - childNote.parentBranches = childNote.parentBranches.filter(branch => branch.branchId !== branchId); - - if (childNote.parents.length > 0) { - childNote.invalidateSubTree(); - } - } - - const parentNote = becca.notes[parentNoteId]; - - if (parentNote) { - parentNote.children = parentNote.children.filter(child => child.noteId !== noteId); - } - - delete becca.childParentToBranch[`${noteId}-${parentNoteId}`]; - delete becca.branches[branchId]; - } - else if (branchId in becca.branches) { - // only relevant properties which can change in a branch are prefix and isExpanded - becca.branches[branchId].prefix = entity.prefix; - becca.branches[branchId].isExpanded = entity.isExpanded; - - if (childNote) { - childNote.flatTextCache = null; - } - } - else { - becca.branches[branchId] = new Branch(becca, entity); - - if (childNote) { - childNote.resortParents(); - } - } + updateBranch(entity); } else if (entityName === 'attributes') { - const {attributeId, noteId} = entity; - const note = becca.notes[noteId]; - const attr = becca.attributes[attributeId]; - - if (entity.isDeleted) { - if (note && attr) { - // first invalidate and only then remove the attribute (otherwise invalidation wouldn't be complete) - if (attr.isAffectingSubtree || note.isTemplate) { - note.invalidateSubTree(); - } else { - note.invalidateThisCache(); - } - - note.ownedAttributes = note.ownedAttributes.filter(attr => attr.attributeId !== attributeId); - - const targetNote = attr.targetNote; - - if (targetNote) { - targetNote.targetRelations = targetNote.targetRelations.filter(rel => rel.attributeId !== attributeId); - } - } - - delete becca.attributes[attributeId]; - - if (attr) { - const key = `${attr.type}-${attr.name.toLowerCase()}`; - - if (key in becca.attributeIndex) { - becca.attributeIndex[key] = becca.attributeIndex[key].filter(attr => attr.attributeId !== attributeId); - } - } - } - else if (attributeId in becca.attributes) { - const attr = becca.attributes[attributeId]; - - // attr name and isInheritable are immutable - attr.value = entity.value; - - if (attr.isAffectingSubtree || note.isTemplate) { - note.invalidateSubtreeFlatText(); - } - else { - note.invalidateThisCache(); - } - } - else { - const attr = new Attribute(becca, entity); - - if (note) { - if (attr.isAffectingSubtree || note.isTemplate) { - note.invalidateSubTree(); - } - else { - note.invalidateThisCache(); - } - } - } + updateAttribute(entity); + } + else if (entityName === 'options') { + // nothing needed } else if (entityName === 'note_reordering') { - const parentNoteIds = new Set(); - - for (const branchId in entity) { - const branch = becca.branches[branchId]; - - if (branch) { - branch.notePosition = entity[branchId]; - - parentNoteIds.add(branch.parentNoteId); - } - } + updateNoteReordering(entity); } }); diff --git a/src/services/becca/entities/option.js b/src/services/becca/entities/option.js new file mode 100644 index 000000000..056d41474 --- /dev/null +++ b/src/services/becca/entities/option.js @@ -0,0 +1,32 @@ +"use strict"; + +const dateUtils = require('../../date_utils.js'); +const AbstractEntity = require("./abstract_entity.js"); + +/** + * Option represents name-value pair, either directly configurable by the user or some system property. + */ +class Option extends AbstractEntity { + static get entityName() { return "options"; } + static get primaryKeyName() { return "name"; } + static get hashedProperties() { return ["name", "value"]; } + + constructor(row) { + super(); + + this.name = row.name; + this.value = row.value; + this.isSynced = !!row.isSynced; + this.utcDateModified = row.utcDateModified; + + this.becca.options[this.name] = this; + } + + beforeSaving() { + super.beforeSaving(); + + this.utcDateModified = dateUtils.utcNowDateTime(); + } +} + +module.exports = Option; diff --git a/src/services/options.js b/src/services/options.js index 2118d4b9d..a7c96752f 100644 --- a/src/services/options.js +++ b/src/services/options.js @@ -1,5 +1,5 @@ function getOption(name) { - const option = require('./repository').getOption(name); + const option = require('./becca').getOption(name); if (!option) { throw new Error(`Option ${name} doesn't exist`); @@ -37,7 +37,7 @@ function getOptionBool(name) { } function setOption(name, value) { - const option = require('./repository').getOption(name); + const option = require('./becca').getOption(name); if (value === true || value === false) { value = value.toString(); @@ -55,7 +55,7 @@ function setOption(name, value) { function createOption(name, value, isSynced) { // to avoid circular dependency, need to find better solution - const Option = require('../entities/option'); + const Option = require('../services/becca/entities/option'); new Option({ name: name,