Safe Haskell | None |
---|---|
Language | Haskell2010 |
RecordWrangler
Description
This module contains a Template Haskell helper to produce a new datatype with modified field names. The initial use case is to allow for easier record construction with Lumi's databases models, which have record fields prefixed with an `_`, and the Stats records, which do not have this underscore. The use of a naming scheme convention allows one to write the conversion function as:
convertData (Entity id Old.Record{..}) RecordStats{..} = Entity (coerce id) New.Record { .. -- Some fields need massaging , _recordClientId = coerce _recordClientId -- Some fields don't need massaging, but need to be explicitly labeled. , _recordStatsFoo = recordStatsFoo }
where each field in RecordStats
must be repeated. This can be accomplished
fairly easily with a vim macro, but it's more fun and less error prone to
write Haskell.
With this module, we can instead write:
wrangle ''RecordStats with { fieldLabelModifier = ('_' :) }
which generates a new type RecordStats'
with the same fields, but modified
to have different field labels. It also creates a conversion function. Now,
we can write (with ViewPatterns
):
convertData (Entity id Old.Record{..}) (wrangleRecordStatsToRecordStats' -> RecordStats'{..}) = Entity (coerce id) New.Record { .. , _recordClientId = coerce _recordClientId }
Now, the only terms that need to be mentioned are the ones that cause a compile-time error due to the types not matching up.
Synopsis
- wrangle :: Name -> WrangleOpts -> DecsQ
- data WrangleOpts
- defWrangleOpts :: WrangleOpts
- fieldLabelModifier :: WrangleOpts -> String -> String
- constructorModifier :: WrangleOpts -> String -> String
- typeNameModifier :: WrangleOpts -> String -> String
The Wranglin One
wrangle :: Name -> WrangleOpts -> DecsQ Source #
Create a new datatype with altered field labels, type name, and constructor names along with a conversion function.
The conversion function will have a name matching the pattern:
wrangle + OldTypeName + To + NewTypeName
As an example, consider the following datatype and wrangling:
data Person = Person { name :: String, age :: Int } 'wrangle' ''Person 'with' { 'fieldLabelModifier' = ('_' :) , 'typeNameModifier' = ("Powerful" ++) }
This has the effect of creating this new datatype and function:
data PowerfulPerson = Person' { _name :: String, _age :: Int } wranglePersonToPowerfulPerson :: Person -> PowerfulPerson wranglePersonToPowerfulPerson (Person x0 x1) = Person' x0 x1
Since: 0.1.0.0
The Options For Wranglin
data WrangleOpts Source #
The options for wrangling records. The constructor is hidden so that we can add new features and powers without breaking your code!
defWrangleOpts :: WrangleOpts Source #
This is the default set of WrangleOpts
. It affixes a '
character to
the end of the fields, type, and constructor. If you want different behavior,
then you will want to alter the fields:
wrangle ''Record defWrangleOpts { fieldLabelModifier = ('_' :) }
Since: 0.1.0.0
fieldLabelModifier :: WrangleOpts -> String -> String Source #
This function will be applied to every field label in the provided record.
Since: 0.1.0.0
constructorModifier :: WrangleOpts -> String -> String Source #
This function will be applied to the constructor name.
Since: 0.1.0.0
typeNameModifier :: WrangleOpts -> String -> String Source #
This function will be applied to the type name.
Since: 0.1.0.0