mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 05:28:59 +01:00 
			
		
		
		
	default search should look also into attribute names and values, #980
This commit is contained in:
		
							parent
							
								
									32020d78b5
								
							
						
					
					
						commit
						87a1e98fa2
					
				@ -12,7 +12,9 @@ const VIRTUAL_ATTRIBUTES = [
 | 
			
		||||
    "type",
 | 
			
		||||
    "mime",
 | 
			
		||||
    "text",
 | 
			
		||||
    "parentCount"
 | 
			
		||||
    "parentCount",
 | 
			
		||||
    "attributeName",
 | 
			
		||||
    "attributeValue"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
module.exports = function(filters, selectedColumns = 'notes.*') {
 | 
			
		||||
@ -33,11 +35,29 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
 | 
			
		||||
 | 
			
		||||
            // forcing to use particular index since SQLite query planner would often choose something pretty bad
 | 
			
		||||
            joins[alias] = `LEFT JOIN attributes AS ${alias} INDEXED BY IDX_attributes_noteId_index `
 | 
			
		||||
                + `ON ${alias}.noteId = notes.noteId `
 | 
			
		||||
                + `AND ${alias}.name = '${property}' AND ${alias}.isDeleted = 0`;
 | 
			
		||||
                + `ON ${alias}.noteId = notes.noteId AND ${alias}.isDeleted = 0`
 | 
			
		||||
                + `AND ${alias}.name = '${property}' `;
 | 
			
		||||
 | 
			
		||||
            accessor = `${alias}.value`;
 | 
			
		||||
        }
 | 
			
		||||
        else if (['attributeType', 'attributeName', 'attributeValue'].includes(property)) {
 | 
			
		||||
            const alias = "attr_filter";
 | 
			
		||||
 | 
			
		||||
            if (!(alias in joins)) {
 | 
			
		||||
                joins[alias] = `LEFT JOIN attributes AS ${alias} INDEXED BY IDX_attributes_noteId_index `
 | 
			
		||||
                    + `ON ${alias}.noteId = notes.noteId AND ${alias}.isDeleted = 0`;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (property === 'attributeType') {
 | 
			
		||||
                accessor = `${alias}.type`
 | 
			
		||||
            } else if (property === 'attributeName') {
 | 
			
		||||
                accessor = `${alias}.name`
 | 
			
		||||
            } else if (property === 'attributeValue') {
 | 
			
		||||
                accessor = `${alias}.value`
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new Error(`Unrecognized property ${property}`);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else if (property === 'content') {
 | 
			
		||||
            const alias = "note_contents";
 | 
			
		||||
 | 
			
		||||
@ -73,39 +93,43 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let where = '1';
 | 
			
		||||
    const params = [];
 | 
			
		||||
 | 
			
		||||
    function parseWhereFilters(filters) {
 | 
			
		||||
        let whereStmt = '';
 | 
			
		||||
 | 
			
		||||
        for (const filter of filters) {
 | 
			
		||||
            if (['isarchived', 'in', 'orderby', 'limit'].includes(filter.name.toLowerCase())) {
 | 
			
		||||
                continue; // these are not real filters
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        where += " " + filter.relation + " ";
 | 
			
		||||
            if (whereStmt) {
 | 
			
		||||
                whereStmt += " " + filter.relation + " ";
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (filter.children) {
 | 
			
		||||
                whereStmt += "(" + parseWhereFilters(filter.children) + ")";
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const accessor = getAccessor(filter.name);
 | 
			
		||||
 | 
			
		||||
            if (filter.operator === 'exists') {
 | 
			
		||||
            where += `${accessor} IS NOT NULL`;
 | 
			
		||||
        }
 | 
			
		||||
        else if (filter.operator === 'not-exists') {
 | 
			
		||||
            where += `${accessor} IS NULL`;
 | 
			
		||||
        }
 | 
			
		||||
        else if (filter.operator === '=' || filter.operator === '!=') {
 | 
			
		||||
            where += `${accessor} ${filter.operator} ?`;
 | 
			
		||||
                whereStmt += `${accessor} IS NOT NULL`;
 | 
			
		||||
            } else if (filter.operator === 'not-exists') {
 | 
			
		||||
                whereStmt += `${accessor} IS NULL`;
 | 
			
		||||
            } else if (filter.operator === '=' || filter.operator === '!=') {
 | 
			
		||||
                whereStmt += `${accessor} ${filter.operator} ?`;
 | 
			
		||||
                params.push(filter.value);
 | 
			
		||||
        }
 | 
			
		||||
        else if (filter.operator === '*=' || filter.operator === '!*=') {
 | 
			
		||||
            where += `${accessor}`
 | 
			
		||||
            } else if (filter.operator === '*=' || filter.operator === '!*=') {
 | 
			
		||||
                whereStmt += `${accessor}`
 | 
			
		||||
                    + (filter.operator.includes('!') ? ' NOT' : '')
 | 
			
		||||
                    + ` LIKE ` + utils.prepareSqlForLike('%', filter.value, '');
 | 
			
		||||
        }
 | 
			
		||||
        else if (filter.operator === '=*' || filter.operator === '!=*') {
 | 
			
		||||
            where += `${accessor}`
 | 
			
		||||
            } else if (filter.operator === '=*' || filter.operator === '!=*') {
 | 
			
		||||
                whereStmt += `${accessor}`
 | 
			
		||||
                    + (filter.operator.includes('!') ? ' NOT' : '')
 | 
			
		||||
                    + ` LIKE ` + utils.prepareSqlForLike('', filter.value, '%');
 | 
			
		||||
        }
 | 
			
		||||
        else if (filter.operator === '*=*' || filter.operator === '!*=*') {
 | 
			
		||||
            } else if (filter.operator === '*=*' || filter.operator === '!*=*') {
 | 
			
		||||
                const columns = filter.name === 'text' ? [getAccessor("title"), getAccessor("content")] : [accessor];
 | 
			
		||||
 | 
			
		||||
                let condition = "(" + columns.map(column =>
 | 
			
		||||
@ -121,9 +145,8 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
 | 
			
		||||
                    condition = `(${condition} AND notes.isProtected = 0)`;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            where += condition;
 | 
			
		||||
        }
 | 
			
		||||
        else if ([">", ">=", "<", "<="].includes(filter.operator)) {
 | 
			
		||||
                whereStmt += condition;
 | 
			
		||||
            } else if ([">", ">=", "<", "<="].includes(filter.operator)) {
 | 
			
		||||
                let floatParam;
 | 
			
		||||
 | 
			
		||||
                // from https://stackoverflow.com/questions/12643009/regular-expression-for-floating-point-numbers
 | 
			
		||||
@ -133,19 +156,22 @@ module.exports = function(filters, selectedColumns = 'notes.*') {
 | 
			
		||||
 | 
			
		||||
                if (floatParam === undefined || isNaN(floatParam)) {
 | 
			
		||||
                    // if the value can't be parsed as float then we assume that string comparison should be used instead of numeric
 | 
			
		||||
                where += `${accessor} ${filter.operator} ?`;
 | 
			
		||||
                    whereStmt += `${accessor} ${filter.operator} ?`;
 | 
			
		||||
                    params.push(filter.value);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                where += `CAST(${accessor} AS DECIMAL) ${filter.operator} ?`;
 | 
			
		||||
                } else {
 | 
			
		||||
                    whereStmt += `CAST(${accessor} AS DECIMAL) ${filter.operator} ?`;
 | 
			
		||||
                    params.push(floatParam);
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new Error("Unknown operator " + filter.operator);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return whereStmt;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const where = parseWhereFilters(filters);
 | 
			
		||||
 | 
			
		||||
    if (orderBy.length === 0) {
 | 
			
		||||
        // if no ordering is given then order at least by note title
 | 
			
		||||
        orderBy.push("notes.title");
 | 
			
		||||
 | 
			
		||||
@ -60,6 +60,20 @@ module.exports = function (searchText) {
 | 
			
		||||
                operator: '*=*',
 | 
			
		||||
                value: searchText
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            filters.push({
 | 
			
		||||
                relation: 'or',
 | 
			
		||||
                name: 'attributeName',
 | 
			
		||||
                operator: '*=*',
 | 
			
		||||
                value: searchText
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            filters.push({
 | 
			
		||||
                relation: 'or',
 | 
			
		||||
                name: 'attributeValue',
 | 
			
		||||
                operator: '*=*',
 | 
			
		||||
                value: searchText
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            const tokens = searchText.split(/\s+/);
 | 
			
		||||
@ -67,9 +81,27 @@ module.exports = function (searchText) {
 | 
			
		||||
            for (const token of tokens) {
 | 
			
		||||
                filters.push({
 | 
			
		||||
                    relation: 'and',
 | 
			
		||||
                    name: 'sub',
 | 
			
		||||
                    children: [
 | 
			
		||||
                        {
 | 
			
		||||
                            relation: 'or',
 | 
			
		||||
                            name: 'text',
 | 
			
		||||
                            operator: '*=*',
 | 
			
		||||
                            value: token
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            relation: 'or',
 | 
			
		||||
                            name: 'attributeName',
 | 
			
		||||
                            operator: '*=*',
 | 
			
		||||
                            value: token
 | 
			
		||||
                        },
 | 
			
		||||
                        {
 | 
			
		||||
                            relation: 'or',
 | 
			
		||||
                            name: 'attributeValue',
 | 
			
		||||
                            operator: '*=*',
 | 
			
		||||
                            value: token
 | 
			
		||||
                        }
 | 
			
		||||
                    ]
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user