mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
WIP blobs
This commit is contained in:
parent
5a8e216dec
commit
e16bedfab4
@ -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})`);
|
||||
|
Loading…
x
Reference in New Issue
Block a user