mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 11:39:01 +01:00 
			
		
		
		
	refactoring of "some path" WIP
This commit is contained in:
		
							parent
							
								
									7aa26580ba
								
							
						
					
					
						commit
						a1d4e062ed
					
				| @ -24,49 +24,12 @@ function isNotePathArchived(notePath) { | |||||||
|     return false; |     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) { | function getNoteTitle(childNoteId, parentNoteId) { | ||||||
|     const childNote = becca.notes[childNoteId]; |     const childNote = becca.notes[childNoteId]; | ||||||
|     const parentNote = becca.notes[parentNoteId]; |     const parentNote = becca.notes[parentNoteId]; | ||||||
| 
 | 
 | ||||||
|     if (!childNote) { |     if (!childNote) { | ||||||
|         log.info(`Cannot find note in cache for noteId '${childNoteId}'`); |         log.info(`Cannot find note '${childNoteId}'`); | ||||||
|         return "[error fetching title]"; |         return "[error fetching title]"; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -119,86 +82,15 @@ function getNoteTitleForPath(notePathArray) { | |||||||
|     return titles.join(' / '); |     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) { | function getNotePath(noteId) { | ||||||
|     const note = becca.notes[noteId]; |     const note = becca.notes[noteId]; | ||||||
| 
 | 
 | ||||||
|     if (!note) { |     if (!note) { | ||||||
|         console.trace(`Cannot find note '${noteId}' in cache.`); |         console.trace(`Cannot find note '${noteId}'.`); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const retPath = getSomePath(note); |     const retPath = note.getBestNotePath(); | ||||||
| 
 | 
 | ||||||
|     if (retPath) { |     if (retPath) { | ||||||
|         const noteTitle = getNoteTitleForPath(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 = { | module.exports = { | ||||||
|     getSomePath, |  | ||||||
|     getNotePath, |     getNotePath, | ||||||
|     getNoteTitle, |     getNoteTitle, | ||||||
|     getNoteTitleForPath, |     getNoteTitleForPath, | ||||||
|     isAvailable, |  | ||||||
|     isArchived, |  | ||||||
|     isInAncestor, |  | ||||||
|     isNotePathArchived |     isNotePathArchived | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -748,6 +748,21 @@ class BNote extends AbstractBeccaEntity { | |||||||
|         return this.hasAttribute('label', 'archived'); |         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() { |     hasInheritableArchivedLabel() { | ||||||
|         for (const attr of this.getAttributes()) { |         for (const attr of this.getAttributes()) { | ||||||
|             if (attr.name === 'archived' && attr.type === LABEL && attr.isInheritable) { |             if (attr.name === 'archived' && attr.type === LABEL && attr.isInheritable) { | ||||||
|  | |||||||
| @ -404,7 +404,7 @@ async function findSimilarNotes(noteId) { | |||||||
|         let score = computeScore(candidateNote); |         let score = computeScore(candidateNote); | ||||||
| 
 | 
 | ||||||
|         if (score >= 1.5) { |         if (score >= 1.5) { | ||||||
|             const notePath = beccaService.getSomePath(candidateNote); |             const notePath = candidateNote.getBestNotePath(); | ||||||
| 
 | 
 | ||||||
|             // this takes care of note hoisting
 |             // this takes care of note hoisting
 | ||||||
|             if (!notePath) { |             if (!notePath) { | ||||||
|  | |||||||
| @ -3,14 +3,14 @@ | |||||||
| const sql = require('../../services/sql'); | const sql = require('../../services/sql'); | ||||||
| const protectedSessionService = require('../../services/protected_session'); | const protectedSessionService = require('../../services/protected_session'); | ||||||
| const noteService = require('../../services/notes'); | const noteService = require('../../services/notes'); | ||||||
| const beccaService = require('../../becca/becca_service'); | const becca = require("../../becca/becca"); | ||||||
| 
 | 
 | ||||||
| function getRecentChanges(req) { | function getRecentChanges(req) { | ||||||
|     const {ancestorNoteId} = req.params; |     const {ancestorNoteId} = req.params; | ||||||
| 
 | 
 | ||||||
|     let recentChanges = []; |     let recentChanges = []; | ||||||
| 
 | 
 | ||||||
|     const noteRevisions = sql.getRows(` |     const noteRevisionRows = sql.getRows(` | ||||||
|         SELECT  |         SELECT  | ||||||
|             notes.noteId, |             notes.noteId, | ||||||
|             notes.isDeleted AS current_isDeleted, |             notes.isDeleted AS current_isDeleted, | ||||||
| @ -24,16 +24,18 @@ function getRecentChanges(req) { | |||||||
|             note_revisions |             note_revisions | ||||||
|             JOIN notes USING(noteId)`);
 |             JOIN notes USING(noteId)`);
 | ||||||
| 
 | 
 | ||||||
|     for (const noteRevision of noteRevisions) { |     for (const noteRevisionRow of noteRevisionRows) { | ||||||
|         if (beccaService.isInAncestor(noteRevision.noteId, ancestorNoteId)) { |         const note = becca.getNote(noteRevisionRow.noteId); | ||||||
|             recentChanges.push(noteRevision); | 
 | ||||||
|  |         if (note?.hasAncestor(ancestorNoteId)) { | ||||||
|  |             recentChanges.push(noteRevisionRow); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // now we need to also collect date points not represented in note revisions:
 |     // now we need to also collect date points not represented in note revisions:
 | ||||||
|     // 1. creation for all notes (dateCreated)
 |     // 1. creation for all notes (dateCreated)
 | ||||||
|     // 2. deletion for deleted notes (dateModified)
 |     // 2. deletion for deleted notes (dateModified)
 | ||||||
|     const notes = sql.getRows(` |     const noteRows = sql.getRows(` | ||||||
|             SELECT |             SELECT | ||||||
|                 notes.noteId, |                 notes.noteId, | ||||||
|                 notes.isDeleted AS current_isDeleted, |                 notes.isDeleted AS current_isDeleted, | ||||||
| @ -57,9 +59,11 @@ function getRecentChanges(req) { | |||||||
|             FROM notes |             FROM notes | ||||||
|             WHERE notes.isDeleted = 1`);
 |             WHERE notes.isDeleted = 1`);
 | ||||||
| 
 | 
 | ||||||
|     for (const note of notes) { |     for (const noteRow of noteRows) { | ||||||
|         if (beccaService.isInAncestor(note.noteId, ancestorNoteId)) { |         const note = becca.getNote(noteRow.noteId); | ||||||
|             recentChanges.push(note); | 
 | ||||||
|  |         if (note?.hasAncestor(ancestorNoteId)) { | ||||||
|  |             recentChanges.push(noteRow); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ class NoteFlatTextExp extends Expression { | |||||||
|          */ |          */ | ||||||
|         function searchDownThePath(note, tokens, path) { |         function searchDownThePath(note, tokens, path) { | ||||||
|             if (tokens.length === 0) { |             if (tokens.length === 0) { | ||||||
|                 const retPath = beccaService.getSomePath(note, path); |                 const retPath = this.getNotePath(note, path); | ||||||
| 
 | 
 | ||||||
|                 if (retPath) { |                 if (retPath) { | ||||||
|                     const noteId = retPath[retPath.length - 1]; |                     const noteId = retPath[retPath.length - 1]; | ||||||
| @ -131,6 +131,17 @@ class NoteFlatTextExp extends Expression { | |||||||
|         return resultNoteSet; |         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 |      * Returns noteIds which have at least one matching tokens | ||||||
|      * |      * | ||||||
|  | |||||||
| @ -157,7 +157,7 @@ function findResultsWithExpression(expression, searchContext) { | |||||||
|     const searchResults = noteSet.notes |     const searchResults = noteSet.notes | ||||||
|         .filter(note => !note.isDeleted) |         .filter(note => !note.isDeleted) | ||||||
|         .map(note => { |         .map(note => { | ||||||
|             const notePathArray = executionContext.noteIdToNotePath[note.noteId] || beccaService.getSomePath(note); |             const notePathArray = executionContext.noteIdToNotePath[note.noteId] || note.getBestNotePath(); | ||||||
| 
 | 
 | ||||||
|             if (!notePathArray) { |             if (!notePathArray) { | ||||||
|                 throw new Error(`Can't find note path for note ${JSON.stringify(note.getPojo())}`); |                 throw new Error(`Can't find note path for note ${JSON.stringify(note.getPojo())}`); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam