trilium/src/services/search/value_extractor.js
2020-12-15 15:09:00 +01:00

114 lines
3.4 KiB
JavaScript

"use strict";
/**
* Search string is lower cased for case insensitive comparison. But when retrieving properties
* we need case sensitive form so we have this translation object.
*/
const PROP_MAPPING = {
"noteid": "noteId",
"title": "title",
"type": "type",
"mime": "mime",
"isprotected": "isProtected",
"isarchived": "isArchived",
"datecreated": "dateCreated",
"datemodified": "dateModified",
"utcdatecreated": "utcDateCreated",
"utcdatemodified": "utcDateModified",
"parentcount": "parentCount",
"childrencount": "childrenCount",
"attributecount": "attributeCount",
"labelcount": "labelCount",
"relationcount": "relationCount"
};
class ValueExtractor {
constructor(propertyPath) {
this.propertyPath = propertyPath.map(pathEl => pathEl.toLowerCase());
if (this.propertyPath[0].startsWith('#')) {
this.propertyPath = ['note', 'labels', this.propertyPath[0].substr(1), ...this.propertyPath.slice( 1, this.propertyPath.length)];
}
else if (this.propertyPath[0].startsWith('~')) {
this.propertyPath = ['note', 'relations', this.propertyPath[0].substr(1), ...this.propertyPath.slice( 1, this.propertyPath.length)];
}
}
validate() {
if (this.propertyPath[0] !== 'note') {
return `property specifier must start with 'note', but starts with '${this.propertyPath[0]}'`;
}
for (let i = 1; i < this.propertyPath.length; i++) {
const pathEl = this.propertyPath[i];
if (pathEl === 'labels') {
if (i !== this.propertyPath.length - 2) {
return `label is a terminal property specifier and must be at the end`;
}
i++;
}
else if (pathEl === 'relations') {
if (i >= this.propertyPath.length - 2) {
return `relation name or property name is missing`;
}
i++;
}
else if (pathEl in PROP_MAPPING) {
if (i !== this.propertyPath.length - 1) {
return `${pathEl} is a terminal property specifier and must be at the end`;
}
}
else if (!["parents", "children"].includes(pathEl)) {
return `Unrecognized property specifier ${pathEl}`;
}
}
}
extract(note) {
let cursor = note;
let i;
const cur = () => this.propertyPath[i];
for (i = 0; i < this.propertyPath.length; i++) {
if (!cursor) {
return cursor;
}
if (cur() === 'labels') {
i++;
const attr = cursor.getAttributeCaseInsensitive('label', cur());
return attr ? attr.value : null;
}
if (cur() === 'relations') {
i++;
const attr = cursor.getAttributeCaseInsensitive('relation', cur());
cursor = attr ? attr.targetNote : null;
}
else if (cur() === 'parents') {
cursor = cursor.parents[0];
}
else if (cur() === 'children') {
cursor = cursor.children[0];
}
else if (cur() in PROP_MAPPING) {
return cursor[PROP_MAPPING[cur()]];
}
else {
// FIXME
}
}
}
}
module.exports = ValueExtractor;