blikblum/nextbone

[virtualcollection] Provide a better way to declare filter

Opened this issue · 3 comments

Should allow to define declarative filters, automatic updates on params change

Bonus: having a way to cache derived values used in filters like regex

Current patterns:

dedicated subclass

export class FilteredPatients extends VirtualCollection {
  __params = {}

  setParams(params = {}) {
    Object.assign(this.__params, params)
    if (this.parent) {
      this.updateFilter()
    }
  }

  acceptModel(model) {
    const { name, shift, group, active } = this.__params
    let accept = true

    if (accept && shift) {
      accept = model.get('shift') === shift
    }
    if (accept && group) {
      accept = model.get('group') === group
    }
    if (accept && name) {
      accept = (model.get('name') || '').search(new RegExp(name, 'i')) !== -1
    }
    if (accept && typeof active === 'boolean') {
      accept = model.get('active') === active
    }
    return accept
  }
}

filter option

 class PatientSurveysPage extends Component {
  @state
  filteredPatients = new VirtualCollection(null, {
    filter: (model) => {
      if (!this.filterParams || !size(this.filterParams)) return true
      let accept = true
      const { nameRegex, groups, shifts, notResponded } = this.filterParams

      if (accept && notResponded) {
        accept = !this.hasRespondedSurvey(model.get('satisfaction'))
      }

      if (accept && groups) {
        accept = groups.includes(model.get('group'))
      }

      if (accept && shifts) {
        accept = shifts.includes(model.get('shift'))
      }

      if (accept && nameRegex) {
        accept = (model.get('name') || '').match(nameRegex)
      }

      return accept
    },
  })

  patients

  @property({})
  survey

  @query('filter-params-bar')
  filterParamsBar

  connectedCallback() {
    super.connectedCallback()
    this.filteredPatients.parent = this.patients
  }

  filterParamsChange() {
    const params = this.filterParamsBar.value
    this.filterParams = { ...params }
    if (params.name) {
      this.filterParams.nameRegex = new RegExp(params.name, 'i')
    }
    this.filteredPatients.updateFilter()
  }
}

Proposal - define params option responsible to calling updateFilter when one of the params change

Proposal - allow to define filters individually

  • accept an object in filter option where values are functions
  • allow to cache a value derived from param

example:

const x = new VirtualCollection({
  filter: {
    name (model, value, params) {
      return model.get('name') === value
   }
  }
})
const x = new VirtualCollection({
  filter: {
    name: {
      prepare(value) {
        return new Regexp(value)
      }
     test (model, value, params) {
      return model.get('name').matches(value)
   }
   } 
  }
})

Proposal - allow to customize the query logic

Currently the accept logic is require all params to be true

const x = new VirtualCollection({
  query({name, cpf}) {
    return name || birthDate
  }
})