record-wrangler-0.1.0.0: Alter your records with ease

Safe HaskellNone
LanguageHaskell2010

RecordWrangler

Contents

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

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