mirror of
https://github.com/zadam/trilium.git
synced 2025-03-04 19:13:37 +08:00
add possibility to debug search queries by logging expression tree, #1655
This commit is contained in:
parent
0c9a11db6f
commit
859465841d
9 changed files with 65 additions and 14 deletions
35
src/public/app/widgets/search_options/debug.js
Normal file
35
src/public/app/widgets/search_options/debug.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
import AbstractSearchOption from "./abstract_search_option.js";
|
||||
|
||||
const TPL = `
|
||||
<tr data-search-option-conf="debug">
|
||||
<td colSpan="2">
|
||||
<span class="bx bx-bug"></span>
|
||||
|
||||
Debug
|
||||
</td>
|
||||
<td class="button-column">
|
||||
<div class="dropdown help-dropdown">
|
||||
<span class="bx bx-help-circle icon-action" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></span>
|
||||
<div class="dropdown-menu dropdown-menu-right p-4">
|
||||
<p>Debug will print extra debugging information into the console to aid in debugging complex queries.</p>
|
||||
|
||||
<p>To access the debug information, execute query and click on "Show backend log" in top left corner.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="bx bx-x icon-action search-option-del"></span>
|
||||
</td>
|
||||
</tr>`;
|
||||
|
||||
export default class Debug extends AbstractSearchOption {
|
||||
static get optionName() { return "debug" };
|
||||
static get attributeType() { return "label" };
|
||||
|
||||
static async create(noteId) {
|
||||
await AbstractSearchOption.setAttribute(noteId,'label', 'debug');
|
||||
}
|
||||
|
||||
doRender() {
|
||||
return $(TPL);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ import OrderBy from "../search_options/order_by.js";
|
|||
import SearchScript from "../search_options/search_script.js";
|
||||
import Limit from "../search_options/limit.js";
|
||||
import DeleteNoteRevisionsSearchAction from "../search_actions/delete_note_revisions.js";
|
||||
import Debug from "../search_options/debug.js";
|
||||
|
||||
const TPL = `
|
||||
<div class="search-definition-widget">
|
||||
|
@ -113,6 +114,11 @@ const TPL = `
|
|||
limit
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-sm" data-search-option-add="debug" title="Debug will print extra debugging information into the console to aid in debugging complex queries">
|
||||
<span class="bx bx-bug"></span>
|
||||
debug
|
||||
</button>
|
||||
|
||||
<div class="dropdown" style="display: inline-block;">
|
||||
<button class="btn btn-sm dropdown-toggle action-add-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<span class="bx bxs-zap"></span>
|
||||
|
@ -173,7 +179,8 @@ const OPTION_CLASSES = [
|
|||
FastSearch,
|
||||
IncludeArchivedNotes,
|
||||
OrderBy,
|
||||
Limit
|
||||
Limit,
|
||||
Debug
|
||||
];
|
||||
|
||||
const ACTION_CLASSES = {};
|
||||
|
|
|
@ -24,6 +24,7 @@ async function search(note) {
|
|||
orderBy: note.getLabelValue('orderBy'),
|
||||
orderDirection: note.getLabelValue('orderDirection'),
|
||||
limit: note.getLabelValue('limit'),
|
||||
debug: note.hasLabel('debug'),
|
||||
fuzzyAttributeSearch: false
|
||||
});
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ class AncestorExp extends Expression {
|
|||
super();
|
||||
|
||||
this.ancestorNoteId = ancestorNoteId;
|
||||
this.ancestorDepth = ancestorDepth; // for DEBUG mode
|
||||
this.ancestorDepthComparator = this.getComparator(ancestorDepth);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
"use strict";
|
||||
|
||||
class Expression {
|
||||
constructor() {
|
||||
this.name = this.constructor.name; // for DEBUG mode to have expression name as part of dumped JSON
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NoteSet} inputNoteSet
|
||||
* @param {object} executionContext
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const Expression = require('./expression');
|
||||
const NoteSet = require('../note_set');
|
||||
const buildComparator = require("../services/build_comparator.js");
|
||||
|
||||
/**
|
||||
* Search string is lower cased for case insensitive comparison. But when retrieving properties
|
||||
|
@ -33,11 +34,13 @@ class PropertyComparisonExp extends Expression {
|
|||
return name in PROP_MAPPING;
|
||||
}
|
||||
|
||||
constructor(searchContext, propertyName, comparator) {
|
||||
constructor(searchContext, propertyName, operator, comparedValue) {
|
||||
super();
|
||||
|
||||
this.propertyName = PROP_MAPPING[propertyName];
|
||||
this.comparator = comparator;
|
||||
this.operator = operator; // for DEBUG mode
|
||||
this.comparedValue = comparedValue; // for DEBUG mode
|
||||
this.comparator = buildComparator(operator, comparedValue);
|
||||
|
||||
if (['contentsize', 'notesize', 'revisioncount'].includes(this.propertyName)) {
|
||||
searchContext.dbLoadNeeded = true;
|
||||
|
|
|
@ -11,6 +11,7 @@ class SearchContext {
|
|||
this.orderBy = params.orderBy;
|
||||
this.orderDirection = params.orderDirection;
|
||||
this.limit = params.limit;
|
||||
this.debug = params.debug;
|
||||
this.fuzzyAttributeSearch = !!params.fuzzyAttributeSearch;
|
||||
this.highlightedTokens = [];
|
||||
this.originalQuery = "";
|
||||
|
|
|
@ -194,7 +194,7 @@ function getExpression(tokens, searchContext, level = 0) {
|
|||
i += 2;
|
||||
|
||||
return new OrExp([
|
||||
new PropertyComparisonExp(searchContext, 'title', buildComparator('*=*', tokens[i].token)),
|
||||
new PropertyComparisonExp(searchContext, 'title', '*=*', tokens[i].token),
|
||||
new NoteContentProtectedFulltextExp('*=*', [tokens[i].token]),
|
||||
new NoteContentUnprotectedFulltextExp('*=*', [tokens[i].token])
|
||||
]);
|
||||
|
@ -208,14 +208,7 @@ function getExpression(tokens, searchContext, level = 0) {
|
|||
|
||||
const comparedValue = resolveConstantOperand();
|
||||
|
||||
const comparator = buildComparator(operator, comparedValue);
|
||||
|
||||
if (!comparator) {
|
||||
searchContext.addError(`Can't find operator '${operator}' in ${context(i - 2)}`);
|
||||
return;
|
||||
}
|
||||
|
||||
return new PropertyComparisonExp(searchContext, propertyName, comparator);
|
||||
return new PropertyComparisonExp(searchContext, propertyName, operator, comparedValue);
|
||||
}
|
||||
|
||||
searchContext.addError(`Unrecognized note property "${tokens[i].token}" in ${context(i)}`);
|
||||
|
@ -411,8 +404,8 @@ 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, searchContext.ancestorDepth) : null,
|
||||
searchContext.includeArchivedNotes ? null : new PropertyComparisonExp(searchContext, "isarchived", "=", "false"),
|
||||
(searchContext.ancestorNoteId && searchContext.ancestorNoteId !== 'root') ? new AncestorExp(searchContext.ancestorNoteId, searchContext.ancestorDepth) : null,
|
||||
getFulltext(fulltextTokens, searchContext),
|
||||
getExpression(expressionTokens, searchContext)
|
||||
]);
|
||||
|
|
|
@ -127,6 +127,12 @@ function parseQueryToExpression(query, searchContext) {
|
|||
originalQuery: query
|
||||
});
|
||||
|
||||
if (searchContext.debug) {
|
||||
log.info(`Fulltext tokens: ` + JSON.stringify(fulltextTokens));
|
||||
log.info(`Expression tokens: ` + JSON.stringify(structuredExpressionTokens, null, 4));
|
||||
log.info("Expression tree: " + JSON.stringify(expression, null, 4));
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue