From 86a53ceebb58f85a08214edd314b5751630cfb63 Mon Sep 17 00:00:00 2001 From: zadam Date: Sat, 7 Aug 2021 21:21:30 +0200 Subject: [PATCH] updating becca after sync --- src/becca/becca.js | 4 +++ src/becca/becca_loader.js | 54 ++++++++++++++++++++++------- src/becca/entities/attribute.js | 7 ++-- src/becca/entities/branch.js | 7 ++-- src/becca/entities/note.js | 11 +++--- src/becca/entities/note_revision.js | 17 +++++++-- src/services/consistency_checks.js | 43 ++++++++++++++--------- src/services/handlers.js | 2 +- 8 files changed, 103 insertions(+), 42 deletions(-) diff --git a/src/becca/becca.js b/src/becca/becca.js index d6f32cb3a..b86e1b5e0 100644 --- a/src/becca/becca.js +++ b/src/becca/becca.js @@ -102,6 +102,10 @@ class Becca { return null; } + if (entityName === 'note_revisions') { + return this.getNoteRevision(entityId); + } + const camelCaseEntityName = entityName.toLowerCase().replace(/(_[a-z])/g, group => group diff --git a/src/becca/becca_loader.js b/src/becca/becca_loader.js index 843256723..13939bc43 100644 --- a/src/becca/becca_loader.js +++ b/src/becca/becca_loader.js @@ -1,15 +1,16 @@ "use strict"; -const sql = require('../services/sql.js'); -const eventService = require('../services/events.js'); -const becca = require('./becca.js'); +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 Note = require('./entities/note.js'); -const Branch = require('./entities/branch.js'); -const Attribute = require('./entities/attribute.js'); -const Option = require('./entities/option.js'); -const cls = require("../services/cls.js"); +const Note = require('./entities/note'); +const Branch = require('./entities/branch'); +const Attribute = require('./entities/attribute'); +const Option = require('./entities/option'); +const cls = require("../services/cls"); +const entityConstructor = require("../becca/entity_constructor"); const beccaLoaded = new Promise((res, rej) => { sqlInit.dbReady.then(() => { @@ -49,11 +50,7 @@ function load() { log.info(`Becca (note cache) load took ${Date.now() - start}ms`); } -eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_CHANGE_SYNCED], ({entityName, entity}) => { - if (!becca.loaded) { - return; - } - +function postProcessEntityUpdate(entityName, entity) { if (entityName === 'branches') { branchUpdated(entity); } else if (entityName === 'attributes') { @@ -61,6 +58,37 @@ eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_CHANGE_ } else if (entityName === 'note_reordering') { noteReorderingUpdated(entity); } +} + +eventService.subscribe([eventService.ENTITY_CHANGE_SYNCED], ({entityName, entity}) => { + if (!becca.loaded) { + return; + } + + if (["notes", "branches", "attributes"].includes(entityName)) { + const EntityClass = entityConstructor.getEntityFromEntityName(entityName); + const primaryKeyName = EntityClass.primaryKeyName; + + let entity = becca.getEntity(entityName, entity[primaryKeyName]); + + if (entity) { + entity.updateFromRow(entity); + } else { + entity = new EntityClass(); + entity.updateFromRow(entity); + entity.init(); + } + } + + postProcessEntityUpdate(entityName, entity); +}); + +eventService.subscribe(eventService.ENTITY_CHANGED, ({entityName, entity}) => { + if (!becca.loaded) { + return; + } + + postProcessEntityUpdate(entityName, entity); }); eventService.subscribe([eventService.ENTITY_DELETED, eventService.ENTITY_DELETE_SYNCED], ({entityName, entityId}) => { diff --git a/src/becca/entities/attribute.js b/src/becca/entities/attribute.js index 77ad4a1c4..d498df81f 100644 --- a/src/becca/entities/attribute.js +++ b/src/becca/entities/attribute.js @@ -18,6 +18,11 @@ class Attribute extends AbstractEntity { return; } + this.updateFromRow(row); + this.init(); + } + + updateFromRow(row) { this.update([ row.attributeId, row.noteId, @@ -28,8 +33,6 @@ class Attribute extends AbstractEntity { row.position, row.utcDateModified ]); - - this.init(); } update([attributeId, noteId, type, name, value, isInheritable, position, utcDateModified]) { diff --git a/src/becca/entities/branch.js b/src/becca/entities/branch.js index 8ddd6b23d..003c22df5 100644 --- a/src/becca/entities/branch.js +++ b/src/becca/entities/branch.js @@ -18,6 +18,11 @@ class Branch extends AbstractEntity { return; } + this.updateFromRow(row); + this.init(); + } + + updateFromRow(row) { this.update([ row.branchId, row.noteId, @@ -27,8 +32,6 @@ class Branch extends AbstractEntity { row.isExpanded, row.utcDateModified ]); - - this.init(); } update([branchId, noteId, parentNoteId, prefix, notePosition, isExpanded, utcDateModified]) { diff --git a/src/becca/entities/note.js b/src/becca/entities/note.js index 9fd0e2c2b..7bf19c974 100644 --- a/src/becca/entities/note.js +++ b/src/becca/entities/note.js @@ -24,6 +24,11 @@ class Note extends AbstractEntity { return; } + this.updateFromRow(row); + this.init(); + } + + updateFromRow(row) { this.update([ row.noteId, row.title, @@ -35,8 +40,6 @@ class Note extends AbstractEntity { row.utcDateCreated, row.utcDateModified ]); - - this.init(); } update([noteId, title, type, mime, isProtected, dateCreated, dateModified, utcDateCreated, utcDateModified]) { @@ -198,7 +201,7 @@ class Note extends AbstractEntity { return JSON.parse(content); } - setContent(content) { + setContent(content, ignoreMissingProtectedSession = false) { if (content === null || content === undefined) { throw new Error(`Cannot set null content to note ${this.noteId}`); } @@ -221,7 +224,7 @@ class Note extends AbstractEntity { if (protectedSessionService.isProtectedSessionAvailable()) { pojo.content = protectedSessionService.encrypt(pojo.content); } - else { + else if (!ignoreMissingProtectedSession) { throw new Error(`Cannot update content of noteId=${this.noteId} since we're out of protected session.`); } } diff --git a/src/becca/entities/note_revision.js b/src/becca/entities/note_revision.js index 6fe9179de..d2eb71378 100644 --- a/src/becca/entities/note_revision.js +++ b/src/becca/entities/note_revision.js @@ -108,7 +108,7 @@ class NoteRevision extends AbstractEntity { } } - setContent(content) { + setContent(content, ignoreMissingProtectedSession = false) { const pojo = { noteRevisionId: this.noteRevisionId, content: content, @@ -119,14 +119,14 @@ class NoteRevision extends AbstractEntity { if (protectedSessionService.isProtectedSessionAvailable()) { pojo.content = protectedSessionService.encrypt(pojo.content); } - else { + else if (!ignoreMissingProtectedSession) { throw new Error(`Cannot update content of noteRevisionId=${this.noteRevisionId} since we're out of protected session.`); } } sql.upsert("note_revision_contents", "noteRevisionId", pojo); - const hash = utils.hash(this.noteRevisionId + "|" + content); + const hash = utils.hash(this.noteRevisionId + "|" + pojo.content.toString()); entityChangesService.addEntityChange({ entityName: 'note_revision_contents', @@ -138,6 +138,17 @@ class NoteRevision extends AbstractEntity { }); } + /** @returns {{contentLength, dateModified, utcDateModified}} */ + getContentMetadata() { + return sql.getRow(` + SELECT + LENGTH(content) AS contentLength, + dateModified, + utcDateModified + FROM note_revision_contents + WHERE noteRevisionId = ?`, [this.noteRevisionId]); + } + beforeSaving() { super.beforeSaving(); diff --git a/src/services/consistency_checks.js b/src/services/consistency_checks.js index e9a427dfc..5dd026179 100644 --- a/src/services/consistency_checks.js +++ b/src/services/consistency_checks.js @@ -460,26 +460,35 @@ class ConsistencyChecks { runEntityChangeChecks(entityName, key) { this.findAndFixIssues(` - SELECT - ${key} as entityId - FROM - ${entityName} - LEFT JOIN entity_changes ON entity_changes.entityName = '${entityName}' - AND entity_changes.entityId = ${key} - WHERE - entity_changes.id IS NULL`, + SELECT + ${key} as entityId + FROM + ${entityName} + LEFT JOIN entity_changes ON entity_changes.entityName = '${entityName}' + AND entity_changes.entityId = ${key} + WHERE + entity_changes.id IS NULL`, ({entityId}) => { if (this.autoFix) { - const entity = becca.getEntity(entityName, entityId); + if (entityName === 'note_contents' || entityName === 'note_revision_contents') { + const entity = entityName === 'note_contents' + ? becca.getNote(entityId) + : becca.getNoteRevision(entityId); - entityChangesService.addEntityChange({ - entityName, - entityId, - hash: entity.generateHash(), - isErased: false, - utcDateChanged: entity.getUtcDateChanged(), - isSynced: entityName !== 'options' || entity.isSynced - }); + entity.setContent(entity.getContent(), true); + } + else { + const entity = becca.getEntity(entityName, entityId); + + entityChangesService.addEntityChange({ + entityName, + entityId, + hash: entity.generateHash(), + isErased: false, + utcDateChanged: entity.getUtcDateChanged(), + isSynced: entityName !== 'options' || entity.isSynced + }); + } logFix(`Created missing entity change for entityName=${entityName}, entityId=${entityId}`); } else { diff --git a/src/services/handlers.js b/src/services/handlers.js index 5785f4153..9a2c9260e 100644 --- a/src/services/handlers.js +++ b/src/services/handlers.js @@ -124,7 +124,7 @@ function processInverseRelations(entityName, entity, handler) { eventService.subscribe(eventService.ENTITY_CHANGED, ({ entityName, entity }) => { processInverseRelations(entityName, entity, (definition, note, targetNote) => { - // we need to make sure that also target's inverse attribute exists and if note, then create it + // we need to make sure that also target's inverse attribute exists and if not, then create it // inverse attribute has to target our note as well const hasInverseAttribute = (targetNote.getRelations(definition.inverseRelation)) .some(attr => attr.value === note.noteId);