SearchFilter.ts 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. import type { Query as PiniaOrmQuery } from 'pinia-orm'
  2. import type { ApiFilter } from '~/types/data'
  3. import ApiResource from '~/models/ApiResource'
  4. import { SEARCH_STRATEGY } from '~/types/enum/data'
  5. export default class SearchFilter implements ApiFilter {
  6. field: string
  7. filterValue: Ref<string>
  8. mode: SEARCH_STRATEGY
  9. reactiveFilter: boolean
  10. /**
  11. * @param field
  12. * @param value
  13. * @param mode The 'search' strategy (exact [default], partial, start, end, word_start).
  14. * This strategy is defined API-side, but PiniaOrm needs to know how to handle this.
  15. * @see https://api-platform.com/docs/core/filters/
  16. * @param reactiveFilter Est-ce qu'on doit conserver la réactivité du filtre ? Concrètement, dans le cas d'une
  17. * recherche textuelle, si le filtre est réactif, le résultat de la query Pinia-ORM sera
  18. * filtré à chaque fois que le filtre est modifié (même sans refresh ou nouvel appel à
  19. * fetchCollection). Si reactiveFilter est false (comportement par défaut), le résultat
  20. * de la query ne sera mis à jour qu'en cas de nouvel appel à fetchCollection (ou à refresh()).
  21. */
  22. constructor(
  23. field: string,
  24. value: Ref<string>,
  25. mode: SEARCH_STRATEGY = SEARCH_STRATEGY.EXACT,
  26. reactiveFilter: boolean = false,
  27. ) {
  28. this.field = field
  29. this.filterValue = value
  30. this.mode = mode
  31. this.reactiveFilter = reactiveFilter
  32. }
  33. public applyToPiniaOrmQuery(
  34. query: PiniaOrmQuery<ApiResource>,
  35. ): PiniaOrmQuery<ApiResource> {
  36. const filterValue = this.reactiveFilter
  37. ? this.filterValue
  38. : ref(this.filterValue.value)
  39. let wordStartRx: RegExp | null = null
  40. if (this.mode === SEARCH_STRATEGY.WORD_START) {
  41. wordStartRx = new RegExp(`^${filterValue.value}|\\s${filterValue.value}`)
  42. }
  43. return query.where(this.field, (value: string) => {
  44. if (this.mode === SEARCH_STRATEGY.EXACT) {
  45. return value === filterValue.value
  46. } else if (this.mode === SEARCH_STRATEGY.IEXACT) {
  47. return value.toLowerCase() === filterValue.value.toLowerCase()
  48. } else if (this.mode === SEARCH_STRATEGY.PARTIAL) {
  49. return value.includes(filterValue.value)
  50. } else if (this.mode === SEARCH_STRATEGY.IPARTIAL) {
  51. return value.toLowerCase().includes(filterValue.value.toLowerCase())
  52. } else if (this.mode === SEARCH_STRATEGY.START) {
  53. return value.startsWith(filterValue.value)
  54. } else if (this.mode === SEARCH_STRATEGY.END) {
  55. return value.endsWith(filterValue.value)
  56. } else if (this.mode === SEARCH_STRATEGY.WORD_START) {
  57. return wordStartRx!.test(value)
  58. } else {
  59. throw new Error('Unrecognized mode')
  60. }
  61. })
  62. }
  63. public getApiQueryPart(): string {
  64. return `${this.field}[]=${this.filterValue.value}`
  65. }
  66. }