Hi all,
I am stuck on how to model a set of filtering conditions as data types in my Model, and I was hoping the smart folks here would have some insight.
What I am trying to achieve
- I have some tabular data stored as a list of records. Each record contains String, Int and Float fields.
- I want users to be able to add/remove filters on this data, where only records matching the filter are shown.
- For int and string fields, users should be able to define 2 types of filter. (1) the field is equal to a given value; (2) the field is contained within a set of values
- For float fields: (1) the field is less than or equal to a given vale; (2) …more than or equal to…
For reference, my type definitions look something like this:
type alias Model =
{ data : List DataRecord
, filters : List Filter
}
type alias DataRecord =
{ id : Int
, name : String,typetype
, someOtherId : Int
, metricX : Float
, metricY : Float
-- etc
}
What I am struggling with
I am having difficulty coming up with a Filter
definition that enables me to easily:
- Expose filter creation to the user
- Display active filters (most likely as String, but could be any HTML)
What have I tried
What I have so far is
type FilterField
= FilterId (DiscreteComparison Int)
| FilterName (DiscreteComparison String)
| FilterSomeOtherId (DiscreteComparison Int)
| FilterMetricX (ContinuousComparison Float)
| FilterMetricY (ContinuousComparison Float)
type DiscreteComparison a
= Eq a
| In (List a)
type ContinuousComparison a
= Gte a
| Lte a
This works relatively well in modelling the filters, but makes it difficult to display active filters (because we need a function that takes *Comparison a -> String
with no way to convert a -> String
) and to enable user input.
An alternative idea I had was storing the record values with a custom type like
type RecordValue = RecordInt | RecordFloat | RecordString
This would enable me to write an exhaustive RecordValue -> String
function and I think solve my problems, with the downside of some additional boilerplate and Json Encode/Decode wrangling.
Another option would be to define the filters as functions directly:
type Filter = Filter (DataRecord -> Bool)
However, including functions in the Model and Msg are against the principles of the elm architecture - for good reason!
Has anyone else tried and achieved something similar? I would be interested in discovering any elegant ways to approach this.