Site Map - skip to main content - dyslexic font - mobile - text - print

Hacker Public Radio

Your ideas, projects, opinions - podcasted.

New episodes Monday through Friday.


hpr2868 :: Custom data with Persistent

tuturto explains how to serialize custom data with Persistent

<< First, < Previous, Latest >>

Hosted by tuturto on 2019-07-31 is flagged as Clean and is released under a CC-BY-SA license.
Tags: haskell, persistent, database.
Listen in ogg, spx, or mp3 format. | Comments (0)

Part of the series: Haskell

A series looking into the Haskell (programming language)

Podcast episode is about two things, serializing custom data with Persistent and IsString typeclass.

I’m using Persistent in conjunction with Yesod (web framework). Process in short is that data is defined in /config/models 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.

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.

For example, following piece defines enumeration BuildingType that is mapped in varchar field in database. Enumeration is thus stored as text.

data BuildingType = SensorStation
    | ResearchComplex
    | Farm
    | ParticleAccelerator
    | NeutronDetector
    | BlackMatterScanner
    | GravityWaveSensor
    deriving (Show, Read, Eq)

derivePersistField "BuildingType"

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.

Our example is for StarDate, which is just glorified Int. I’m using newtype to make StarDate distinct from any other Int, even when it behaves just like Int.

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 "Failed to deserialize"


instance PersistFieldSql StarDate where
    sqlType _ = SqlInt64

One more trick, that doesn’t directly relate to Persistent is IsString type class. Instead of having to specify all the time what type text literal is, one can let compiler to deduce it from usage.

For example, if I had a newtype like:

newtype PlanetName = PlanetName { unPlanetName :: Text }

I can turn on OverloadedStrings pragma and create IsString instance:

instance IsString PlanetName where
    fromString = PlanetName . fromString

Now I can write: placeName = "Earth" instead of placeName = PlanetName "Earth" and compiler can deduce correct type based on how the placeName is used.

Thanks for listening, if you have any questions or comments, you can reach me via email or in the fediverse, where I’m tuturto@mastodon.social.


Comments

Subscribe to the comments RSS feed.

<< First, < Previous, Latest >>

Leave Comment

Note to Verbose Commenters
If you can't fit everything you want to say in the comment below then you really should record a response show instead.

Note to Spammers
All comments are moderated. All links are checked by humans. We strip out all html. Feel free to record a show about yourself, or your industry, or any other topic we may find interesting. We also check shows for spam :).

Provide feedback
Your Name/Handle:
Title:
Comment:
Anti Spam Question: What does the P in HPR stand for ?