added ancestor depth search criteria

This commit is contained in:
zadam 2021-01-26 23:25:18 +01:00
parent a1f67e830d
commit fbabdef272
6 changed files with 119 additions and 9 deletions

View File

@ -3,12 +3,43 @@ import noteAutocompleteService from "../../services/note_autocomplete.js";
const TPL = `
<tr>
<td class="title-column" title="Matched notes must be within subtree of given note.">
Ancestor:
</td>
<td>
<div class="input-group">
<input class="ancestor form-control" placeholder="search for note by its name">
<td colspan="2">
<div style="display: flex; align-items: center;">
<div style="margin-right: 10px">Ancestor:</div>
<div class="input-group" style="flex-shrink: 2">
<input class="ancestor form-control" placeholder="search for note by its name">
</div>
<div style="margin-left: 10px; margin-right: 10px">depth:</div>
<select name="depth" class="form-control d-inline ancestor-depth" style="flex-shrink: 3">
<option value="">doesn't mattter</option>
<option value="eq1">is exactly 1 (direct children)</option>
<option value="eq2">is exactly 2</option>
<option value="eq3">is exactly 3</option>
<option value="eq4">is exactly 4</option>
<option value="eq5">is exactly 5</option>
<option value="eq6">is exactly 6</option>
<option value="eq7">is exactly 7</option>
<option value="eq8">is exactly 8</option>
<option value="eq9">is exactly 9</option>
<option value="gt1">is greater than 1</option>
<option value="gt2">is greater than 2</option>
<option value="gt3">is greater than 3</option>
<option value="gt4">is greater than 4</option>
<option value="gt5">is greater than 5</option>
<option value="gt6">is greater than 6</option>
<option value="gt7">is greater than 7</option>
<option value="gt8">is greater than 8</option>
<option value="gt9">is greater than 9</option>
<option value="lt3">is less than 3</option>
<option value="lt4">is less than 4</option>
<option value="lt5">is less than 5</option>
<option value="lt6">is less than 6</option>
<option value="lt7">is less than 7</option>
<option value="lt8">is less than 8</option>
<option value="lt9">is less than 9</option>
</select>
</div>
</td>
<td class="button-column">
@ -27,6 +58,7 @@ export default class Ancestor extends AbstractSearchOption {
doRender() {
const $option = $(TPL);
const $ancestor = $option.find('.ancestor');
const $ancestorDepth = $option.find('.ancestor-depth');
noteAutocompleteService.initNoteAutocomplete($ancestor);
$ancestor.on('autocomplete:closed', async () => {
@ -37,12 +69,35 @@ export default class Ancestor extends AbstractSearchOption {
}
});
$ancestorDepth.on('change', async () => {
const ancestorDepth = $ancestorDepth.val();
if (ancestorDepth) {
await this.setAttribute('label', 'ancestorDepth', ancestorDepth);
}
else {
await this.deleteAttribute('label', 'ancestorDepth');
}
});
const ancestorNoteId = this.note.getRelationValue('ancestor');
if (ancestorNoteId !== 'root') {
$ancestor.setNote(ancestorNoteId);
}
const ancestorDepth = this.note.getLabelValue('ancestorDepth');
if (ancestorDepth) {
$ancestorDepth.val(ancestorDepth);
}
return $option;
}
async deleteOption() {
await this.deleteAttribute('label', 'ancestorDepth');
await super.deleteOption();
}
}

View File

@ -18,6 +18,7 @@ async function search(note) {
const searchContext = new SearchContext({
fastSearch: note.hasLabel('fastSearch'),
ancestorNoteId: note.getRelationValue('ancestor'),
ancestorDepth: note.getLabelValue('ancestorDepth'),
includeArchivedNotes: note.hasLabel('includeArchivedNotes'),
orderBy: note.getLabelValue('orderBy'),
orderDirection: note.getLabelValue('orderDirection'),

View File

@ -368,6 +368,20 @@ class Note {
return arr;
}
getDistanceToAncestor(ancestorNoteId) {
if (this.noteId === ancestorNoteId) {
return 0;
}
let minDistance = 999_999;
for (const parent of this.parents) {
minDistance = Math.min(minDistance, parent.getDistanceToAncestor(ancestorNoteId) + 1);
}
return minDistance;
}
decrypt() {
if (this.isProtected && !this.isDecrypted && protectedSessionService.isProtectedSessionAvailable()) {
this.title = protectedSessionService.decryptString(this.title);

View File

@ -6,10 +6,11 @@ const log = require('../../log');
const noteCache = require('../../note_cache/note_cache');
class AncestorExp extends Expression {
constructor(ancestorNoteId) {
constructor(ancestorNoteId, ancestorDepth) {
super();
this.ancestorNoteId = ancestorNoteId;
this.ancestorDepthComparator = this.getComparator(ancestorDepth);
}
execute(inputNoteSet, executionContext) {
@ -21,7 +22,45 @@ class AncestorExp extends Expression {
return new NoteSet([]);
}
return new NoteSet(ancestorNote.subtreeNotes).intersection(inputNoteSet);
const subTreeNoteSet = new NoteSet(ancestorNote.subtreeNotes).intersection(inputNoteSet);
if (!this.ancestorDepthComparator) {
return subTreeNoteSet;
}
const depthConformingNoteSet = new NoteSet([]);
for (const note of subTreeNoteSet.notes) {
const distance = note.getDistanceToAncestor(ancestorNote.noteId);
if (this.ancestorDepthComparator(distance)) {
depthConformingNoteSet.add(note);
}
}
return depthConformingNoteSet;
}
getComparator(depthCondition) {
if (!depthCondition) {
return null;
}
const comparedDepth = parseInt(depthCondition.substr(2));
if (depthCondition.startsWith("eq")) {
return depth => depth === comparedDepth;
}
else if (depthCondition.startsWith("gt")) {
return depth => depth > comparedDepth;
}
else if (depthCondition.startsWith("lt")) {
return depth => depth < comparedDepth;
}
else {
log.error(`Unrecognized depth condition value ${depthCondition}`);
return null;
}
}
}

View File

@ -4,6 +4,7 @@ class SearchContext {
constructor(params = {}) {
this.fastSearch = !!params.fastSearch;
this.ancestorNoteId = params.ancestorNoteId;
this.ancestorDepth = params.ancestorDepth;
this.includeArchivedNotes = !!params.includeArchivedNotes;
this.orderBy = params.orderBy;
this.orderDirection = params.orderDirection;

View File

@ -410,7 +410,7 @@ function getExpression(tokens, searchContext, level = 0) {
function parse({fulltextTokens, expressionTokens, searchContext}) {
let exp = AndExp.of([
searchContext.includeArchivedNotes ? null : new PropertyComparisonExp(searchContext, "isarchived", buildComparator("=", "false")),
searchContext.ancestorNoteId ? new AncestorExp(searchContext.ancestorNoteId) : null,
searchContext.ancestorNoteId ? new AncestorExp(searchContext.ancestorNoteId, searchContext.ancestorDepth) : null,
getFulltext(fulltextTokens, searchContext),
getExpression(expressionTokens, searchContext)
]);