import type { Query as PiniaOrmQuery } from 'pinia-orm' import type { Ref } from 'vue' import type { ApiFilter } from '~/types/data' import type ApiResource from '~/models/ApiResource' import { SEARCH_STRATEGY } from '~/types/enum/data' import AbstractFilter from '~/services/data/Filters/AbstractFilter' import RefUtils from '~/services/utils/refUtils' export default class SearchFilter extends AbstractFilter implements ApiFilter { field: string filterValue: Ref mode: SEARCH_STRATEGY /** * @param field * @param value * @param mode The 'search' strategy (exact [default], partial, start, end, word_start). * This strategy is defined API-side, but PiniaOrm needs to know how to handle this. * @see https://api-platform.com/docs/core/filters/ * @param reactiveFilter */ constructor( field: string, value: Ref, mode: SEARCH_STRATEGY = SEARCH_STRATEGY.EXACT, reactiveFilter: boolean = false, ) { super(reactiveFilter) this.field = field this.filterValue = value this.mode = mode } protected search(value: string, filterValue: Ref): boolean { if (filterValue.value === null || filterValue.value === '') { return false } let wordStartRx: RegExp | null = null if (this.mode === SEARCH_STRATEGY.WORD_START) { wordStartRx = new RegExp( `^${filterValue.value}|\\s${filterValue.value}`, 'i', ) } if (this.mode === SEARCH_STRATEGY.EXACT) { return value === filterValue.value } else if (this.mode === SEARCH_STRATEGY.IEXACT) { return value.toLowerCase() === filterValue.value.toLowerCase() } else if (this.mode === SEARCH_STRATEGY.PARTIAL) { return value.includes(filterValue.value) } else if (this.mode === SEARCH_STRATEGY.IPARTIAL) { return value.toLowerCase().includes(filterValue.value.toLowerCase()) } else if (this.mode === SEARCH_STRATEGY.START) { return value.startsWith(filterValue.value) } else if (this.mode === SEARCH_STRATEGY.END) { return value.endsWith(filterValue.value) } else if (this.mode === SEARCH_STRATEGY.WORD_START) { return wordStartRx!.test(value) } else { throw new Error('Unrecognized mode') } } public applyToPiniaOrmQuery( query: PiniaOrmQuery, ): PiniaOrmQuery { const filterValue = RefUtils.castToRef( this.filterValue, this.reactiveFilter, ) if (!filterValue.value) { return query } return query.where(this.field, (value: string) => this.search(value, filterValue), ) } public getApiQueryPart(): string { if (!this.filterValue.value) { return '' } return `${this.field}[]=${this.filterValue.value}` } }