searching now works correctly in inherited attributes

This commit is contained in:
zadam 2020-05-13 00:01:10 +02:00
parent 29e6b63f82
commit ccb5f3ee18

View file

@ -29,6 +29,8 @@ class Note {
this.isProtected = !!row.isProtected; this.isProtected = !!row.isProtected;
/** @param {Note[]} */ /** @param {Note[]} */
this.parents = []; this.parents = [];
/** @param {Note[]} */
this.children = [];
/** @param {Attribute[]} */ /** @param {Attribute[]} */
this.ownedAttributes = []; this.ownedAttributes = [];
} }
@ -60,6 +62,14 @@ class Note {
return noteAttributeCache[this.noteId]; return noteAttributeCache[this.noteId];
} }
addSubTreeNoteIdsTo(noteIdSet) {
noteIdSet.add(this.noteId);
for (const child of this.children) {
child.addSubTreeNoteIdsTo(noteIdSet);
}
}
/** @return {Attribute[]} */ /** @return {Attribute[]} */
get inheritableAttributes() { get inheritableAttributes() {
return this.attributes.filter(attr => attr.isInheritable); return this.attributes.filter(attr => attr.isInheritable);
@ -111,22 +121,11 @@ class Attribute {
/** @param {string} */ /** @param {string} */
this.value = row.value; this.value = row.value;
/** @param {boolean} */ /** @param {boolean} */
this.isInheritable = row.isInheritable; this.isInheritable = !!row.isInheritable;
} }
} }
class FulltextReference { /** @type {Object.<String, String>} */
/**
* @param type - attributeName, attributeValue, title
* @param noteId
*/
constructor(type, noteId) {
this.type = type;
this.noteId = noteId;
}
}
/** @type {Object.<String, FulltextReference>} */
let fulltext = {}; let fulltext = {};
/** @type {Object.<String, AttributeMeta>} */ /** @type {Object.<String, AttributeMeta>} */
@ -195,17 +194,21 @@ async function getMappedRows(query, cb) {
return map; return map;
} }
function updateFulltext(note) {
let ft = note.title.toLowerCase();
for (const attr of note.attributes) {
ft += '|' + attr.name.toLowerCase();
ft += '|' + attr.value.toLowerCase();
}
fulltext[note.noteId] = ft;
}
async function load() { 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 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`, branches = await getMappedRows(`SELECT branchId, noteId, parentNoteId, prefix FROM branches WHERE isDeleted = 0`,
row => new Branch(row)); row => new Branch(row));
@ -213,17 +216,9 @@ async function load() {
row => new Attribute(row)); row => new Attribute(row));
for (const attr of Object.values(attributes)) { for (const attr of Object.values(attributes)) {
notes[attr.noteId].attributes.push(attr); notes[attr.noteId].ownedAttributes.push(attr);
addToAttributeMeta(attributes); addToAttributeMeta(attributes);
const attrName = attr.name.toLowerCase();
fulltext[attrName] = fulltext[attrName] || [];
fulltext[attrName].push(new FulltextReference('aName', attr.noteId));
const attrValue = attr.value.toLowerCase();
fulltext[attrValue] = fulltext[attrValue] || [];
fulltext[attrValue].push(new FulltextReference('aVal', attr.noteId));
} }
for (const branch of Object.values(branches)) { for (const branch of Object.values(branches)) {
@ -232,13 +227,16 @@ async function load() {
} }
const childNote = notes[branch.noteId]; const childNote = notes[branch.noteId];
const parentNote = branch.parentNote;
if (!childNote) { if (!childNote) {
console.log(`Cannot find child note ${branch.noteId} of a branch ${branch.branchId}`); console.log(`Cannot find child note ${branch.noteId} of a branch ${branch.branchId}`);
continue; continue;
} }
childNote.parents.push(branch.parentNote); childNote.parents.push(parentNote);
parentNote.children.push(childNote);
childParentToBranch[`${branch.noteId}-${branch.parentNoteId}`] = branch; childParentToBranch[`${branch.noteId}-${branch.parentNoteId}`] = branch;
} }
@ -246,6 +244,10 @@ async function load() {
await decryptProtectedNotes(); await decryptProtectedNotes();
} }
for (const note of Object.values(notes)) {
updateFulltext(note);
}
loaded = true; loaded = true;
loadedPromiseResolve(); loadedPromiseResolve();
} }
@ -295,7 +297,7 @@ function highlightResults(results, allTokens) {
} }
async function findNotes(query) { async function findNotes(query) {
if (!noteTitles || !query.length) { if (!query.length) {
return []; return [];
} }
@ -310,15 +312,31 @@ async function findNotes(query) {
const matchedNoteIds = new Set(); const matchedNoteIds = new Set();
for (const token of tokens) { for (const token of tokens) {
for (const chunk in fulltext) { for (const noteId in fulltext) {
if (chunk.includes(token)) { if (!fulltext[noteId].includes(token)) {
for (const fulltextReference of fulltext[chunk]) { continue;
matchedNoteIds.add(fulltextReference.noteId);
}
} }
matchedNoteIds.add(noteId);
const note = notes[noteId];
const inheritableAttrs = note.ownedAttributes.filter(attr => attr.isInheritable);
searchingAttrs:
for (const attr of inheritableAttrs) {
const lcName = attr.name.toLowerCase();
const lcValue = attr.value.toLowerCase();
for (const token of tokens) {
if (lcName.includes(token) || lcValue.includes(token)) {
note.addSubTreeNoteIdsTo(matchedNoteIds);
break searchingAttrs;
}
}
}
} }
} }
//console.log(matchedNoteIds);
// now we have set of noteIds which match at least one token // now we have set of noteIds which match at least one token
let results = []; let results = [];
@ -339,9 +357,10 @@ async function findNotes(query) {
const foundAttrTokens = []; const foundAttrTokens = [];
for (const attribute of note.attributes) { for (const attribute of note.ownedAttributes) {
for (const token of tokens) { for (const token of tokens) {
if (attribute.name.includes(token) || attribute.value.includes(token)) { if (attribute.name.toLowerCase().includes(token)
|| attribute.value.toLowerCase().includes(token)) {
foundAttrTokens.push(token); foundAttrTokens.push(token);
} }
} }
@ -423,9 +442,20 @@ function search(note, tokens, path, results) {
return; return;
} }
const foundAttrTokens = [];
for (const attribute of note.ownedAttributes) {
for (const token of tokens) {
if (attribute.name.toLowerCase().includes(token)
|| attribute.value.toLowerCase().includes(token)) {
foundAttrTokens.push(token);
}
}
}
for (const parentNote of note.parents) { for (const parentNote of note.parents) {
const title = getNoteTitle(note.noteId, parentNote.noteId).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)) {
@ -592,15 +622,16 @@ function getSomePath(note, path = []) {
} }
function getNotePath(noteId) { function getNotePath(noteId) {
const retPath = getSomePath(noteId); const note = notes[noteId];
const retPath = getSomePath(note);
if (retPath) { if (retPath) {
const noteTitle = getNoteTitleForPath(retPath); const noteTitle = getNoteTitleForPath(retPath);
const parentNoteId = childToParent[noteId][0]; const parentNote = note.parents[0];
return { return {
noteId: noteId, noteId: noteId,
branchId: childParentToBranchId[`${noteId}-${parentNoteId}`], branchId: getBranch(noteId, parentNote.noteId).branchId,
title: noteTitle, title: noteTitle,
notePath: retPath, notePath: retPath,
path: retPath.join('/') path: retPath.join('/')