mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 18:36:30 +01:00 
			
		
		
		
	fix setting mime after import + cleanup of old search code
This commit is contained in:
		| @@ -176,7 +176,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null, $contain | |||||||
|      * @returns {Promise<NoteShort[]>} |      * @returns {Promise<NoteShort[]>} | ||||||
|      */ |      */ | ||||||
|     this.searchForNotes = async searchString => { |     this.searchForNotes = async searchString => { | ||||||
|         const noteIds = await this.runOnServer(async searchString => { |         const noteIds = await this.runOnBackend(async searchString => { | ||||||
|             const notes = await api.searchForNotes(searchString); |             const notes = await api.searchForNotes(searchString); | ||||||
|  |  | ||||||
|             return notes.map(note => note.noteId); |             return notes.map(note => note.noteId); | ||||||
|   | |||||||
| @@ -127,7 +127,7 @@ class ImageTypeWidget extends TypeWidget { | |||||||
|  |  | ||||||
|         this.$widget.show(); |         this.$widget.show(); | ||||||
|  |  | ||||||
|         const noteComplement = await this.tabContext.getNoteComplement(); |         const noteComplement = await this.tabContext.getNoteComplement();console.log(noteComplement, note); | ||||||
|  |  | ||||||
|         this.$fileName.text(attributeMap.originalFileName || "?"); |         this.$fileName.text(attributeMap.originalFileName || "?"); | ||||||
|         this.$fileSize.text(noteComplement.contentLength + " bytes"); |         this.$fileSize.text(noteComplement.contentLength + " bytes"); | ||||||
|   | |||||||
| @@ -18,6 +18,7 @@ function updateFile(req) { | |||||||
|     noteRevisionService.createNoteRevision(note); |     noteRevisionService.createNoteRevision(note); | ||||||
|  |  | ||||||
|     note.mime = file.mimetype.toLowerCase(); |     note.mime = file.mimetype.toLowerCase(); | ||||||
|  |     note.save(); | ||||||
|  |  | ||||||
|     note.setContent(file.buffer); |     note.setContent(file.buffer); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,6 +25,8 @@ function getNote(req) { | |||||||
|  |  | ||||||
|     const contentMetadata = note.getContentMetadata(); |     const contentMetadata = note.getContentMetadata(); | ||||||
|  |  | ||||||
|  |     note.contentLength = contentMetadata.contentLength; | ||||||
|  |  | ||||||
|     note.combinedUtcDateModified = note.utcDateModified > contentMetadata.utcDateModified ? note.utcDateModified : contentMetadata.utcDateModified; |     note.combinedUtcDateModified = note.utcDateModified > contentMetadata.utcDateModified ? note.utcDateModified : contentMetadata.utcDateModified; | ||||||
|     note.combinedDateModified = note.utcDateModified > contentMetadata.utcDateModified ? note.dateModified : contentMetadata.dateModified; |     note.combinedDateModified = note.utcDateModified > contentMetadata.utcDateModified ? note.dateModified : contentMetadata.dateModified; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,158 +0,0 @@ | |||||||
| const utils = require('./utils'); |  | ||||||
|  |  | ||||||
| const VIRTUAL_ATTRIBUTES = [ |  | ||||||
|     "dateCreated", |  | ||||||
|     "dateModified", |  | ||||||
|     "utcDateCreated", |  | ||||||
|     "utcDateModified", |  | ||||||
|     "noteId", |  | ||||||
|     "isProtected", |  | ||||||
|     "title", |  | ||||||
|     "content", |  | ||||||
|     "type", |  | ||||||
|     "mime", |  | ||||||
|     "text", |  | ||||||
|     "parentCount" |  | ||||||
| ]; |  | ||||||
|  |  | ||||||
| module.exports = function(filters, selectedColumns = 'notes.*') { |  | ||||||
|     // alias => join |  | ||||||
|     const joins = { |  | ||||||
|         "notes": null |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     let attrFilterId = 1; |  | ||||||
|  |  | ||||||
|     function getAccessor(property) { |  | ||||||
|         let accessor; |  | ||||||
|  |  | ||||||
|         if (!VIRTUAL_ATTRIBUTES.includes(property)) { |  | ||||||
|             // not reusing existing filters to support multi-valued filters e.g. "@tag=christmas @tag=shopping" |  | ||||||
|             // can match notes because @tag can be both "shopping" and "christmas" |  | ||||||
|             const alias = "attr_" + property + "_" + attrFilterId++; |  | ||||||
|  |  | ||||||
|             // 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`; |  | ||||||
|  |  | ||||||
|             accessor = `${alias}.value`; |  | ||||||
|         } |  | ||||||
|         else if (property === 'content') { |  | ||||||
|             const alias = "note_contents"; |  | ||||||
|  |  | ||||||
|             if (!(alias in joins)) { |  | ||||||
|                 joins[alias] = `LEFT JOIN note_contents ON note_contents.noteId = notes.noteId`; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             accessor = `${alias}.${property}`; |  | ||||||
|         } |  | ||||||
|         else if (property === 'parentCount') { |  | ||||||
|             // need to cast as string for the equality operator to work |  | ||||||
|             // for >= etc. it is cast again to DECIMAL |  | ||||||
|             // also cannot use COUNT() in WHERE so using subquery ... |  | ||||||
|             accessor = `CAST((SELECT COUNT(1) FROM branches WHERE branches.noteId = notes.noteId AND isDeleted = 0) AS STRING)`; |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             accessor = "notes." + property; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return accessor; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     let orderBy = []; |  | ||||||
|  |  | ||||||
|     const orderByFilter = filters.find(filter => filter.name.toLowerCase() === 'orderby'); |  | ||||||
|  |  | ||||||
|     if (orderByFilter) { |  | ||||||
|         orderBy = orderByFilter.value.split(",").map(prop => { |  | ||||||
|             const direction = prop.includes("-") ? "DESC" : "ASC"; |  | ||||||
|             const cleanedProp = prop.trim().replace(/-/g, ""); |  | ||||||
|  |  | ||||||
|             return getAccessor(cleanedProp) + " " + direction; |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     let where = '1'; |  | ||||||
|     const params = []; |  | ||||||
|  |  | ||||||
|         for (const filter of filters) { |  | ||||||
|             if (['isarchived', 'in', 'orderby', 'limit'].includes(filter.name.toLowerCase())) { |  | ||||||
|                 continue; // these are not real filters |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         where += " " + filter.relation + " "; |  | ||||||
|  |  | ||||||
|             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} ?`; |  | ||||||
|                 params.push(filter.value); |  | ||||||
|             } else if (filter.operator === '*=' || filter.operator === '!*=') { |  | ||||||
|             where += `${accessor}` |  | ||||||
|                     + (filter.operator.includes('!') ? ' NOT' : '') |  | ||||||
|                     + ` LIKE ` + utils.prepareSqlForLike('%', filter.value, ''); |  | ||||||
|             } else if (filter.operator === '=*' || filter.operator === '!=*') { |  | ||||||
|             where += `${accessor}` |  | ||||||
|                     + (filter.operator.includes('!') ? ' NOT' : '') |  | ||||||
|                     + ` LIKE ` + utils.prepareSqlForLike('', filter.value, '%'); |  | ||||||
|             } else if (filter.operator === '*=*' || filter.operator === '!*=*') { |  | ||||||
|                 const columns = filter.name === 'text' ? [getAccessor("title"), getAccessor("content")] : [accessor]; |  | ||||||
|  |  | ||||||
|                 let condition = "(" + columns.map(column => |  | ||||||
|                     `${column}` + ` LIKE ` + utils.prepareSqlForLike('%', filter.value, '%')) |  | ||||||
|                     .join(" OR ") + ")"; |  | ||||||
|  |  | ||||||
|                 if (filter.operator.includes('!')) { |  | ||||||
|                     condition = "NOT(" + condition + ")"; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 if (['text', 'title', 'content'].includes(filter.name)) { |  | ||||||
|                     // for title/content search does not make sense to search for protected notes |  | ||||||
|                     condition = `(${condition} AND notes.isProtected = 0)`; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|             where += condition; |  | ||||||
|         } |  | ||||||
|         else if ([">", ">=", "<", "<="].includes(filter.operator)) { |  | ||||||
|                 let floatParam; |  | ||||||
|  |  | ||||||
|                 // from https://stackoverflow.com/questions/12643009/regular-expression-for-floating-point-numbers |  | ||||||
|                 if (/^[+-]?([0-9]*[.])?[0-9]+$/.test(filter.value)) { |  | ||||||
|                     floatParam = parseFloat(filter.value); |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 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} ?`; |  | ||||||
|                     params.push(filter.value); |  | ||||||
|                 } else { |  | ||||||
|                 where += `CAST(${accessor} AS DECIMAL) ${filter.operator} ?`; |  | ||||||
|                     params.push(floatParam); |  | ||||||
|                 } |  | ||||||
|             } else { |  | ||||||
|                 throw new Error("Unknown operator " + filter.operator); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     if (orderBy.length === 0) { |  | ||||||
|         // if no ordering is given then order at least by note title |  | ||||||
|         orderBy.push("notes.title"); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const query = `SELECT ${selectedColumns} FROM notes |  | ||||||
|             ${Object.values(joins).join('\r\n')} |  | ||||||
|               WHERE |  | ||||||
|                 notes.isDeleted = 0 |  | ||||||
|                 AND (${where}) |  | ||||||
|               GROUP BY notes.noteId |  | ||||||
|               ORDER BY ${orderBy.join(", ")}`; |  | ||||||
|  |  | ||||||
|     return { query, params }; |  | ||||||
| }; |  | ||||||
| @@ -15,7 +15,7 @@ const isSvg = require('is-svg'); | |||||||
| async function processImage(uploadBuffer, originalName, shrinkImageSwitch) { | async function processImage(uploadBuffer, originalName, shrinkImageSwitch) { | ||||||
|     const origImageFormat = getImageType(uploadBuffer); |     const origImageFormat = getImageType(uploadBuffer); | ||||||
|  |  | ||||||
|     if (origImageFormat && ["webp", "svg"].includes(origImageFormat.ext)) { |     if (origImageFormat && ["webp", "svg", "gif"].includes(origImageFormat.ext)) { | ||||||
|         // JIMP does not support webp at the moment: https://github.com/oliver-moran/jimp/issues/144 |         // JIMP does not support webp at the moment: https://github.com/oliver-moran/jimp/issues/144 | ||||||
|         shrinkImageSwitch = false; |         shrinkImageSwitch = false; | ||||||
|     } |     } | ||||||
| @@ -61,6 +61,8 @@ function updateImage(noteId, uploadBuffer, originalName) { | |||||||
|     processImage(uploadBuffer, originalName, true).then(({buffer, imageFormat}) => { |     processImage(uploadBuffer, originalName, true).then(({buffer, imageFormat}) => { | ||||||
|         sql.transactional(() => { |         sql.transactional(() => { | ||||||
|             note.mime = getImageMimeFromExtension(imageFormat.ext); |             note.mime = getImageMimeFromExtension(imageFormat.ext); | ||||||
|  |             note.save(); | ||||||
|  |  | ||||||
|             note.setContent(buffer); |             note.setContent(buffer); | ||||||
|         }) |         }) | ||||||
|     }); |     }); | ||||||
| @@ -88,6 +90,8 @@ function saveImage(parentNoteId, uploadBuffer, originalName, shrinkImageSwitch) | |||||||
|     processImage(uploadBuffer, originalName, shrinkImageSwitch).then(({buffer, imageFormat}) => { |     processImage(uploadBuffer, originalName, shrinkImageSwitch).then(({buffer, imageFormat}) => { | ||||||
|         sql.transactional(() => { |         sql.transactional(() => { | ||||||
|             note.mime = getImageMimeFromExtension(imageFormat.ext); |             note.mime = getImageMimeFromExtension(imageFormat.ext); | ||||||
|  |             note.save(); | ||||||
|  |  | ||||||
|             note.setContent(buffer); |             note.setContent(buffer); | ||||||
|         }) |         }) | ||||||
|     }); |     }); | ||||||
|   | |||||||
| @@ -105,7 +105,7 @@ function createNewNote(params) { | |||||||
|         throw new Error(`Note title must not be empty`); |         throw new Error(`Note title must not be empty`); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     sql.transactional(() => { |     return sql.transactional(() => { | ||||||
|         const note = new Note({ |         const note = new Note({ | ||||||
|             noteId: params.noteId, // optionally can force specific noteId |             noteId: params.noteId, // optionally can force specific noteId | ||||||
|             title: params.title, |             title: params.title, | ||||||
| @@ -744,8 +744,8 @@ function duplicateNote(noteId, parentNoteId) { | |||||||
|     const newNote = new Note(origNote); |     const newNote = new Note(origNote); | ||||||
|     newNote.noteId = undefined; // force creation of new note |     newNote.noteId = undefined; // force creation of new note | ||||||
|     newNote.title += " (dup)"; |     newNote.title += " (dup)"; | ||||||
|  |  | ||||||
|     newNote.save(); |     newNote.save(); | ||||||
|  |  | ||||||
|     newNote.setContent(origNote.getContent()); |     newNote.setContent(origNote.getContent()); | ||||||
|  |  | ||||||
|     const newBranch = new Branch({ |     const newBranch = new Branch({ | ||||||
|   | |||||||
| @@ -1,89 +0,0 @@ | |||||||
| "use strict"; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * Missing things from the OLD search: |  | ||||||
|  * - orderBy |  | ||||||
|  * - limit |  | ||||||
|  * - in - replaced with note.ancestors |  | ||||||
|  * - content in attribute search |  | ||||||
|  * - not - pherhaps not necessary |  | ||||||
|  * |  | ||||||
|  * other potential additions: |  | ||||||
|  * - targetRelations - either named or not |  | ||||||
|  * - any relation without name |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| const repository = require('./repository'); |  | ||||||
| const sql = require('./sql'); |  | ||||||
| const log = require('./log'); |  | ||||||
| const parseFilters = require('./search/parse_filters.js'); |  | ||||||
| const buildSearchQuery = require('./build_search_query'); |  | ||||||
| const noteCacheService = require('./note_cache/note_cache_service'); |  | ||||||
|  |  | ||||||
| function searchForNotes(searchString) { |  | ||||||
|     const noteIds = searchForNoteIds(searchString); |  | ||||||
|  |  | ||||||
|     return repository.getNotes(noteIds); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function searchForNoteIds(searchString) { |  | ||||||
|     const filters = parseFilters(searchString); |  | ||||||
|  |  | ||||||
|     const {query, params} = buildSearchQuery(filters, 'notes.noteId'); |  | ||||||
|  |  | ||||||
|     try { |  | ||||||
|         let noteIds = sql.getColumn(query, params); |  | ||||||
|  |  | ||||||
|         noteIds = noteIds.filter(noteCacheService.isAvailable); |  | ||||||
|  |  | ||||||
|         const isArchivedFilter = filters.find(filter => filter.name.toLowerCase() === 'isarchived'); |  | ||||||
|  |  | ||||||
|         if (isArchivedFilter) { |  | ||||||
|             if (isArchivedFilter.operator === 'exists') { |  | ||||||
|                 noteIds = noteIds.filter(noteCacheService.isArchived); |  | ||||||
|             } |  | ||||||
|             else if (isArchivedFilter.operator === 'not-exists') { |  | ||||||
|                 noteIds = noteIds.filter(noteId => !noteCacheService.isArchived(noteId)); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 throw new Error(`Unrecognized isArchived operator ${isArchivedFilter.operator}`); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const isInFilters = filters.filter(filter => filter.name.toLowerCase() === 'in'); |  | ||||||
|  |  | ||||||
|         for (const isInFilter of isInFilters) { |  | ||||||
|             if (isInFilter.operator === '=') { |  | ||||||
|                 noteIds = noteIds.filter(noteId => noteCacheService.isInAncestor(noteId, isInFilter.value)); |  | ||||||
|             } |  | ||||||
|             else if (isInFilter.operator === '!=') { |  | ||||||
|                 noteIds = noteIds.filter(noteId => !noteCacheService.isInAncestor(noteId, isInFilter.value)); |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 throw new Error(`Unrecognized isIn operator ${isInFilter.operator}`); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         const limitFilter = filters.find(filter => filter.name.toLowerCase() === 'limit'); |  | ||||||
|  |  | ||||||
|         if (limitFilter) { |  | ||||||
|             const limit = parseInt(limitFilter.value); |  | ||||||
|  |  | ||||||
|             return noteIds.splice(0, limit); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             return noteIds; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|     catch (e) { |  | ||||||
|         log.error("Search failed for " + query); |  | ||||||
|  |  | ||||||
|         throw e; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| module.exports = { |  | ||||||
|     searchForNotes, |  | ||||||
|     searchForNoteIds |  | ||||||
| }; |  | ||||||
| @@ -1,118 +0,0 @@ | |||||||
| const dayjs = require("dayjs"); |  | ||||||
|  |  | ||||||
| const filterRegex = /(\b(AND|OR)\s+)?@(!?)([\p{L}\p{Number}_]+|"[^"]+")\s*((=|!=|<|<=|>|>=|!?\*=|!?=\*|!?\*=\*)\s*([^\s=*"]+|"[^"]+"))?/igu; |  | ||||||
| const smartValueRegex = /^(NOW|TODAY|WEEK|MONTH|YEAR) *([+\-] *\d+)?$/i; |  | ||||||
|  |  | ||||||
| function calculateSmartValue(v) { |  | ||||||
|     const match = smartValueRegex.exec(v); |  | ||||||
|     if (match === null) { |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const keyword = match[1].toUpperCase(); |  | ||||||
|     const num = match[2] ? parseInt(match[2].replace(/ /g, "")) : 0; // can contain spaces between sign and digits |  | ||||||
|  |  | ||||||
|     let format, date; |  | ||||||
|  |  | ||||||
|     if (keyword === 'NOW') { |  | ||||||
|         date = dayjs().add(num, 'second'); |  | ||||||
|         format = "YYYY-MM-DD HH:mm:ss"; |  | ||||||
|     } |  | ||||||
|     else if (keyword === 'TODAY') { |  | ||||||
|         date = dayjs().add(num, 'day'); |  | ||||||
|         format = "YYYY-MM-DD"; |  | ||||||
|     } |  | ||||||
|     else if (keyword === 'WEEK') { |  | ||||||
|         // FIXME: this will always use sunday as start of the week |  | ||||||
|         date = dayjs().startOf('week').add(7 * num, 'day'); |  | ||||||
|         format = "YYYY-MM-DD"; |  | ||||||
|     } |  | ||||||
|     else if (keyword === 'MONTH') { |  | ||||||
|         date = dayjs().add(num, 'month'); |  | ||||||
|         format = "YYYY-MM"; |  | ||||||
|     } |  | ||||||
|     else if (keyword === 'YEAR') { |  | ||||||
|         date = dayjs().add(num, 'year'); |  | ||||||
|         format = "YYYY"; |  | ||||||
|     } |  | ||||||
|     else { |  | ||||||
|         throw new Error("Unrecognized keyword: " + keyword); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return date.format(format); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| module.exports = function (searchText) { |  | ||||||
|     searchText = searchText.trim(); |  | ||||||
|  |  | ||||||
|     // if the string doesn't start with attribute then we consider it as just standard full text search |  | ||||||
|     if (!searchText.startsWith("@")) { |  | ||||||
|         // replace with space instead of empty string since these characters are probably separators |  | ||||||
|         const filters = []; |  | ||||||
|  |  | ||||||
|         if (searchText.startsWith('"') && searchText.endsWith('"')) { |  | ||||||
|             // "bla bla" will search for exact match |  | ||||||
|             searchText = searchText.substr(1, searchText.length - 2); |  | ||||||
|  |  | ||||||
|             filters.push({ |  | ||||||
|                 relation: 'and', |  | ||||||
|                 name: 'text', |  | ||||||
|                 operator: '*=*', |  | ||||||
|                 value: searchText |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|             const tokens = searchText.split(/\s+/); |  | ||||||
|  |  | ||||||
|             for (const token of tokens) { |  | ||||||
|                 filters.push({ |  | ||||||
|                     relation: 'and', |  | ||||||
|                             name: 'text', |  | ||||||
|                             operator: '*=*', |  | ||||||
|                             value: token |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         filters.push({ |  | ||||||
|             relation: 'and', |  | ||||||
|             name: 'isArchived', |  | ||||||
|             operator: 'not-exists' |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         filters.push({ |  | ||||||
|             relation: 'or', |  | ||||||
|             name: 'noteId', |  | ||||||
|             operator: '=', |  | ||||||
|             value: searchText |  | ||||||
|         }); |  | ||||||
|  |  | ||||||
|         return filters; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     const filters = []; |  | ||||||
|  |  | ||||||
|     function trimQuotes(str) { return str.startsWith('"') ? str.substr(1, str.length - 2) : str; } |  | ||||||
|  |  | ||||||
|     let match; |  | ||||||
|  |  | ||||||
|     while (match = filterRegex.exec(searchText)) { |  | ||||||
|         const relation = match[2] !== undefined ? match[2].toLowerCase() : 'and'; |  | ||||||
|         const operator = match[3] === '!' ? 'not-exists' : 'exists'; |  | ||||||
|  |  | ||||||
|         const value = match[7] !== undefined ? trimQuotes(match[7]) : null; |  | ||||||
|  |  | ||||||
|         filters.push({ |  | ||||||
|             relation: relation, |  | ||||||
|             name: trimQuotes(match[4]), |  | ||||||
|             operator: match[6] !== undefined ? match[6] : operator, |  | ||||||
|             value: ( |  | ||||||
|                 value && value.match(smartValueRegex) |  | ||||||
|                     ? calculateSmartValue(value) |  | ||||||
|                     : value |  | ||||||
|             ) |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return filters; |  | ||||||
| }; |  | ||||||
		Reference in New Issue
	
	Block a user