<p>Podcast episode is about two things, serializing custom data with Persistent and <code>IsString</code> typeclass.</p>
<p>I’m using Persistent in conjunction with Yesod (web framework). Process in short is that data is defined in <code>/config/models</code> file that is used in compile time to generate data type definitions for Haskell. Same information is used to create schema for the database when Yesod application starts. It can even do simple migrations if schema changes, but I wouldn’t recommend using that in production.</p>
<p>Persistent maps information between database and program written in Haskell. There’s pre-existing mappings for things like text and various kinds of numbers. In case one wants to use custom data type, compiler can automatically generate needed mapping. This automatic generation works well with enumerations and very complex data.</p>
<p>For example, following piece defines enumeration <code>BuildingType</code> that is mapped in <code>varchar</code> field in database. Enumeration is thus stored as text.</p>
<pre><code>data BuildingType = SensorStation
    | ResearchComplex
    | Farm
    | ParticleAccelerator
    | NeutronDetector
    | BlackMatterScanner
    | GravityWaveSensor
    deriving (Show, Read, Eq)

derivePersistField &quot;BuildingType&quot;</code></pre>
<p>For newtypes, automatic deriving works too, but generates (in my opinion) extra information that isn’t needed. This extra information causes data saved as text. For those cases, manual mapping can be used.</p>
<p>Our example is for <code>StarDate</code>, which is just glorified <code>Int</code>. I’m using newtype to make <code>StarDate</code> distinct from any other <code>Int</code>, even when it behaves just like <code>Int</code>.</p>
<pre><code>newtype StarDate = StarDate { unStarDate :: Int }
    deriving (Show, Read, Eq, Num, Ord)

instance PersistField StarDate where
    toPersistValue (StarDate n) =
        PersistInt64 $ fromIntegral n

    fromPersistValue (PersistInt64 n) =
        Right $ StarDate $ fromIntegral n

    fromPersistValue _ =
        Left &quot;Failed to deserialize&quot;


instance PersistFieldSql StarDate where
    sqlType _ = SqlInt64</code></pre>
<p>One more trick, that doesn’t directly relate to Persistent is <code>IsString</code> type class. Instead of having to specify all the time what type text literal is, one can let compiler to deduce it from usage.</p>
<p>For example, if I had a newtype like:</p>
<pre><code>newtype PlanetName = PlanetName { unPlanetName :: Text }</code></pre>
<p>I can turn on OverloadedStrings pragma and create <code>IsString</code> instance:</p>
<pre><code>instance IsString PlanetName where
    fromString = PlanetName . fromString</code></pre>
<p>Now I can write: <code>placeName = &quot;Earth&quot;</code> instead of <code>placeName = PlanetName &quot;Earth&quot;</code> and compiler can deduce correct type based on how the <code>placeName</code> is used.</p>
<p>Thanks for listening, if you have any questions or comments, you can reach me via email or in the fediverse, where I’m <code>Tuula@mastodon.social</code>.</p>
