search overhaul WIP

This commit is contained in:
zadam 2020-05-10 23:27:53 +02:00
parent 552fc5261a
commit 15bc9dce1c

View File

@ -35,7 +35,7 @@ class Note {
/** @return {Attribute[]} */ /** @return {Attribute[]} */
get attributes() { get attributes() {
if (this.noteId in noteAttributeCache) { if (!(this.noteId in noteAttributeCache)) {
const attrArrs = [ const attrArrs = [
this.ownedAttributes this.ownedAttributes
]; ];
@ -88,7 +88,13 @@ class Branch {
/** @return {Note} */ /** @return {Note} */
get parentNote() { 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 { class FulltextReference {
/** /**
* @param type - attributeName, attributeValue, title * @param type - attributeName, attributeValue, title
* @param id - attributeId, noteId * @param noteId
*/ */
constructor(type, id) { constructor(type, noteId) {
this.type = type; 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`, notes = await getMappedRows(`SELECT noteId, title, isProtected FROM notes WHERE isDeleted = 0`,
row => new Note(row)); row => new Note(row));
for (const note of notes) { for (const note of Object.values(notes)) {
fulltext[note.title] = fulltext[note.title] || []; const title = note.title.toLowerCase();
fulltext[note.title].push(new FulltextReference('note', note.noteId));
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`, 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`, attributes = await getMappedRows(`SELECT attributeId, noteId, type, name, value, isInheritable FROM attributes WHERE isDeleted = 0`,
row => new Attribute(row)); row => new Attribute(row));
for (const attr of attributes) { for (const attr of Object.values(attributes)) {
notes[attr.noteId].attributes.push(attr);
addToAttributeMeta(attributes); addToAttributeMeta(attributes);
fulltext[attr.name] = fulltext[attr.name] || []; const attrName = attr.name.toLowerCase();
fulltext[attr.name].push(new FulltextReference('aName', attr.attributeId)); fulltext[attrName] = fulltext[attrName] || [];
fulltext[attrName].push(new FulltextReference('aName', attr.noteId));
fulltext[attr.value] = fulltext[attr.value] || []; const attrValue = attr.value.toLowerCase();
fulltext[attr.value].push(new FulltextReference('aVal', attr.attributeId)); fulltext[attrValue] = fulltext[attrValue] || [];
fulltext[attrValue].push(new FulltextReference('aVal', attr.noteId));
} }
for (const branch of branches) { for (const branch of Object.values(branches)) {
if (branch.branchId === 'root') {
continue;
}
const childNote = notes[branch.noteId]; const childNote = notes[branch.noteId];
if (!childNote) { if (!childNote) {
@ -252,6 +268,14 @@ function highlightResults(results, allTokens) {
allTokens.sort((a, b) => a.length > b.length ? -1 : 1); allTokens.sort((a, b) => a.length > b.length ? -1 : 1);
for (const result of results) { 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; result.highlightedTitle = result.pathTitle;
} }
@ -282,14 +306,29 @@ async function findNotes(query) {
.filter(token => token !== '/'); // '/' is used as separator .filter(token => token !== '/'); // '/' is used as separator
const tokens = allTokens.slice(); 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 = []; let results = [];
for (const noteId in notes) { for (const noteId of matchedNoteIds) {
const note = notes[noteId]; const note = notes[noteId];
// autocomplete should be able to find notes by their noteIds as well (only leafs) // autocomplete should be able to find notes by their noteIds as well (only leafs)
if (noteId === query) { if (noteId === query) {
search(noteId, [], [], results); search(note, [], [], results);
continue; continue;
} }
@ -298,9 +337,19 @@ async function findNotes(query) {
continue; 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) { for (const parentNote of note.parents) {
const title = getNoteTitle(note, parentNote).toLowerCase(); const title = getNoteTitle(note.noteId, parentNote.noteId).toLowerCase();
const foundTokens = []; const foundTokens = foundAttrTokens.slice();
for (const token of tokens) { for (const token of tokens) {
if (title.includes(token)) { if (title.includes(token)) {
@ -370,12 +419,12 @@ function search(note, tokens, path, results) {
return; return;
} }
if (!note.parents.length === 0 || noteId === 'root') { if (!note.parents.length === 0 || note.noteId === 'root') {
return; return;
} }
for (const parentNote of note.parents) { for (const parentNote of note.parents) {
const title = getNoteTitle(note, parentNote).toLowerCase(); const title = getNoteTitle(note.noteId, parentNote.noteId).toLowerCase();
const foundTokens = []; const foundTokens = [];
for (const token of tokens) { for (const token of tokens) {
@ -387,10 +436,10 @@ function search(note, tokens, path, results) {
if (foundTokens.length > 0) { if (foundTokens.length > 0) {
const remainingTokens = tokens.filter(token => !foundTokens.includes(token)); const remainingTokens = tokens.filter(token => !foundTokens.includes(token));
search(parentNote, remainingTokens, path.concat([noteId]), results); search(parentNote, remainingTokens, path.concat([note.noteId]), results);
} }
else { 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]; const note = notes[noteId];
for (const parentNote of notes.parents) { for (const parentNote of note.parents) {
if (isInAncestor(parentNote.noteId, ancestorNoteId)) { if (isInAncestor(parentNote.noteId, ancestorNoteId)) {
return true; 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; let title;
if (childNote.isProtected) { if (childNote.isProtected) {
@ -466,9 +518,9 @@ function getNoteTitle(childNote, parentNote) {
title = childNote.title; 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) { 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 * - 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() * - you can check whether returned path is archived using isArchived()
*/ */
function getSomePath(noteId, path = []) { function getSomePath(note, path = []) {
if (noteId === 'root') { if (note.noteId === 'root') {
path.push(noteId); path.push(note.noteId);
path.reverse(); path.reverse();
if (!path.includes(hoistedNoteService.getHoistedNoteId())) { if (!path.includes(hoistedNoteService.getHoistedNoteId())) {
@ -523,13 +575,13 @@ function getSomePath(noteId, path = []) {
return path; return path;
} }
const parents = childToParent[noteId]; const parents = note.parents;
if (!parents || parents.length === 0) { if (parents.length === 0) {
return false; return false;
} }
for (const parentNoteId of parents) { for (const parentNote of parents) {
const retPath = getSomePath(parentNoteId, path.concat([noteId])); const retPath = getSomePath(parentNote, path.concat([note.noteId]));
if (retPath) { if (retPath) {
return retPath; return retPath;