mirror of
https://github.com/zadam/trilium.git
synced 2025-06-06 18:08:33 +02:00
cleanup of isErased obsolete usage
This commit is contained in:
parent
d0578971f7
commit
c5ec57e08e
@ -15,7 +15,6 @@ const entityChangesService = require('../services/entity_changes.js');
|
|||||||
* @property {string} type
|
* @property {string} type
|
||||||
* @property {string} mime
|
* @property {string} mime
|
||||||
* @property {string} title
|
* @property {string} title
|
||||||
* @property {boolean} isErased
|
|
||||||
* @property {boolean} isProtected
|
* @property {boolean} isProtected
|
||||||
* @property {string} dateLastEdited
|
* @property {string} dateLastEdited
|
||||||
* @property {string} dateCreated
|
* @property {string} dateCreated
|
||||||
|
@ -80,8 +80,7 @@ function downloadNoteRevision(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function eraseAllNoteRevisions(req) {
|
function eraseAllNoteRevisions(req) {
|
||||||
const noteRevisionIdsToErase = sql.getColumn(
|
const noteRevisionIdsToErase = sql.getColumn('SELECT noteRevisionId FROM note_revisions WHERE noteId = ?',
|
||||||
'SELECT noteRevisionId FROM note_revisions WHERE isErased = 0 AND noteId = ?',
|
|
||||||
[req.params.noteId]);
|
[req.params.noteId]);
|
||||||
|
|
||||||
noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase);
|
noteRevisionService.eraseNoteRevisions(noteRevisionIdsToErase);
|
||||||
@ -94,7 +93,7 @@ function eraseNoteRevision(req) {
|
|||||||
function restoreNoteRevision(req) {
|
function restoreNoteRevision(req) {
|
||||||
const noteRevision = repository.getNoteRevision(req.params.noteRevisionId);
|
const noteRevision = repository.getNoteRevision(req.params.noteRevisionId);
|
||||||
|
|
||||||
if (noteRevision && !noteRevision.isErased) {
|
if (noteRevision) {
|
||||||
const note = noteRevision.getNote();
|
const note = noteRevision.getNote();
|
||||||
|
|
||||||
noteRevisionService.createNoteRevision(note);
|
noteRevisionService.createNoteRevision(note);
|
||||||
|
@ -15,7 +15,6 @@ function getRecentChanges(req) {
|
|||||||
notes.noteId,
|
notes.noteId,
|
||||||
notes.isDeleted AS current_isDeleted,
|
notes.isDeleted AS current_isDeleted,
|
||||||
notes.deleteId AS current_deleteId,
|
notes.deleteId AS current_deleteId,
|
||||||
notes.isErased AS current_isErased,
|
|
||||||
notes.title AS current_title,
|
notes.title AS current_title,
|
||||||
notes.isProtected AS current_isProtected,
|
notes.isProtected AS current_isProtected,
|
||||||
note_revisions.title,
|
note_revisions.title,
|
||||||
@ -23,8 +22,7 @@ function getRecentChanges(req) {
|
|||||||
note_revisions.dateCreated AS date
|
note_revisions.dateCreated AS date
|
||||||
FROM
|
FROM
|
||||||
note_revisions
|
note_revisions
|
||||||
JOIN notes USING(noteId)
|
JOIN notes USING(noteId)`);
|
||||||
WHERE note_revisions.isErased = 0`);
|
|
||||||
|
|
||||||
for (const noteRevision of noteRevisions) {
|
for (const noteRevision of noteRevisions) {
|
||||||
if (noteCacheService.isInAncestor(noteRevision.noteId, ancestorNoteId)) {
|
if (noteCacheService.isInAncestor(noteRevision.noteId, ancestorNoteId)) {
|
||||||
@ -40,28 +38,24 @@ function getRecentChanges(req) {
|
|||||||
notes.noteId,
|
notes.noteId,
|
||||||
notes.isDeleted AS current_isDeleted,
|
notes.isDeleted AS current_isDeleted,
|
||||||
notes.deleteId AS current_deleteId,
|
notes.deleteId AS current_deleteId,
|
||||||
notes.isErased AS current_isErased,
|
|
||||||
notes.title AS current_title,
|
notes.title AS current_title,
|
||||||
notes.isProtected AS current_isProtected,
|
notes.isProtected AS current_isProtected,
|
||||||
notes.title,
|
notes.title,
|
||||||
notes.utcDateCreated AS utcDate,
|
notes.utcDateCreated AS utcDate,
|
||||||
notes.dateCreated AS date
|
notes.dateCreated AS date
|
||||||
FROM
|
FROM notes
|
||||||
notes
|
|
||||||
UNION ALL
|
UNION ALL
|
||||||
SELECT
|
SELECT
|
||||||
notes.noteId,
|
notes.noteId,
|
||||||
notes.isDeleted AS current_isDeleted,
|
notes.isDeleted AS current_isDeleted,
|
||||||
notes.deleteId AS current_deleteId,
|
notes.deleteId AS current_deleteId,
|
||||||
notes.isErased AS current_isErased,
|
|
||||||
notes.title AS current_title,
|
notes.title AS current_title,
|
||||||
notes.isProtected AS current_isProtected,
|
notes.isProtected AS current_isProtected,
|
||||||
notes.title,
|
notes.title,
|
||||||
notes.utcDateModified AS utcDate,
|
notes.utcDateModified AS utcDate,
|
||||||
notes.dateModified AS date
|
notes.dateModified AS date
|
||||||
FROM
|
FROM notes
|
||||||
notes
|
WHERE notes.isDeleted = 1`);
|
||||||
WHERE notes.isDeleted = 1 AND notes.isErased = 0`);
|
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
if (noteCacheService.isInAncestor(note.noteId, ancestorNoteId)) {
|
if (noteCacheService.isInAncestor(note.noteId, ancestorNoteId)) {
|
||||||
@ -85,17 +79,12 @@ function getRecentChanges(req) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (change.current_isDeleted) {
|
if (change.current_isDeleted) {
|
||||||
if (change.current_isErased) {
|
const deleteId = change.current_deleteId;
|
||||||
change.canBeUndeleted = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const deleteId = change.current_deleteId;
|
|
||||||
|
|
||||||
const undeletedParentBranches = noteService.getUndeletedParentBranches(change.noteId, deleteId);
|
const undeletedParentBranches = noteService.getUndeletedParentBranches(change.noteId, deleteId);
|
||||||
|
|
||||||
// note (and the subtree) can be undeleted if there's at least one undeleted parent (whose branch would be undeleted by this op)
|
// note (and the subtree) can be undeleted if there's at least one undeleted parent (whose branch would be undeleted by this op)
|
||||||
change.canBeUndeleted = undeletedParentBranches.length > 0;
|
change.canBeUndeleted = undeletedParentBranches.length > 0;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ const optionsService = require('./options');
|
|||||||
const Branch = require('../entities/branch');
|
const Branch = require('../entities/branch');
|
||||||
const dateUtils = require('./date_utils');
|
const dateUtils = require('./date_utils');
|
||||||
const attributeService = require('./attributes');
|
const attributeService = require('./attributes');
|
||||||
|
const noteRevisionService = require('./note_revisions');
|
||||||
|
|
||||||
class ConsistencyChecks {
|
class ConsistencyChecks {
|
||||||
constructor(autoFix) {
|
constructor(autoFix) {
|
||||||
@ -304,7 +305,7 @@ class ConsistencyChecks {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// empty string might be wrong choice for some note types but it's a best guess
|
// empty string might be wrong choice for some note types but it's a best guess
|
||||||
note.setContent(note.isErased ? null : '');
|
note.setContent('');
|
||||||
}
|
}
|
||||||
|
|
||||||
logFix(`Note ${noteId} content was set to empty string since there was no corresponding row`);
|
logFix(`Note ${noteId} content was set to empty string since there was no corresponding row`);
|
||||||
@ -332,53 +333,6 @@ class ConsistencyChecks {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
|
||||||
SELECT noteId
|
|
||||||
FROM notes
|
|
||||||
JOIN note_contents USING (noteId)
|
|
||||||
WHERE isErased = 1
|
|
||||||
AND content IS NOT NULL`,
|
|
||||||
({noteId}) => {
|
|
||||||
|
|
||||||
// we always fix this issue because there does not seem to be a good way to prevent it.
|
|
||||||
// Scenario in which this can happen:
|
|
||||||
// 1. user on instance A deletes the note (sync for notes is created, but not for note_contents) and is later erased
|
|
||||||
// 2. instance B gets synced from instance A, note is updated because of entity change for notes,
|
|
||||||
// but note_contents is not because erasion does not create entity change rows
|
|
||||||
// 3. therefore note.isErased = true, but note_contents.content remains not updated and not erased.
|
|
||||||
//
|
|
||||||
// Considered solutions:
|
|
||||||
// - don't sync erased notes - this might prevent syncing also of the isDeleted flag and note would continue
|
|
||||||
// to exist on the other instance
|
|
||||||
// - create entity changes for erased event - this would be a problem for undeletion since erasion might happen
|
|
||||||
// on one instance after undelete and thus would win even though there's no user action behind it
|
|
||||||
//
|
|
||||||
// So instead we just fix such cases afterwards here.
|
|
||||||
|
|
||||||
sql.execute(`UPDATE note_contents SET content = NULL WHERE noteId = ?`, [noteId]);
|
|
||||||
|
|
||||||
logFix(`Note ${noteId} content has been set to null since the note is erased`);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
|
||||||
SELECT noteId, noteRevisionId
|
|
||||||
FROM notes
|
|
||||||
JOIN note_revisions USING (noteId)
|
|
||||||
WHERE notes.isErased = 1
|
|
||||||
AND note_revisions.isErased = 0`,
|
|
||||||
({noteId, noteRevisionId}) => {
|
|
||||||
if (this.autoFix) {
|
|
||||||
const noteRevision = repository.getNoteRevision(noteRevisionId);
|
|
||||||
noteRevision.isErased = true;
|
|
||||||
noteRevision.setContent(null);
|
|
||||||
noteRevision.save();
|
|
||||||
|
|
||||||
logFix(`Note revision ${noteRevisionId} has been erased since its note ${noteId} is also erased.`);
|
|
||||||
} else {
|
|
||||||
logError(`Note revision ${noteRevisionId} is not erased even though note ${noteId} is erased.`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
this.findAndFixIssues(`
|
||||||
SELECT note_revisions.noteRevisionId
|
SELECT note_revisions.noteRevisionId
|
||||||
FROM note_revisions
|
FROM note_revisions
|
||||||
@ -387,10 +341,7 @@ class ConsistencyChecks {
|
|||||||
AND note_revisions.isProtected = 0`,
|
AND note_revisions.isProtected = 0`,
|
||||||
({noteRevisionId}) => {
|
({noteRevisionId}) => {
|
||||||
if (this.autoFix) {
|
if (this.autoFix) {
|
||||||
const noteRevision = repository.getNoteRevision(noteRevisionId);
|
noteRevisionService.eraseNoteRevisions([noteRevisionId]);
|
||||||
noteRevision.setContent(null);
|
|
||||||
noteRevision.isErased = true;
|
|
||||||
noteRevision.save();
|
|
||||||
|
|
||||||
logFix(`Note revision content ${noteRevisionId} was created and set to erased since it did not exist.`);
|
logFix(`Note revision content ${noteRevisionId} was created and set to erased since it did not exist.`);
|
||||||
} else {
|
} else {
|
||||||
@ -398,59 +349,6 @@ class ConsistencyChecks {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
|
||||||
SELECT noteRevisionId
|
|
||||||
FROM note_revisions
|
|
||||||
JOIN note_revision_contents USING (noteRevisionId)
|
|
||||||
WHERE isErased = 0
|
|
||||||
AND content IS NULL`,
|
|
||||||
({noteRevisionId}) => {
|
|
||||||
if (this.autoFix) {
|
|
||||||
const noteRevision = repository.getNoteRevision(noteRevisionId);
|
|
||||||
noteRevision.isErased = true;
|
|
||||||
noteRevision.save();
|
|
||||||
|
|
||||||
logFix(`Note revision ${noteRevisionId} content was set to erased since it was null even though it was not erased`);
|
|
||||||
} else {
|
|
||||||
logError(`Note revision ${noteRevisionId} content is null even though it is not erased`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
|
||||||
SELECT noteRevisionId
|
|
||||||
FROM note_revisions
|
|
||||||
JOIN note_revision_contents USING (noteRevisionId)
|
|
||||||
WHERE isErased = 1
|
|
||||||
AND content IS NOT NULL`,
|
|
||||||
({noteRevisionId}) => {
|
|
||||||
if (this.autoFix) {
|
|
||||||
sql.execute(`UPDATE note_revision_contents SET content = NULL WHERE noteRevisionId = ?`, [noteRevisionId]);
|
|
||||||
|
|
||||||
logFix(`Note revision ${noteRevisionId} content was set to null since the note revision is erased`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logError(`Note revision ${noteRevisionId} content is not null even though the note revision is erased`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
|
||||||
SELECT noteId
|
|
||||||
FROM notes
|
|
||||||
WHERE isErased = 1
|
|
||||||
AND isDeleted = 0`,
|
|
||||||
({noteId}) => {
|
|
||||||
if (this.autoFix) {
|
|
||||||
const note = repository.getNote(noteId);
|
|
||||||
note.isDeleted = true;
|
|
||||||
note.save();
|
|
||||||
|
|
||||||
logFix(`Note ${noteId} was set to deleted since it is erased`);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logError(`Note ${noteId} is not deleted even though it is erased`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.findAndFixIssues(`
|
this.findAndFixIssues(`
|
||||||
SELECT parentNoteId
|
SELECT parentNoteId
|
||||||
FROM branches
|
FROM branches
|
||||||
@ -661,36 +559,18 @@ class ConsistencyChecks {
|
|||||||
return !this.unrecoveredConsistencyErrors;
|
return !this.unrecoveredConsistencyErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
showEntityStat(name, query) {
|
|
||||||
const map = sql.getMap(query);
|
|
||||||
|
|
||||||
map[0] = map[0] || 0;
|
|
||||||
map[1] = map[1] || 0;
|
|
||||||
|
|
||||||
log.info(`${name} deleted: ${map[1]}, not deleted ${map[0]}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
runDbDiagnostics() {
|
runDbDiagnostics() {
|
||||||
this.showEntityStat("Notes",
|
function showEntityStat(tableName) {
|
||||||
`SELECT isDeleted, count(1)
|
const count = sql.getValue(`SELECT COUNT(1) FROM ${tableName}`);
|
||||||
FROM notes
|
|
||||||
GROUP BY isDeleted`);
|
log.info(`${tableName}: ${count}`);
|
||||||
this.showEntityStat("Note revisions",
|
}
|
||||||
`SELECT isErased, count(1)
|
|
||||||
FROM note_revisions
|
showEntityStat("notes");
|
||||||
GROUP BY isErased`);
|
showEntityStat("note_revisions");
|
||||||
this.showEntityStat("Branches",
|
showEntityStat("branches");
|
||||||
`SELECT isDeleted, count(1)
|
showEntityStat("attributes");
|
||||||
FROM branches
|
showEntityStat("api_tokens");
|
||||||
GROUP BY isDeleted`);
|
|
||||||
this.showEntityStat("Attributes",
|
|
||||||
`SELECT isDeleted, count(1)
|
|
||||||
FROM attributes
|
|
||||||
GROUP BY isDeleted`);
|
|
||||||
this.showEntityStat("API tokens",
|
|
||||||
`SELECT isDeleted, count(1)
|
|
||||||
FROM api_tokens
|
|
||||||
GROUP BY isDeleted`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async runChecks() {
|
async runChecks() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user