mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 11:39:01 +01:00 
			
		
		
		
	server-ts: Port services/search/expressions/note_content_fulltext
This commit is contained in:
		
							parent
							
								
									3df6acda32
								
							
						
					
					
						commit
						414964e791
					
				| @ -106,6 +106,7 @@ export interface NoteRow { | |||||||
|     dateModified: string; |     dateModified: string; | ||||||
|     utcDateCreated: string; |     utcDateCreated: string; | ||||||
|     utcDateModified: string; |     utcDateModified: string; | ||||||
|  |     content?: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface AttributeRow { | export interface AttributeRow { | ||||||
|  | |||||||
| @ -1,18 +1,22 @@ | |||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
| const Expression = require('./expression'); | import { NoteRow } from "../../../becca/entities/rows"; | ||||||
| const NoteSet = require('../note_set'); | import SearchContext = require("../search_context"); | ||||||
| const log = require('../../log'); | 
 | ||||||
| const becca = require('../../../becca/becca'); | import Expression = require('./expression'); | ||||||
| const protectedSessionService = require('../../protected_session'); | import NoteSet = require('../note_set'); | ||||||
| const striptags = require('striptags'); | import log = require('../../log'); | ||||||
| const utils = require('../../utils'); | import becca = require('../../../becca/becca'); | ||||||
|  | import protectedSessionService = require('../../protected_session'); | ||||||
|  | import striptags = require('striptags'); | ||||||
|  | import utils = require('../../utils'); | ||||||
|  | import sql = require("../../sql"); | ||||||
| 
 | 
 | ||||||
| const ALLOWED_OPERATORS = ['=', '!=', '*=*', '*=', '=*', '%=']; | const ALLOWED_OPERATORS = ['=', '!=', '*=*', '*=', '=*', '%=']; | ||||||
| 
 | 
 | ||||||
| const cachedRegexes = {}; | const cachedRegexes: Record<string, RegExp> = {}; | ||||||
| 
 | 
 | ||||||
| function getRegex(str) { | function getRegex(str: string): RegExp { | ||||||
|     if (!(str in cachedRegexes)) { |     if (!(str in cachedRegexes)) { | ||||||
|         cachedRegexes[str] = new RegExp(str, 'ms'); // multiline, dot-all
 |         cachedRegexes[str] = new RegExp(str, 'ms'); // multiline, dot-all
 | ||||||
|     } |     } | ||||||
| @ -20,8 +24,22 @@ function getRegex(str) { | |||||||
|     return cachedRegexes[str]; |     return cachedRegexes[str]; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | interface ConstructorOpts { | ||||||
|  |     tokens: string[]; | ||||||
|  |     raw: boolean; | ||||||
|  |     flatText: boolean; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type SearchRow = Pick<NoteRow, "noteId" | "type" | "mime" | "content" | "isProtected">; | ||||||
|  | 
 | ||||||
| class NoteContentFulltextExp extends Expression { | class NoteContentFulltextExp extends Expression { | ||||||
|     constructor(operator, {tokens, raw, flatText}) { | 
 | ||||||
|  |     private operator: string; | ||||||
|  |     private tokens: string[]; | ||||||
|  |     private raw: boolean; | ||||||
|  |     private flatText: boolean; | ||||||
|  |      | ||||||
|  |     constructor(operator: string, {tokens, raw, flatText}: ConstructorOpts) { | ||||||
|         super(); |         super(); | ||||||
| 
 | 
 | ||||||
|         this.operator = operator; |         this.operator = operator; | ||||||
| @ -30,7 +48,7 @@ class NoteContentFulltextExp extends Expression { | |||||||
|         this.flatText = !!flatText; |         this.flatText = !!flatText; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     execute(inputNoteSet, executionContext, searchContext) { |     execute(inputNoteSet: NoteSet, executionContext: {}, searchContext: SearchContext) { | ||||||
|         if (!ALLOWED_OPERATORS.includes(this.operator)) { |         if (!ALLOWED_OPERATORS.includes(this.operator)) { | ||||||
|             searchContext.addError(`Note content can be searched only with operators: ${ALLOWED_OPERATORS.join(", ")}, operator ${this.operator} given.`); |             searchContext.addError(`Note content can be searched only with operators: ${ALLOWED_OPERATORS.join(", ")}, operator ${this.operator} given.`); | ||||||
| 
 | 
 | ||||||
| @ -38,9 +56,8 @@ class NoteContentFulltextExp extends Expression { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const resultNoteSet = new NoteSet(); |         const resultNoteSet = new NoteSet(); | ||||||
|         const sql = require('../../sql'); |          | ||||||
| 
 |         for (const row of sql.iterateRows<SearchRow>(` | ||||||
|         for (const row of sql.iterateRows(` |  | ||||||
|                 SELECT noteId, type, mime, content, isProtected |                 SELECT noteId, type, mime, content, isProtected | ||||||
|                 FROM notes JOIN blobs USING (blobId)  |                 FROM notes JOIN blobs USING (blobId)  | ||||||
|                 WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) {
 |                 WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0`)) {
 | ||||||
| @ -51,18 +68,18 @@ class NoteContentFulltextExp extends Expression { | |||||||
|         return resultNoteSet; |         return resultNoteSet; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     findInText({noteId, isProtected, content, type, mime}, inputNoteSet, resultNoteSet) { |     findInText({noteId, isProtected, content, type, mime}: SearchRow, inputNoteSet: NoteSet, resultNoteSet: NoteSet) { | ||||||
|         if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) { |         if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (isProtected) { |         if (isProtected) { | ||||||
|             if (!protectedSessionService.isProtectedSessionAvailable()) { |             if (!protectedSessionService.isProtectedSessionAvailable() || !content) { | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             try { |             try { | ||||||
|                 content = protectedSessionService.decryptString(content); |                 content = protectedSessionService.decryptString(content) || undefined; | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 log.info(`Cannot decrypt content of note ${noteId}`); |                 log.info(`Cannot decrypt content of note ${noteId}`); | ||||||
|                 return; |                 return; | ||||||
| @ -89,7 +106,7 @@ class NoteContentFulltextExp extends Expression { | |||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             const nonMatchingToken = this.tokens.find(token => |             const nonMatchingToken = this.tokens.find(token => | ||||||
|                 !content.includes(token) && |                 !content?.includes(token) && | ||||||
|                 ( |                 ( | ||||||
|                     // in case of default fulltext search, we should consider both title, attrs and content
 |                     // in case of default fulltext search, we should consider both title, attrs and content
 | ||||||
|                     // so e.g. "hello world" should match when "hello" is in title and "world" in content
 |                     // so e.g. "hello world" should match when "hello" is in title and "world" in content
 | ||||||
| @ -106,7 +123,7 @@ class NoteContentFulltextExp extends Expression { | |||||||
|         return content; |         return content; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     preprocessContent(content, type, mime) { |     preprocessContent(content: string, type: string, mime: string) { | ||||||
|         content = utils.normalize(content.toString()); |         content = utils.normalize(content.toString()); | ||||||
| 
 | 
 | ||||||
|         if (type === 'text' && mime === 'text/html') { |         if (type === 'text' && mime === 'text/html') { | ||||||
| @ -125,4 +142,4 @@ class NoteContentFulltextExp extends Expression { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| module.exports = NoteContentFulltextExp; | export = NoteContentFulltextExp; | ||||||
| @ -12,7 +12,7 @@ const PropertyComparisonExp = require('../expressions/property_comparison.js'); | |||||||
| const AttributeExistsExp = require('../expressions/attribute_exists'); | const AttributeExistsExp = require('../expressions/attribute_exists'); | ||||||
| const LabelComparisonExp = require('../expressions/label_comparison'); | const LabelComparisonExp = require('../expressions/label_comparison'); | ||||||
| const NoteFlatTextExp = require('../expressions/note_flat_text.js'); | const NoteFlatTextExp = require('../expressions/note_flat_text.js'); | ||||||
| const NoteContentFulltextExp = require('../expressions/note_content_fulltext.js'); | const NoteContentFulltextExp = require('../expressions/note_content_fulltext'); | ||||||
| const OrderByAndLimitExp = require('../expressions/order_by_and_limit.js'); | const OrderByAndLimitExp = require('../expressions/order_by_and_limit.js'); | ||||||
| const AncestorExp = require('../expressions/ancestor'); | const AncestorExp = require('../expressions/ancestor'); | ||||||
| const buildComparator = require('./build_comparator.js'); | const buildComparator = require('./build_comparator.js'); | ||||||
|  | |||||||
| @ -147,12 +147,12 @@ function getRawRows<T extends {} | unknown[]>(query: string, params: Params = [] | |||||||
|     return (wrap(query, s => s.raw().all(params)) as T[] | null) || []; |     return (wrap(query, s => s.raw().all(params)) as T[] | null) || []; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function iterateRows(query: string, params: Params = []) { | function iterateRows<T>(query: string, params: Params = []): IterableIterator<T> { | ||||||
|     if (LOG_ALL_QUERIES) { |     if (LOG_ALL_QUERIES) { | ||||||
|         console.log(query); |         console.log(query); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return stmt(query).iterate(params); |     return stmt(query).iterate(params) as IterableIterator<T>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getMap<K extends string | number | symbol, V>(query: string, params: Params = []) { | function getMap<K extends string | number | symbol, V>(query: string, params: Params = []) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran