feathersjs/feathers

View on GitHub
docs/ecosystem/useQuery.ts

Summary

Maintainability
A
2 hrs
Test Coverage
import { Ref, watch } from 'vue'
import queryString from 'query-string'

type MaybeArray<T> = T | T[]

type FieldType = MaybeArray<'string' | 'number' | 'boolean'>

export const useQuery = <T extends FieldType>(reference: Ref<T>, field: string) => {
  function getQuery() {
    return queryString.parse(window.location.search, {
      parseNumbers: true,
      parseBooleans: true,
      arrayFormat: 'none'
    })
  }

  function getFromUrl() {
    const q = getQuery()
    const result = q[field]
    // explicitly return false instead of undefined
    if (typeof reference.value === 'boolean' && !result) {
      return false
    }
    if (result == null) return
    if (Array.isArray(reference.value)) {
      return Array.isArray(result) ? result : [result]
    }
    return result
  }

  const fromUrl = getFromUrl()

  if (fromUrl != null) {
    // @ts-expect-error arbitrary type
    reference.value = fromUrl
  }

  function setToUrl(val: any) {
    const q = getQuery()
    if (val && (!Array.isArray(reference.value) || (Array.isArray(val) && val.length > 0))) {
      q[field] = val
    } else {
      delete q[field]
    }
    const prepend = Object.keys(q).length ? '?' : ''
    const newQuery = `${prepend}${queryString.stringify(q, { skipNull: true })}`
    window.history.replaceState(null, '', newQuery)
  }

  watch(
    reference,
    (val) => {
      setToUrl(val)
    },
    { immediate: true }
  )
}