fallback to search query if implicit fields are in the filter

This commit is contained in:
Hongbo Wu 2024-03-26 17:34:57 +08:00
parent 37459f64c7
commit 4c458c7118
2 changed files with 44 additions and 34 deletions

View file

@ -1,10 +1,13 @@
import { LiqeQuery } from '@omnivore/liqe'
import { ReadingProgressDataSource } from '../datasources/reading_progress_data_source'
import { LibraryItemState } from '../entity/library_item'
import { LibraryItem, LibraryItemState } from '../entity/library_item'
import { Rule, RuleAction, RuleActionType, RuleEventType } from '../entity/rule'
import { addLabelsToLibraryItem } from '../services/labels'
import {
filterItemEvents,
ItemEvent,
RequiresSearchQueryError,
searchLibraryItems,
softDeleteLibraryItem,
updateLibraryItem,
} from '../services/library_item'
@ -24,7 +27,7 @@ interface RuleActionObj {
libraryItemId: string
userId: string
action: RuleAction
data: ItemEvent
data: ItemEvent | LibraryItem
}
type RuleActionFunc = (obj: RuleActionObj) => Promise<unknown>
@ -107,33 +110,52 @@ const triggerActions = async (
const actionPromises: Promise<unknown>[] = []
for (const rule of rules) {
let filteredData: ItemEvent
let ast: LiqeQuery
let results: (ItemEvent | LibraryItem)[]
try {
const ast = parseSearchQuery(rule.filter)
// filter library item by rule filter
const results = filterItemEvents(ast, [data])
if (results.length === 0) {
logger.info(`No items found for rule ${rule.id}`)
continue
}
filteredData = results[0]
ast = parseSearchQuery(rule.filter)
} catch (error) {
// failed to search for library items, mark rule as failed
logger.error('Error parsing filter in rules', error)
await markRuleAsFailed(rule.id, userId)
continue
}
// filter library item by metadata
try {
results = filterItemEvents(ast, [data])
} catch (error) {
if (error instanceof RequiresSearchQueryError) {
logger.info('Failed to filter items by metadata, running search query')
// failed to filter items by metadata, run search query
const searchResult = await searchLibraryItems(
{
query: `includes: ${libraryItemId} AND (${rule.filter})`,
size: 1,
},
userId
)
results = searchResult.libraryItems
} else {
logger.error('Error filtering item events', error)
await markRuleAsFailed(rule.id, userId)
continue
}
}
if (results.length === 0) {
logger.info(`No items found for rule ${rule.id}`)
continue
}
for (const action of rule.actions) {
const actionFunc = getRuleAction(action.type)
const actionObj: RuleActionObj = {
libraryItemId,
userId,
action,
data: filteredData,
data: results[0],
}
actionPromises.push(actionFunc(actionObj))

View file

@ -43,6 +43,12 @@ export type UpdateItemEvent = Omit<
IgnoredFields
>
export class RequiresSearchQueryError extends Error {
constructor() {
super('Requires a search query')
}
}
enum ReadFilter {
ALL = 'all',
READ = 'read',
@ -1328,7 +1334,7 @@ export const findLibraryItemIdsByLabelId = async (
export const filterItemEvents = (
ast: LiqeQuery,
events: readonly ItemEvent[]
): readonly ItemEvent[] => {
): ItemEvent[] => {
const testNo = (value: string, event: ItemEvent) => {
const keywordRegexMap: Record<string, RegExp> = {
highlightAnnotations: /^highlight(s)?$/i,
@ -1364,25 +1370,7 @@ export const filterItemEvents = (
const lowercasedValue = expression.value?.toString().toLowerCase()
if (field.type === 'ImplicitField') {
if (!lowercasedValue) {
return true
}
const textFields = [
'author',
'title',
'description',
'note',
'siteName',
'readableContent',
'originalUrl',
]
const text = textFields
.map((field) => event[field as keyof ItemEvent])
.join(' ')
// TODO: Implement full text search
return text.match(new RegExp(lowercasedValue, 'i'))
throw new RequiresSearchQueryError()
}
if (!lowercasedValue) {