mirror of
https://github.com/zadam/trilium.git
synced 2025-01-15 19:51:57 +08:00
refactoring of "some path" WIP
This commit is contained in:
parent
7aa26580ba
commit
a1d4e062ed
6 changed files with 45 additions and 137 deletions
|
@ -24,49 +24,12 @@ function isNotePathArchived(notePath) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This assumes that note is available. "archived" note means that there isn't a single non-archived note-path
|
||||
* leading to this note.
|
||||
*
|
||||
* @param noteId
|
||||
*/
|
||||
function isArchived(noteId) {
|
||||
const notePath = getSomePath(noteId);
|
||||
|
||||
return isNotePathArchived(notePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} noteId
|
||||
* @param {string} ancestorNoteId
|
||||
* @returns {boolean} - true if given noteId has ancestorNoteId in any of its paths (even archived)
|
||||
*/
|
||||
function isInAncestor(noteId, ancestorNoteId) {
|
||||
if (ancestorNoteId === 'root' || ancestorNoteId === noteId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const note = becca.notes[noteId];
|
||||
|
||||
if (!note) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const parentNote of note.parents) {
|
||||
if (isInAncestor(parentNote.noteId, ancestorNoteId)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function getNoteTitle(childNoteId, parentNoteId) {
|
||||
const childNote = becca.notes[childNoteId];
|
||||
const parentNote = becca.notes[parentNoteId];
|
||||
|
||||
if (!childNote) {
|
||||
log.info(`Cannot find note in cache for noteId '${childNoteId}'`);
|
||||
log.info(`Cannot find note '${childNoteId}'`);
|
||||
return "[error fetching title]";
|
||||
}
|
||||
|
||||
|
@ -119,86 +82,15 @@ function getNoteTitleForPath(notePathArray) {
|
|||
return titles.join(' / ');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns notePath for noteId. Note hoisting is respected.
|
||||
* Archived (and hidden) notes are also returned, but non-archived paths are preferred if available
|
||||
* - this means that archived paths is returned only if there's no non-archived path
|
||||
* - you can check whether returned path is archived using isArchived
|
||||
*
|
||||
* @param {BNote} note
|
||||
* @param {string[]} path
|
||||
*/
|
||||
function getSomePath(note, path = []) {
|
||||
// first try to find note within hoisted note, otherwise take any existing note path
|
||||
return getSomePathInner(note, path, true)
|
||||
|| getSomePathInner(note, path, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BNote} note
|
||||
* @param {string[]} parentPath
|
||||
* @param {boolean} respectHoisting
|
||||
* @returns {string[]|false}
|
||||
*/
|
||||
function getSomePathInner(note, parentPath, respectHoisting) {
|
||||
const childPath = [...parentPath, note.noteId];
|
||||
if (note.isRoot()) {
|
||||
childPath.reverse();
|
||||
|
||||
if (respectHoisting && !childPath.includes(cls.getHoistedNoteId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return childPath;
|
||||
}
|
||||
|
||||
const parents = note.parents;
|
||||
if (parents.length === 0) {
|
||||
console.log(`Note '${note.noteId}' - '${note.title}' has no parents.`);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const completeNotePaths = parents.map(parentNote => getSomePathInner(parentNote, childPath, respectHoisting));
|
||||
|
||||
if (completeNotePaths.length === 0) {
|
||||
return false;
|
||||
} else if (completeNotePaths.length === 1) {
|
||||
return completeNotePaths[0];
|
||||
} else {
|
||||
completeNotePaths.sort((a, b) => {
|
||||
if (a.isInHoistedSubTree !== b.isInHoistedSubTree) {
|
||||
return a.isInHoistedSubTree ? -1 : 1;
|
||||
} else if (a.isSearch !== b.isSearch) {
|
||||
return a.isSearch ? 1 : -1;
|
||||
} else if (a.isArchived !== b.isArchived) {
|
||||
return a.isArchived ? 1 : -1;
|
||||
} else if (a.isHidden !== b.isHidden) {
|
||||
return a.isHidden ? 1 : -1;
|
||||
} else {
|
||||
return a.notePath.length - b.notePath.length;
|
||||
}
|
||||
});
|
||||
|
||||
// if there are multiple valid paths, take the shortest one
|
||||
const shortestNotePath = completeNotePaths.reduce((shortestPath, nextPath) =>
|
||||
nextPath.length < shortestPath.length
|
||||
? nextPath
|
||||
: shortestPath, completeNotePaths[0]);
|
||||
|
||||
return shortestNotePath;
|
||||
}
|
||||
}
|
||||
|
||||
function getNotePath(noteId) {
|
||||
const note = becca.notes[noteId];
|
||||
|
||||
if (!note) {
|
||||
console.trace(`Cannot find note '${noteId}' in cache.`);
|
||||
console.trace(`Cannot find note '${noteId}'.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const retPath = getSomePath(note);
|
||||
const retPath = note.getBestNotePath();
|
||||
|
||||
if (retPath) {
|
||||
const noteTitle = getNoteTitleForPath(retPath);
|
||||
|
@ -223,23 +115,9 @@ function getNotePath(noteId) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param noteId
|
||||
* @returns {boolean} - true if note exists (is not deleted) and is available in current note hoisting
|
||||
*/
|
||||
function isAvailable(noteId) {
|
||||
const notePath = getNotePath(noteId);
|
||||
|
||||
return !!notePath;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getSomePath,
|
||||
getNotePath,
|
||||
getNoteTitle,
|
||||
getNoteTitleForPath,
|
||||
isAvailable,
|
||||
isArchived,
|
||||
isInAncestor,
|
||||
isNotePathArchived
|
||||
};
|
||||
|
|
|
@ -748,6 +748,21 @@ class BNote extends AbstractBeccaEntity {
|
|||
return this.hasAttribute('label', 'archived');
|
||||
}
|
||||
|
||||
areAllNotePathsArchived() {
|
||||
// there's a slight difference between note being itself archived and all its note paths being archived
|
||||
// - note is archived when it itself has an archived label or inherits it
|
||||
// - note does not have or inherit archived label, but each note paths contains a note with (non-inheritable)
|
||||
// archived label
|
||||
|
||||
const bestNotePathRecord = this.getSortedNotePathRecords()[0];
|
||||
|
||||
if (!bestNotePathRecord) {
|
||||
throw new Error(`No note path available for note '${this.noteId}'`);
|
||||
}
|
||||
|
||||
return bestNotePathRecord.isArchived;
|
||||
}
|
||||
|
||||
hasInheritableArchivedLabel() {
|
||||
for (const attr of this.getAttributes()) {
|
||||
if (attr.name === 'archived' && attr.type === LABEL && attr.isInheritable) {
|
||||
|
|
|
@ -404,7 +404,7 @@ async function findSimilarNotes(noteId) {
|
|||
let score = computeScore(candidateNote);
|
||||
|
||||
if (score >= 1.5) {
|
||||
const notePath = beccaService.getSomePath(candidateNote);
|
||||
const notePath = candidateNote.getBestNotePath();
|
||||
|
||||
// this takes care of note hoisting
|
||||
if (!notePath) {
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
const sql = require('../../services/sql');
|
||||
const protectedSessionService = require('../../services/protected_session');
|
||||
const noteService = require('../../services/notes');
|
||||
const beccaService = require('../../becca/becca_service');
|
||||
const becca = require("../../becca/becca");
|
||||
|
||||
function getRecentChanges(req) {
|
||||
const {ancestorNoteId} = req.params;
|
||||
|
||||
let recentChanges = [];
|
||||
|
||||
const noteRevisions = sql.getRows(`
|
||||
const noteRevisionRows = sql.getRows(`
|
||||
SELECT
|
||||
notes.noteId,
|
||||
notes.isDeleted AS current_isDeleted,
|
||||
|
@ -24,16 +24,18 @@ function getRecentChanges(req) {
|
|||
note_revisions
|
||||
JOIN notes USING(noteId)`);
|
||||
|
||||
for (const noteRevision of noteRevisions) {
|
||||
if (beccaService.isInAncestor(noteRevision.noteId, ancestorNoteId)) {
|
||||
recentChanges.push(noteRevision);
|
||||
for (const noteRevisionRow of noteRevisionRows) {
|
||||
const note = becca.getNote(noteRevisionRow.noteId);
|
||||
|
||||
if (note?.hasAncestor(ancestorNoteId)) {
|
||||
recentChanges.push(noteRevisionRow);
|
||||
}
|
||||
}
|
||||
|
||||
// now we need to also collect date points not represented in note revisions:
|
||||
// 1. creation for all notes (dateCreated)
|
||||
// 2. deletion for deleted notes (dateModified)
|
||||
const notes = sql.getRows(`
|
||||
const noteRows = sql.getRows(`
|
||||
SELECT
|
||||
notes.noteId,
|
||||
notes.isDeleted AS current_isDeleted,
|
||||
|
@ -57,9 +59,11 @@ function getRecentChanges(req) {
|
|||
FROM notes
|
||||
WHERE notes.isDeleted = 1`);
|
||||
|
||||
for (const note of notes) {
|
||||
if (beccaService.isInAncestor(note.noteId, ancestorNoteId)) {
|
||||
recentChanges.push(note);
|
||||
for (const noteRow of noteRows) {
|
||||
const note = becca.getNote(noteRow.noteId);
|
||||
|
||||
if (note?.hasAncestor(ancestorNoteId)) {
|
||||
recentChanges.push(noteRow);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class NoteFlatTextExp extends Expression {
|
|||
*/
|
||||
function searchDownThePath(note, tokens, path) {
|
||||
if (tokens.length === 0) {
|
||||
const retPath = beccaService.getSomePath(note, path);
|
||||
const retPath = this.getNotePath(note, path);
|
||||
|
||||
if (retPath) {
|
||||
const noteId = retPath[retPath.length - 1];
|
||||
|
@ -131,6 +131,17 @@ class NoteFlatTextExp extends Expression {
|
|||
return resultNoteSet;
|
||||
}
|
||||
|
||||
getNotePath(note, path) {
|
||||
if (path.length === 0) {
|
||||
return note.getBestNotePath();
|
||||
} else {
|
||||
const closestNoteId = path[0];
|
||||
const closestNoteBestNotePath = becca.getNote(closestNoteId).getBestNotePathString();
|
||||
|
||||
return [...closestNoteBestNotePath, ...path.slice(1)];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns noteIds which have at least one matching tokens
|
||||
*
|
||||
|
|
|
@ -157,7 +157,7 @@ function findResultsWithExpression(expression, searchContext) {
|
|||
const searchResults = noteSet.notes
|
||||
.filter(note => !note.isDeleted)
|
||||
.map(note => {
|
||||
const notePathArray = executionContext.noteIdToNotePath[note.noteId] || beccaService.getSomePath(note);
|
||||
const notePathArray = executionContext.noteIdToNotePath[note.noteId] || note.getBestNotePath();
|
||||
|
||||
if (!notePathArray) {
|
||||
throw new Error(`Can't find note path for note ${JSON.stringify(note.getPojo())}`);
|
||||
|
|
Loading…
Reference in a new issue