mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 10:26:08 +01:00 
			
		
		
		
	search overhaul WIP
This commit is contained in:
		| @@ -35,7 +35,7 @@ class Note { | ||||
|  | ||||
|     /** @return {Attribute[]} */ | ||||
|     get attributes() { | ||||
|         if (this.noteId in noteAttributeCache) { | ||||
|         if (!(this.noteId in noteAttributeCache)) { | ||||
|             const attrArrs = [ | ||||
|                 this.ownedAttributes | ||||
|             ]; | ||||
| @@ -88,7 +88,13 @@ class Branch { | ||||
|  | ||||
|     /** @return {Note} */ | ||||
|     get parentNote() { | ||||
|         return notes[this.parentNoteId]; | ||||
|         const note = notes[this.parentNoteId]; | ||||
|  | ||||
|         if (!note) { | ||||
|             console.log(`Cannot find note ${this.parentNoteId}`); | ||||
|         } | ||||
|  | ||||
|         return note; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -112,11 +118,11 @@ class Attribute { | ||||
| class FulltextReference { | ||||
|     /** | ||||
|      * @param type - attributeName, attributeValue, title | ||||
|      * @param id - attributeId, noteId | ||||
|      * @param noteId | ||||
|      */ | ||||
|     constructor(type, id) { | ||||
|     constructor(type, noteId) { | ||||
|         this.type = type; | ||||
|         this.id = id; | ||||
|         this.noteId = noteId; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -193,9 +199,11 @@ async function load() { | ||||
|     notes = await getMappedRows(`SELECT noteId, title, isProtected FROM notes WHERE isDeleted = 0`, | ||||
|         row => new Note(row)); | ||||
|  | ||||
|     for (const note of notes) { | ||||
|         fulltext[note.title] = fulltext[note.title] || []; | ||||
|         fulltext[note.title].push(new FulltextReference('note', note.noteId)); | ||||
|     for (const note of Object.values(notes)) { | ||||
|         const title = note.title.toLowerCase(); | ||||
|  | ||||
|         fulltext[title] = fulltext[title] || []; | ||||
|         fulltext[title].push(new FulltextReference('note', note.noteId)); | ||||
|     } | ||||
|  | ||||
|     branches = await getMappedRows(`SELECT branchId, noteId, parentNoteId, prefix FROM branches WHERE isDeleted = 0`, | ||||
| @@ -204,17 +212,25 @@ async function load() { | ||||
|     attributes = await getMappedRows(`SELECT attributeId, noteId, type, name, value, isInheritable FROM attributes WHERE isDeleted = 0`, | ||||
|         row => new Attribute(row)); | ||||
|  | ||||
|     for (const attr of attributes) { | ||||
|     for (const attr of Object.values(attributes)) { | ||||
|         notes[attr.noteId].attributes.push(attr); | ||||
|  | ||||
|         addToAttributeMeta(attributes); | ||||
|  | ||||
|         fulltext[attr.name] = fulltext[attr.name] || []; | ||||
|         fulltext[attr.name].push(new FulltextReference('aName', attr.attributeId)); | ||||
|         const attrName = attr.name.toLowerCase(); | ||||
|         fulltext[attrName] = fulltext[attrName] || []; | ||||
|         fulltext[attrName].push(new FulltextReference('aName', attr.noteId)); | ||||
|  | ||||
|         fulltext[attr.value] = fulltext[attr.value] || []; | ||||
|         fulltext[attr.value].push(new FulltextReference('aVal', attr.attributeId)); | ||||
|         const attrValue = attr.value.toLowerCase(); | ||||
|         fulltext[attrValue] = fulltext[attrValue] || []; | ||||
|         fulltext[attrValue].push(new FulltextReference('aVal', attr.noteId)); | ||||
|     } | ||||
|  | ||||
|     for (const branch of Object.values(branches)) { | ||||
|         if (branch.branchId === 'root') { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|     for (const branch of branches) { | ||||
|         const childNote = notes[branch.noteId]; | ||||
|  | ||||
|         if (!childNote) { | ||||
| @@ -252,6 +268,14 @@ function highlightResults(results, allTokens) { | ||||
|     allTokens.sort((a, b) => a.length > b.length ? -1 : 1); | ||||
|  | ||||
|     for (const result of results) { | ||||
|         const note = notes[result.noteId]; | ||||
|  | ||||
|         for (const attr of note.attributes) { | ||||
|             if (allTokens.find(token => attr.name.includes(token) || attr.value.includes(token))) { | ||||
|                 result.pathTitle += ` <small>@${attr.name}=${attr.value}</small>`; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         result.highlightedTitle = result.pathTitle; | ||||
|     } | ||||
|  | ||||
| @@ -282,14 +306,29 @@ async function findNotes(query) { | ||||
|         .filter(token => token !== '/'); // '/' is used as separator | ||||
|  | ||||
|     const tokens = allTokens.slice(); | ||||
|  | ||||
|     const matchedNoteIds = new Set(); | ||||
|  | ||||
|     for (const token of tokens) { | ||||
|         for (const chunk in fulltext) { | ||||
|             if (chunk.includes(token)) { | ||||
|                 for (const fulltextReference of fulltext[chunk]) { | ||||
|                     matchedNoteIds.add(fulltextReference.noteId); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // now we have set of noteIds which match at least one token | ||||
|  | ||||
|     let results = []; | ||||
|  | ||||
|     for (const noteId in notes) { | ||||
|     for (const noteId of matchedNoteIds) { | ||||
|         const note = notes[noteId]; | ||||
|  | ||||
|         // autocomplete should be able to find notes by their noteIds as well (only leafs) | ||||
|         if (noteId === query) { | ||||
|             search(noteId, [], [], results); | ||||
|             search(note, [], [], results); | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
| @@ -298,9 +337,19 @@ async function findNotes(query) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         const foundAttrTokens = []; | ||||
|  | ||||
|         for (const attribute of note.attributes) { | ||||
|             for (const token of tokens) { | ||||
|                 if (attribute.name.includes(token) || attribute.value.includes(token)) { | ||||
|                     foundAttrTokens.push(token); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         for (const parentNote of note.parents) { | ||||
|             const title = getNoteTitle(note, parentNote).toLowerCase(); | ||||
|             const foundTokens = []; | ||||
|             const title = getNoteTitle(note.noteId, parentNote.noteId).toLowerCase(); | ||||
|             const foundTokens = foundAttrTokens.slice(); | ||||
|  | ||||
|             for (const token of tokens) { | ||||
|                 if (title.includes(token)) { | ||||
| @@ -370,12 +419,12 @@ function search(note, tokens, path, results) { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (!note.parents.length === 0 || noteId === 'root') { | ||||
|     if (!note.parents.length === 0 || note.noteId === 'root') { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     for (const parentNote of note.parents) { | ||||
|         const title = getNoteTitle(note, parentNote).toLowerCase(); | ||||
|         const title = getNoteTitle(note.noteId, parentNote.noteId).toLowerCase(); | ||||
|         const foundTokens = []; | ||||
|  | ||||
|         for (const token of tokens) { | ||||
| @@ -387,10 +436,10 @@ function search(note, tokens, path, results) { | ||||
|         if (foundTokens.length > 0) { | ||||
|             const remainingTokens = tokens.filter(token => !foundTokens.includes(token)); | ||||
|  | ||||
|             search(parentNote, remainingTokens, path.concat([noteId]), results); | ||||
|             search(parentNote, remainingTokens, path.concat([note.noteId]), results); | ||||
|         } | ||||
|         else { | ||||
|             search(parentNote, tokens, path.concat([noteId]), results); | ||||
|             search(parentNote, tokens, path.concat([note.noteId]), results); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -436,7 +485,7 @@ function isInAncestor(noteId, ancestorNoteId) { | ||||
|  | ||||
|     const note = notes[noteId]; | ||||
|  | ||||
|     for (const parentNote of notes.parents) { | ||||
|     for (const parentNote of note.parents) { | ||||
|         if (isInAncestor(parentNote.noteId, ancestorNoteId)) { | ||||
|             return true; | ||||
|         } | ||||
| @@ -456,7 +505,10 @@ function getNoteTitleFromPath(notePath) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function getNoteTitle(childNote, parentNote) { | ||||
| function getNoteTitle(childNoteId, parentNoteId) { | ||||
|     const childNote = notes[childNoteId]; | ||||
|     const parentNote = notes[parentNoteId]; | ||||
|  | ||||
|     let title; | ||||
|  | ||||
|     if (childNote.isProtected) { | ||||
| @@ -466,9 +518,9 @@ function getNoteTitle(childNote, parentNote) { | ||||
|         title = childNote.title; | ||||
|     } | ||||
|  | ||||
|     const branch = getBranch(childNote.noteId, parentNote.noteId); | ||||
|     const branch = parentNote ? getBranch(childNote.noteId, parentNote.noteId) : null; | ||||
|  | ||||
|     return (branch.prefix ? (branch.prefix + ' - ') : '') + title; | ||||
|     return ((branch && branch.prefix) ? (branch.prefix + ' - ') : '') + title; | ||||
| } | ||||
|  | ||||
| function getNoteTitleArrayForPath(path) { | ||||
| @@ -511,9 +563,9 @@ function getNoteTitleForPath(path) { | ||||
|  * - 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() | ||||
|  */ | ||||
| function getSomePath(noteId, path = []) { | ||||
|     if (noteId === 'root') { | ||||
|         path.push(noteId); | ||||
| function getSomePath(note, path = []) { | ||||
|     if (note.noteId === 'root') { | ||||
|         path.push(note.noteId); | ||||
|         path.reverse(); | ||||
|  | ||||
|         if (!path.includes(hoistedNoteService.getHoistedNoteId())) { | ||||
| @@ -523,13 +575,13 @@ function getSomePath(noteId, path = []) { | ||||
|         return path; | ||||
|     } | ||||
|  | ||||
|     const parents = childToParent[noteId]; | ||||
|     if (!parents || parents.length === 0) { | ||||
|     const parents = note.parents; | ||||
|     if (parents.length === 0) { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     for (const parentNoteId of parents) { | ||||
|         const retPath = getSomePath(parentNoteId, path.concat([noteId])); | ||||
|     for (const parentNote of parents) { | ||||
|         const retPath = getSomePath(parentNote, path.concat([note.noteId])); | ||||
|  | ||||
|         if (retPath) { | ||||
|             return retPath; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user