import type { Query as PiniaOrmQuery } from 'pinia-orm' import type { ApiFilter } from '~/types/data' import ApiResource from '~/models/ApiResource' import { SEARCH_STRATEGY } from '~/types/enum/data' export default class SearchFilter implements ApiFilter { field: string filterValue: Ref mode: SEARCH_STRATEGY reactiveFilter: boolean /** * @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 Est-ce qu'on doit conserver la réactivité du filtre ? Concrètement, dans le cas d'une * recherche textuelle, si le filtre est réactif, le résultat de la query Pinia-ORM sera * filtré à chaque fois que le filtre est modifié (même sans refresh ou nouvel appel à * fetchCollection). Si reactiveFilter est false (comportement par défaut), le résultat * de la query ne sera mis à jour qu'en cas de nouvel appel à fetchCollection (ou à refresh()). */ constructor( field: string, value: Ref, mode: SEARCH_STRATEGY = SEARCH_STRATEGY.EXACT, reactiveFilter: boolean = false, ) { this.field = field this.filterValue = value this.mode = mode this.reactiveFilter = reactiveFilter } public applyToPiniaOrmQuery( query: PiniaOrmQuery, ): PiniaOrmQuery { const filterValue = this.reactiveFilter ? this.filterValue : ref(this.filterValue.value) let wordStartRx: RegExp | null = null if (this.mode === SEARCH_STRATEGY.WORD_START) { wordStartRx = new RegExp(`^${filterValue.value}|\\s${filterValue.value}`) } return query.where(this.field, (value: string) => { 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 getApiQueryPart(): string { return `${this.field}[]=${this.filterValue.value}` } }