Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/parsonsmatt/record-wrangler

Alter datatypes at your leisure!
https://github.com/parsonsmatt/record-wrangler

Last synced: 13 days ago
JSON representation

Alter datatypes at your leisure!

Awesome Lists containing this project

README

        

# record-wrangler

[![Build Status](https://travis-ci.org/lumihq/record-wrangler.svg?branch=master)](https://travis-ci.org/lumihq/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:

```haskell
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.

```haskell
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:

```haskell
convertUser Api.User{..} = Domain.User{..}
```

However, because the field labels are different, we have to do it manually:

```haskell
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.

```haskell
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:

```haskell
convertUser :: Api.User -> Domain.User
convertUser (wrangleUserToUser' -> User'{..}) = Domain.User{..}
```