SearchFilter.ts 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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. if (!filterValue) {
  40. return query
  41. }
  42. let wordStartRx: RegExp | null = null
  43. if (this.mode === SEARCH_STRATEGY.WORD_START) {
  44. wordStartRx = new RegExp(`^${filterValue.value}|\\s${filterValue.value}`)
  45. }
  46. return query.where(this.field, (value: string) => {
  47. if (this.mode === SEARCH_STRATEGY.EXACT) {
  48. return value === filterValue.value
  49. } else if (this.mode === SEARCH_STRATEGY.IEXACT) {
  50. return value.toLowerCase() === filterValue.value.toLowerCase()
  51. } else if (this.mode === SEARCH_STRATEGY.PARTIAL) {
  52. return value.includes(filterValue.value)
  53. } else if (this.mode === SEARCH_STRATEGY.IPARTIAL) {
  54. return value.toLowerCase().includes(filterValue.value.toLowerCase())
  55. } else if (this.mode === SEARCH_STRATEGY.START) {
  56. return value.startsWith(filterValue.value)
  57. } else if (this.mode === SEARCH_STRATEGY.END) {
  58. return value.endsWith(filterValue.value)
  59. } else if (this.mode === SEARCH_STRATEGY.WORD_START) {
  60. return wordStartRx!.test(value)
  61. } else {
  62. throw new Error('Unrecognized mode')
  63. }
  64. })
  65. }
  66. public getApiQueryPart(): string {
  67. if (!this.filterValue.value) {
  68. return ''
  69. }
  70. return `${this.field}[]=${this.filterValue.value}`
  71. }
  72. }