mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	WIP blobs
This commit is contained in:
		| @@ -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' | ||||
|   | ||||
| @@ -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, | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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 | ||||
|         }; | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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 = ` | ||||
| <div class="note-detail"> | ||||
|   | ||||
| @@ -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]); | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|             )`); | ||||
|   | ||||
| @@ -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}`); | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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"); | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -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); | ||||
|     } | ||||
| }); | ||||
|   | ||||
| @@ -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 = `<img src="${url}">`; | ||||
|  | ||||
| @@ -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 => { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 = { | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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'); | ||||
|             } | ||||
|   | ||||
| @@ -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)) { | ||||
|   | ||||
| @@ -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 | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -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}'`); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -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})`); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user