Alter your records with ease.
Please see the README on GitHub at https://github.com/lumihq/record-wrangler#readme
record-wrangler
This package uses TemplateHaskell
to alter records in ways that may be convenient for you.
Inspiration
Let's say you've got a set of API types and a set of domain types. The API types define your HTTP contract, and you generically derive ToJSON and FromJSON instances from their field labels. They look like this:
data User = User
{ id :: Int
, name :: String
, age :: Int
}
data Dog = Dog
{ id :: Int
, name :: String
, toy :: FavoriteToy
, ownerId :: Int
}
The domain types for your business logic look a little different, though. The record fields are prefixed with an _
underscore character, to allow for lens
derivation. We can pretend they have other differences that are relevant to internal details and irrelevant for showing off record-wrangler
if that makes you feel better.
data Dog = Dog
{ _id :: Int
, _name :: String
, _toy :: FavoriteToy
, _ownerId :: Int
}
makeLenses ''Dog
data User = User
{ _id :: Int
, _name :: String
, _age :: Int
}
makeLenses ''User
If the record fields were the same, then we could just write the conversion function using RecordWildCards
and it'd be fine:
convertUser Api.User{..} = Domain.User{..}
However, because the field labels are different, we have to do it manually:
convertUser Api.User{..} = Domain.User
{ _id = id
, _name = name
, _age = age
}
This is annoying and boilerplatey. I don't know about you, but I hate writing code, for every line of code I write is a chance to mess up. Let's use record-wrangler
to make these conversions easier.
wrangle ''Api.User defWrangleOpts
{ fieldLabelModifier = \fieldStr -> '_' : fieldStr
}
This is going to take the Api.User
type and modify it slightly. By default, we append a '
to the constructor name, type name, and field labels. Here, we've decided to prepend a _
character to the field label. It also generates a function wrangleUserToUser'
which converts the old record to the modified one.
With the power of view patterns, our conversion function is now quite concise:
convertUser :: Api.User -> Domain.User
convertUser (wrangleUserToUser' -> User'{..}) = Domain.User{..}