From e16bedfab4b65e36e49390779fbf2bab79266d60 Mon Sep 17 00:00:00 2001 From: zadam Date: Thu, 16 Mar 2023 11:02:07 +0100 Subject: [PATCH] WIP blobs --- bin/tpl/anonymize-database.sql | 4 +--- ...ncillaries.sql => 0217__note_attachments.sql} | 1 - db/schema.sql | 5 +---- dump-db/inc/dump.js | 2 +- src/becca/becca.js | 2 +- src/becca/entities/bnote.js | 9 +-------- .../{bnote_ancillary.js => bnote_attachment.js} | 7 ++----- src/becca/entity_constructor.js | 5 +---- src/public/app/services/froca_updater.js | 4 +--- src/public/app/widgets/note_detail.js | 2 +- .../{ancillaries.js => attachments.js} | 0 src/routes/api/note_revisions.js | 4 ++-- src/routes/api/stats.js | 14 ++++++++------ src/routes/api/sync.js | 12 ++++-------- src/services/anonymization.js | 16 ++++++---------- src/services/consistency_checks.js | 4 +--- src/services/entity_changes.js | 6 ++---- src/services/handlers.js | 2 +- src/services/import/enex.js | 16 ++++++++-------- src/services/import/zip.js | 2 +- .../{note_ancillaries.js => note_attachments.js} | 0 src/services/note_revisions.js | 3 --- src/services/notes.js | 7 ++----- .../search/expressions/note_content_fulltext.js | 2 +- src/services/search/services/search.js | 4 ++-- src/services/sync.js | 2 +- src/services/sync_update.js | 8 +++----- src/services/ws.js | 14 +++++++------- src/share/shaca/entities/snote.js | 8 +++++--- src/share/shaca/shaca_loader.js | 2 +- 30 files changed, 65 insertions(+), 102 deletions(-) rename db/migrations/{0217__note_ancillaries.sql => 0217__note_attachments.sql} (93%) rename src/becca/entities/{bnote_ancillary.js => bnote_attachment.js} (95%) rename src/public/app/widgets/type_widgets/{ancillaries.js => attachments.js} (100%) rename src/services/{note_ancillaries.js => note_attachments.js} (100%) diff --git a/bin/tpl/anonymize-database.sql b/bin/tpl/anonymize-database.sql index cf701e53f..a33c1e3c6 100644 --- a/bin/tpl/anonymize-database.sql +++ b/bin/tpl/anonymize-database.sql @@ -1,10 +1,8 @@ UPDATE etapi_tokens SET tokenHash = 'API token hash value'; UPDATE notes SET title = 'title' WHERE noteId != 'root' AND noteId NOT LIKE '\_%' ESCAPE '\'; -UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL; +UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; UPDATE note_revisions SET title = 'title'; -UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL; -UPDATE note_ancillary_contents SET content = 'text' WHERE content IS NOT NULL; UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' diff --git a/db/migrations/0217__note_ancillaries.sql b/db/migrations/0217__note_attachments.sql similarity index 93% rename from db/migrations/0217__note_ancillaries.sql rename to db/migrations/0217__note_attachments.sql index 26b9faa5d..e98ae1045 100644 --- a/db/migrations/0217__note_ancillaries.sql +++ b/db/migrations/0217__note_attachments.sql @@ -5,7 +5,6 @@ CREATE TABLE IF NOT EXISTS "note_ancillaries" name TEXT not null, mime TEXT not null, isProtected INT not null DEFAULT 0, - contentCheckSum TEXT not null, blobId TEXT not null, utcDateModified TEXT not null, isDeleted INT not null, diff --git a/db/schema.sql b/db/schema.sql index 6537ea720..bf8225c2e 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -119,13 +119,10 @@ CREATE TABLE IF NOT EXISTS "note_ancillaries" name TEXT not null, mime TEXT not null, isProtected INT not null DEFAULT 0, - contentCheckSum TEXT not null, utcDateModified TEXT not null, isDeleted INT not null, `deleteId` TEXT DEFAULT NULL); -CREATE TABLE IF NOT EXISTS "note_ancillary_contents" (`noteAncillaryId` TEXT NOT NULL PRIMARY KEY, - `content` TEXT DEFAULT NULL, - `utcDateModified` TEXT NOT NULL); + CREATE INDEX IDX_note_ancillaries_name on note_ancillaries (name); CREATE UNIQUE INDEX IDX_note_ancillaries_noteId_name diff --git a/dump-db/inc/dump.js b/dump-db/inc/dump.js index cd6ba5534..e67d60a1f 100644 --- a/dump-db/inc/dump.js +++ b/dump-db/inc/dump.js @@ -74,7 +74,7 @@ function dumpDocument(documentPath, targetPath, options) { return; } - let {content} = sql.getRow("SELECT content FROM note_contents WHERE noteId = ?", [noteId]); + let {content} = sql.getRow("SELECT content FROM blobs WHERE blobId = ?", [note.blobId]); if (content !== null && note.isProtected && dataKey) { content = decryptService.decrypt(dataKey, content); diff --git a/src/becca/becca.js b/src/becca/becca.js index 3f142f35b..f40a40dec 100644 --- a/src/becca/becca.js +++ b/src/becca/becca.js @@ -125,7 +125,7 @@ class Becca { getNoteAncillary(noteAncillaryId) { const row = sql.getRow("SELECT * FROM note_ancillaries WHERE noteAncillaryId = ?", [noteAncillaryId]); - const BNoteAncillary = require("./entities/bnote_ancillary"); // avoiding circular dependency problems + const BNoteAncillary = require("./entities/bnote_attachment.js"); // avoiding circular dependency problems return row ? new BNoteAncillary(row) : null; } diff --git a/src/becca/entities/bnote.js b/src/becca/entities/bnote.js index 8561c5c33..4561368b3 100644 --- a/src/becca/entities/bnote.js +++ b/src/becca/entities/bnote.js @@ -8,7 +8,7 @@ const dateUtils = require('../../services/date_utils'); const entityChangesService = require('../../services/entity_changes'); const AbstractBeccaEntity = require("./abstract_becca_entity"); const BNoteRevision = require("./bnote_revision"); -const BNoteAncillary = require("./bnote_ancillary"); +const BNoteAncillary = require("./bnote_attachment.js"); const TaskContext = require("../../services/task_context"); const dayjs = require("dayjs"); const utc = require('dayjs/plugin/utc'); @@ -1507,13 +1507,6 @@ class BNote extends AbstractBeccaEntity { saveNoteAncillary(name, mime, content) { let noteAncillary = this.getNoteAncillaryByName(name); - if (noteAncillary - && noteAncillary.mime === mime - && noteAncillary.contentCheckSum === noteAncillary.calculateCheckSum(content)) { - - return noteAncillary; // no change - } - noteAncillary = new BNoteAncillary({ noteId: this.noteId, name, diff --git a/src/becca/entities/bnote_ancillary.js b/src/becca/entities/bnote_attachment.js similarity index 95% rename from src/becca/entities/bnote_ancillary.js rename to src/becca/entities/bnote_attachment.js index 600889391..daf1e063f 100644 --- a/src/becca/entities/bnote_ancillary.js +++ b/src/becca/entities/bnote_attachment.js @@ -41,8 +41,6 @@ class BNoteAncillary extends AbstractBeccaEntity { /** @type {boolean} */ this.isProtected = !!row.isProtected; /** @type {string} */ - this.contentCheckSum = row.contentCheckSum; - /** @type {string} */ this.utcDateModified = row.utcDateModified; } @@ -91,7 +89,6 @@ class BNoteAncillary extends AbstractBeccaEntity { setContent(content) { sql.transactional(() => { - this.contentCheckSum = this.calculateCheckSum(content); this.save(); // also explicitly save note_ancillary to update contentCheckSum const pojo = { @@ -113,7 +110,7 @@ class BNoteAncillary extends AbstractBeccaEntity { entityChangesService.addEntityChange({ entityName: 'note_ancillary_contents', entityId: this.noteAncillaryId, - hash: this.contentCheckSum, + hash: this.contentCheckSum, // FIXME isErased: false, utcDateChanged: pojo.utcDateModified, isSynced: true @@ -144,7 +141,7 @@ class BNoteAncillary extends AbstractBeccaEntity { name: this.name, mime: this.mime, isProtected: !!this.isProtected, - contentCheckSum: this.contentCheckSum, + contentCheckSum: this.contentCheckSum, // FIXME isDeleted: false, utcDateModified: this.utcDateModified }; diff --git a/src/becca/entity_constructor.js b/src/becca/entity_constructor.js index 2b2cdf3c7..e4549ef40 100644 --- a/src/becca/entity_constructor.js +++ b/src/becca/entity_constructor.js @@ -1,6 +1,6 @@ const BNote = require('./entities/bnote'); const BNoteRevision = require('./entities/bnote_revision'); -const BNoteAncillary = require("./entities/bnote_ancillary"); +const BNoteAncillary = require("./entities/bnote_attachment.js"); const BBranch = require('./entities/bbranch'); const BAttribute = require('./entities/battribute'); const BRecentNote = require('./entities/brecent_note'); @@ -11,11 +11,8 @@ const ENTITY_NAME_TO_ENTITY = { "attributes": BAttribute, "branches": BBranch, "notes": BNote, - "note_contents": BNote, "note_revisions": BNoteRevision, - "note_revision_contents": BNoteRevision, "note_ancillaries": BNoteAncillary, - "note_ancillary_contents": BNoteAncillary, "recent_notes": BRecentNote, "etapi_tokens": BEtapiToken, "options": BOption diff --git a/src/public/app/services/froca_updater.js b/src/public/app/services/froca_updater.js index cb8a7248b..ab59ee7c2 100644 --- a/src/public/app/services/froca_updater.js +++ b/src/public/app/services/froca_updater.js @@ -25,8 +25,6 @@ async function processEntityChanges(entityChanges) { loadResults.addNoteContent(ec.noteIds, ec.componentId); } else if (ec.entityName === 'note_revisions') { loadResults.addNoteRevision(ec.entityId, ec.noteId, ec.componentId); - } else if (ec.entityName === 'note_revision_contents') { - // this should change only when toggling isProtected, ignore } else if (ec.entityName === 'options') { if (ec.entity.name === 'openTabs') { continue; // only noise @@ -36,7 +34,7 @@ async function processEntityChanges(entityChanges) { loadResults.addOption(ec.entity.name); } - else if (['etapi_tokens', 'note_ancillaries', 'note_ancillary_contents'].includes(ec.entityName)) { + else if (['etapi_tokens', 'note_ancillaries'].includes(ec.entityName)) { // NOOP } else { diff --git a/src/public/app/widgets/note_detail.js b/src/public/app/widgets/note_detail.js index 433a20a71..b146c3f32 100644 --- a/src/public/app/widgets/note_detail.js +++ b/src/public/app/widgets/note_detail.js @@ -27,7 +27,7 @@ import NoteMapTypeWidget from "./type_widgets/note_map.js"; import WebViewTypeWidget from "./type_widgets/web_view.js"; import DocTypeWidget from "./type_widgets/doc.js"; import ContentWidgetTypeWidget from "./type_widgets/content_widget.js"; -import AncillariesTypeWidget from "./type_widgets/ancillaries.js"; +import AncillariesTypeWidget from "./type_widgets/attachments.js"; const TPL = `
diff --git a/src/public/app/widgets/type_widgets/ancillaries.js b/src/public/app/widgets/type_widgets/attachments.js similarity index 100% rename from src/public/app/widgets/type_widgets/ancillaries.js rename to src/public/app/widgets/type_widgets/attachments.js diff --git a/src/routes/api/note_revisions.js b/src/routes/api/note_revisions.js index 7448eb7da..e6eb5079b 100644 --- a/src/routes/api/note_revisions.js +++ b/src/routes/api/note_revisions.js @@ -12,9 +12,9 @@ const becca = require("../../becca/becca"); function getNoteRevisions(req) { return becca.getNoteRevisionsFromQuery(` SELECT note_revisions.*, - LENGTH(note_revision_contents.content) AS contentLength + LENGTH(blobs.content) AS contentLength FROM note_revisions - JOIN note_revision_contents ON note_revisions.noteRevisionId = note_revision_contents.noteRevisionId + JOIN blobs ON note_revisions.blobId = blobs.blobId WHERE noteId = ? ORDER BY utcDateCreated DESC`, [req.params.noteId]); } diff --git a/src/routes/api/stats.js b/src/routes/api/stats.js index 43aec3014..b342c577c 100644 --- a/src/routes/api/stats.js +++ b/src/routes/api/stats.js @@ -4,18 +4,19 @@ const NotFoundError = require("../../errors/not_found_error"); function getNoteSize(req) { const {noteId} = req.params; + const note = becca.getNote(noteId); const noteSize = sql.getValue(` SELECT - COALESCE((SELECT LENGTH(content) FROM note_contents WHERE noteId = ?), 0) + COALESCE((SELECT LENGTH(content) FROM blobs WHERE blobId = ?), 0) + COALESCE( (SELECT SUM(LENGTH(content)) FROM note_revisions - JOIN note_revision_contents USING (noteRevisionId) + JOIN blobs USING (blobId) WHERE note_revisions.noteId = ?), 0 - )`, [noteId, noteId]); + )`, [note.blobId, noteId]); return { noteSize @@ -38,14 +39,15 @@ function getSubtreeSize(req) { SELECT COALESCE(( SELECT SUM(LENGTH(content)) - FROM note_contents - JOIN param_list ON param_list.paramId = note_contents.noteId + FROM notes + JOIN blobs USING (blobId) + JOIN param_list ON param_list.paramId = notes.noteId ), 0) + COALESCE( (SELECT SUM(LENGTH(content)) FROM note_revisions - JOIN note_revision_contents USING (noteRevisionId) + JOIN blobs USING (blobId) JOIN param_list ON param_list.paramId = note_revisions.noteId), 0 )`); diff --git a/src/routes/api/sync.js b/src/routes/api/sync.js index 3600aa743..ff50874c6 100644 --- a/src/routes/api/sync.js +++ b/src/routes/api/sync.js @@ -12,6 +12,7 @@ const syncOptions = require('../../services/sync_options'); const dateUtils = require('../../services/date_utils'); const utils = require('../../services/utils'); const ws = require('../../services/ws'); +const becca = require("../../becca/becca.js"); async function testSync() { try { @@ -85,14 +86,15 @@ function forceFullSync() { function forceNoteSync(req) { const noteId = req.params.noteId; + const note = becca.getNote(noteId); const now = dateUtils.utcNowDateTime(); sql.execute(`UPDATE notes SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]); entityChangesService.moveEntityChangeToTop('notes', noteId); - sql.execute(`UPDATE note_contents SET utcDateModified = ? WHERE noteId = ?`, [now, noteId]); - entityChangesService.moveEntityChangeToTop('note_contents', noteId); + sql.execute(`UPDATE blobs SET utcDateModified = ? WHERE blobId = ?`, [now, note.blobId]); + entityChangesService.moveEntityChangeToTop('blobs', note.blobId); for (const branchId of sql.getColumn("SELECT branchId FROM branches WHERE noteId = ?", [noteId])) { sql.execute(`UPDATE branches SET utcDateModified = ? WHERE branchId = ?`, [now, branchId]); @@ -109,17 +111,11 @@ function forceNoteSync(req) { for (const noteRevisionId of sql.getColumn("SELECT noteRevisionId FROM note_revisions WHERE noteId = ?", [noteId])) { sql.execute(`UPDATE note_revisions SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]); entityChangesService.moveEntityChangeToTop('note_revisions', noteRevisionId); - - sql.execute(`UPDATE note_revision_contents SET utcDateModified = ? WHERE noteRevisionId = ?`, [now, noteRevisionId]); - entityChangesService.moveEntityChangeToTop('note_revision_contents', noteRevisionId); } for (const noteAncillaryId of sql.getColumn("SELECT noteAncillaryId FROM note_ancillaries WHERE noteId = ?", [noteId])) { sql.execute(`UPDATE note_ancillaries SET utcDateModified = ? WHERE noteAncillaryId = ?`, [now, noteAncillaryId]); entityChangesService.moveEntityChangeToTop('note_ancillaries', noteAncillaryId); - - sql.execute(`UPDATE note_ancillary_contents SET utcDateModified = ? WHERE noteAncillaryId = ?`, [now, noteAncillaryId]); - entityChangesService.moveEntityChangeToTop('note_ancillary_contents', noteAncillaryId); } log.info(`Forcing note sync for ${noteId}`); diff --git a/src/services/anonymization.js b/src/services/anonymization.js index e7de0ecc8..db7c2602b 100644 --- a/src/services/anonymization.js +++ b/src/services/anonymization.js @@ -14,9 +14,8 @@ function getFullAnonymizationScript() { const anonymizeScript = ` UPDATE etapi_tokens SET tokenHash = 'API token hash value'; UPDATE notes SET title = 'title' WHERE title NOT IN ('root', '_hidden', '_share'); -UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL; +UPDATE blobs SET content = 'text' WHERE content IS NOT NULL; UPDATE note_revisions SET title = 'title'; -UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL; UPDATE attributes SET name = 'name', value = 'value' WHERE type = 'label' AND name NOT IN(${builtinAttrNames}); UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${builtinAttrNames}); @@ -34,14 +33,11 @@ VACUUM; } function getLightAnonymizationScript() { - return ` - UPDATE note_contents SET content = 'text' WHERE content IS NOT NULL AND noteId NOT IN ( - SELECT noteId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') - ); - UPDATE note_revision_contents SET content = 'text' WHERE content IS NOT NULL AND noteRevisionId NOT IN ( - SELECT noteRevisionId FROM note_revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') - ); - `; + return `UPDATE blobs SET content = 'text' WHERE content IS NOT NULL AND blobId NOT IN ( + SELECT blobId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') + UNION ALL + SELECT blobId FROM note_revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend') + );`; } async function createAnonymizedCopy(type) { diff --git a/src/services/consistency_checks.js b/src/services/consistency_checks.js index 696a89c49..133e5af85 100644 --- a/src/services/consistency_checks.js +++ b/src/services/consistency_checks.js @@ -656,11 +656,9 @@ class ConsistencyChecks { findEntityChangeIssues() { this.runEntityChangeChecks("notes", "noteId"); - //this.runEntityChangeChecks("note_contents", "noteId"); this.runEntityChangeChecks("note_revisions", "noteRevisionId"); - //this.runEntityChangeChecks("note_revision_contents", "noteRevisionId"); this.runEntityChangeChecks("note_ancillaries", "noteAncillaryId"); - //this.runEntityChangeChecks("note_ancillary_contents", "noteAncillaryId"); + this.runEntityChangeChecks("blobs", "blobId"); this.runEntityChangeChecks("branches", "branchId"); this.runEntityChangeChecks("attributes", "attributeId"); this.runEntityChangeChecks("etapi_tokens", "etapiTokenId"); diff --git a/src/services/entity_changes.js b/src/services/entity_changes.js index 2c3991d81..c91dc19dd 100644 --- a/src/services/entity_changes.js +++ b/src/services/entity_changes.js @@ -104,7 +104,7 @@ function fillEntityChanges(entityName, entityPrimaryKey, condition = '') { let utcDateChanged; let isSynced; - if (entityName.endsWith("_contents")) { + if (entityName === 'blobs') { // FIXME: hacky, not sure if it might cause some problems hash = "fake value"; utcDateChanged = dateUtils.utcNowDateTime(); @@ -147,12 +147,10 @@ function fillAllEntityChanges() { sql.execute("DELETE FROM entity_changes WHERE isErased = 0"); fillEntityChanges("notes", "noteId"); - fillEntityChanges("note_contents", "noteId"); fillEntityChanges("branches", "branchId"); fillEntityChanges("note_revisions", "noteRevisionId"); - fillEntityChanges("note_revision_contents", "noteRevisionId"); fillEntityChanges("note_ancillaries", "noteAncillaryId"); - fillEntityChanges("note_ancillary_contents", "noteAncillaryId"); + fillEntityChanges("blobs", "blobId"); fillEntityChanges("attributes", "attributeId"); fillEntityChanges("etapi_tokens", "etapiTokenId"); fillEntityChanges("options", "name", 'isSynced = 1'); diff --git a/src/services/handlers.js b/src/services/handlers.js index 4bb21f910..69e3c1e21 100644 --- a/src/services/handlers.js +++ b/src/services/handlers.js @@ -59,7 +59,7 @@ eventService.subscribe([ eventService.ENTITY_CHANGED, eventService.ENTITY_DELETE }); eventService.subscribe(eventService.ENTITY_CHANGED, ({entityName, entity}) => { - if (entityName === 'note_contents') { + if (entityName === 'note_contents') { // FIXME runAttachedRelations(entity, 'runOnNoteContentChange', entity); } }); diff --git a/src/services/import/enex.js b/src/services/import/enex.js index 5e8eab780..d0199bbdb 100644 --- a/src/services/import/enex.js +++ b/src/services/import/enex.js @@ -206,7 +206,7 @@ function importEnex(taskContext, file, parentNote) { } }); - function updateDates(noteId, utcDateCreated, utcDateModified) { + function updateDates(note, utcDateCreated, utcDateModified) { // it's difficult to force custom dateCreated and dateModified to Note entity, so we do it post-creation with SQL sql.execute(` UPDATE notes @@ -215,13 +215,13 @@ function importEnex(taskContext, file, parentNote) { dateModified = ?, utcDateModified = ? WHERE noteId = ?`, - [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, noteId]); + [utcDateCreated, utcDateCreated, utcDateModified, utcDateModified, note.noteId]); sql.execute(` - UPDATE note_contents + UPDATE blobs SET utcDateModified = ? - WHERE noteId = ?`, - [utcDateModified, noteId]); + WHERE blobId = ?`, + [utcDateModified, note.blobId]); } function saveNote() { @@ -287,7 +287,7 @@ function importEnex(taskContext, file, parentNote) { resourceNote.addAttribute(attr.type, attr.name, attr.value); } - updateDates(resourceNote.noteId, utcDateCreated, utcDateModified); + updateDates(resourceNote, utcDateCreated, utcDateModified); taskContext.increaseProgressCount(); @@ -310,7 +310,7 @@ function importEnex(taskContext, file, parentNote) { } } - updateDates(imageNote.noteId, utcDateCreated, utcDateModified); + updateDates(imageNote, utcDateCreated, utcDateModified); const imageLink = ``; @@ -337,7 +337,7 @@ function importEnex(taskContext, file, parentNote) { noteService.asyncPostProcessContent(noteEntity, content); - updateDates(noteEntity.noteId, utcDateCreated, utcDateModified); + updateDates(noteEntity, utcDateCreated, utcDateModified); } saxStream.on("closetag", tag => { diff --git a/src/services/import/zip.js b/src/services/import/zip.js index 64df89e28..33a6cbe77 100644 --- a/src/services/import/zip.js +++ b/src/services/import/zip.js @@ -14,7 +14,7 @@ const treeService = require("../tree"); const yauzl = require("yauzl"); const htmlSanitizer = require('../html_sanitizer'); const becca = require("../../becca/becca"); -const BNoteAncillary = require("../../becca/entities/bnote_ancillary"); +const BNoteAncillary = require("../../becca/entities/bnote_attachment.js"); /** * @param {TaskContext} taskContext diff --git a/src/services/note_ancillaries.js b/src/services/note_attachments.js similarity index 100% rename from src/services/note_ancillaries.js rename to src/services/note_attachments.js diff --git a/src/services/note_revisions.js b/src/services/note_revisions.js index 977e80a77..012884c4c 100644 --- a/src/services/note_revisions.js +++ b/src/services/note_revisions.js @@ -44,9 +44,6 @@ function eraseNoteRevisions(noteRevisionIdsToErase) { sql.executeMany(`DELETE FROM note_revisions WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase); sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_revisions' AND entityId IN (???)`, noteRevisionIdsToErase); - - sql.executeMany(`DELETE FROM note_revision_contents WHERE noteRevisionId IN (???)`, noteRevisionIdsToErase); - sql.executeMany(`UPDATE entity_changes SET isErased = 1 WHERE entityName = 'note_revision_contents' AND entityId IN (???)`, noteRevisionIdsToErase); } module.exports = { diff --git a/src/services/notes.js b/src/services/notes.js index 2c71a9a08..9d6260cfd 100644 --- a/src/services/notes.js +++ b/src/services/notes.js @@ -220,7 +220,7 @@ function createNewNote(params) { entity: note }); - eventService.emit(eventService.ENTITY_CREATED, { + eventService.emit(eventService.ENTITY_CREATED, { // FIXME entityName: 'note_contents', entity: note }); @@ -499,7 +499,7 @@ function downloadImages(noteId, content) { asyncPostProcessContent(origNote, updatedContent); eventService.emit(eventService.ENTITY_CHANGED, { - entityName: 'note_contents', + entityName: 'note_contents', // FIXME entity: origNote }); @@ -733,9 +733,6 @@ function eraseNotes(noteIdsToErase) { sql.executeMany(`DELETE FROM notes WHERE noteId IN (???)`, noteIdsToErase); setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'notes' AND entityId IN (???)`, noteIdsToErase)); - sql.executeMany(`DELETE FROM note_contents WHERE noteId IN (???)`, noteIdsToErase); - setEntityChangesAsErased(sql.getManyRows(`SELECT * FROM entity_changes WHERE entityName = 'note_contents' AND entityId IN (???)`, noteIdsToErase)); - // we also need to erase all "dependent" entities of the erased notes const branchIdsToErase = sql.getManyRows(`SELECT branchId FROM branches WHERE noteId IN (???)`, noteIdsToErase) .map(row => row.branchId); diff --git a/src/services/search/expressions/note_content_fulltext.js b/src/services/search/expressions/note_content_fulltext.js index 456306667..2476754d1 100644 --- a/src/services/search/expressions/note_content_fulltext.js +++ b/src/services/search/expressions/note_content_fulltext.js @@ -42,7 +42,7 @@ class NoteContentFulltextExp extends Expression { for (const row of sql.iterateRows(` SELECT noteId, type, mime, content, isProtected - FROM notes JOIN note_contents USING (noteId) + FROM notes JOIN blobs USING (blobId) WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) { this.findInText(row, inputNoteSet, resultNoteSet); diff --git a/src/services/search/services/search.js b/src/services/search/services/search.js index 80b49f3bb..c633d4189 100644 --- a/src/services/search/services/search.js +++ b/src/services/search/services/search.js @@ -103,7 +103,7 @@ function loadNeededInfoFromDatabase() { noteId, LENGTH(content) AS length FROM notes - JOIN note_contents USING(noteId) + JOIN blobs USING(blobId) WHERE notes.isDeleted = 0`); for (const {noteId, length} of noteContentLengths) { @@ -122,7 +122,7 @@ function loadNeededInfoFromDatabase() { LENGTH(content) AS length FROM notes JOIN note_revisions USING(noteId) - JOIN note_revision_contents USING(noteRevisionId) + JOIN blobs USING(blobId) WHERE notes.isDeleted = 0`); for (const {noteId, length} of noteRevisionContentLengths) { diff --git a/src/services/sync.js b/src/services/sync.js index 243266cf6..77622d6ce 100644 --- a/src/services/sync.js +++ b/src/services/sync.js @@ -321,7 +321,7 @@ function getEntityChangeRow(entityName, entityId) { throw new Error(`Entity ${entityName} ${entityId} not found.`); } - if (['note_contents', 'note_revision_contents', 'note_ancillary_contents'].includes(entityName) && entity.content !== null) { + if (entityName === 'blobs' && entity.content !== null) { if (typeof entity.content === 'string') { entity.content = Buffer.from(entity.content, 'UTF-8'); } diff --git a/src/services/sync_update.js b/src/services/sync_update.js index 50fb29a0e..5bd467ddb 100644 --- a/src/services/sync_update.js +++ b/src/services/sync_update.js @@ -64,7 +64,7 @@ function updateNormalEntity(remoteEntityChange, remoteEntityRow, instanceId) { || localEntityChange.utcDateChanged < remoteEntityChange.utcDateChanged || localEntityChange.hash !== remoteEntityChange.hash // sync error, we should still update ) { - if (['note_contents', 'note_revision_contents', 'note_ancillary_contents'].includes(remoteEntityChange.entityName)) { + if (remoteEntityChange.entityName === 'blobs') { remoteEntityRow.content = handleContent(remoteEntityRow.content); } @@ -94,7 +94,7 @@ function updateNoteReordering(entityChange, entity, instanceId) { function handleContent(content) { // we always use Buffer object which is different from normal saving - there we use simple string type for - // "string notes". The problem is that in general it's not possible to detect whether a note_content + // "string notes". The problem is that in general it's not possible to detect whether a blob content // is string note or note (syncs can arrive out of order) content = content === null ? null : Buffer.from(content, 'base64'); @@ -111,13 +111,11 @@ function eraseEntity(entityChange, instanceId) { const entityNames = [ "notes", - "note_contents", "branches", "attributes", "note_revisions", - "note_revision_contents", "note_ancillaries", - "note_ancillary_contents" + "blobs", ]; if (!entityNames.includes(entityName)) { diff --git a/src/services/ws.js b/src/services/ws.js index 8c1f34dd4..ac054b8f4 100644 --- a/src/services/ws.js +++ b/src/services/ws.js @@ -147,13 +147,13 @@ function fillInAdditionalProperties(entityChange) { // entities with higher number can reference the entities with lower number const ORDERING = { "etapi_tokens": 0, - "attributes": 1, - "branches": 1, - "note_contents": 1, - "note_reordering": 1, - "note_revision_contents": 2, - "note_revisions": 1, - "notes": 0, + "attributes": 2, + "branches": 2, + "blobs": 0, + "note_reordering": 2, + "note_revisions": 2, + "note_attachments": 3, + "notes": 1, "options": 0 }; diff --git a/src/share/shaca/entities/snote.js b/src/share/shaca/entities/snote.js index e083ca97b..4a80e0157 100644 --- a/src/share/shaca/entities/snote.js +++ b/src/share/shaca/entities/snote.js @@ -12,7 +12,7 @@ const CREDENTIALS = 'shareCredentials'; const isCredentials = attr => attr.type === 'label' && attr.name === CREDENTIALS; class SNote extends AbstractShacaEntity { - constructor([noteId, title, type, mime, utcDateModified, isProtected]) { + constructor([noteId, title, type, mime, blobId, utcDateModified, isProtected]) { super(); /** @param {string} */ @@ -24,6 +24,8 @@ class SNote extends AbstractShacaEntity { /** @param {string} */ this.mime = mime; /** @param {string} */ + this.blobId = blobId; + /** @param {string} */ this.utcDateModified = utcDateModified; // used for caching of images /** @param {boolean} */ this.isProtected = isProtected; @@ -92,14 +94,14 @@ class SNote extends AbstractShacaEntity { } getContent(silentNotFoundError = false) { - const row = sql.getRow(`SELECT content FROM note_contents WHERE noteId = ?`, [this.noteId]); + const row = sql.getRow(`SELECT content FROM blobs WHERE blobId = ?`, [this.blobId]); if (!row) { if (silentNotFoundError) { return undefined; } else { - throw new Error(`Cannot find note content for noteId=${this.noteId}`); + throw new Error(`Cannot find note content for noteId '${this.noteId}', blobId '${this.blobId}'`); } } diff --git a/src/share/shaca/shaca_loader.js b/src/share/shaca/shaca_loader.js index 64c488036..7ecaaf617 100644 --- a/src/share/shaca/shaca_loader.js +++ b/src/share/shaca/shaca_loader.js @@ -35,7 +35,7 @@ function load() { const noteIdStr = noteIds.map(noteId => `'${noteId}'`).join(","); const rawNoteRows = sql.getRawRows(` - SELECT noteId, title, type, mime, utcDateModified, isProtected + SELECT noteId, title, type, mime, blobId, utcDateModified, isProtected FROM notes WHERE isDeleted = 0 AND noteId IN (${noteIdStr})`);