I'm trying to build a Data.HashMap
structure by grouping multiple Persistent entities by their foreign key field. E.g. say I have these two entities (straight out of the Yesod book)
Person
name String
age Int Maybe
deriving Show
BlogPost
title String
authorId PersonId
deriving Show
and I want a:
HashMap PersonId [BlogPost]
The challenge here is that PersonId does not directly implement Hashable
(from Data.Hashable) and additionally it's abstracted depending on which DB you're using (Postgres in my case).
I suppose (just a wild beginner guess) I could implement Hashable for PersonId myself by doing fromPersistValue
and a read
into an Int64, for which there's a Hashable implementation already, but I imagine there might be a less convoluted way of achieving that.
Any suggestions?
You can do this for the price of a few orphan instances. You can find the complete code below.
PersonId
is just an alias for KeyBackend SqlBackend Person
, so the instance Hashable (KeyBackend b e)
is what you need. The rest of the declarations derive Hashable
for other types that may end up being parts of PersonId
.
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveGeneric #-}
module HashableInstances where
import Database.Persist
import GHC.Generics
import Data.Hashable
import Data.Time
import Data.Fixed
instance HasResolution e => Hashable (Fixed e) where
hashWithSalt s = (hashWithSalt s :: Double -> Int) . realToFrac
deriving instance Generic Day
instance Hashable Day
deriving instance Generic LocalTime
instance Hashable LocalTime
deriving instance Generic TimeOfDay
instance Hashable TimeOfDay
deriving instance Generic TimeZone
instance Hashable TimeZone
instance Hashable DiffTime where
hashWithSalt s = (hashWithSalt s :: Double -> Int) . realToFrac
deriving instance Generic UTCTime
instance Hashable UTCTime
deriving instance Generic ZonedTime
instance Hashable ZonedTime
deriving instance Generic ZT
instance Hashable ZT
deriving instance Generic PersistValue
instance Hashable PersistValue
deriving instance Generic (KeyBackend b e)
instance Hashable (KeyBackend b e)
Does it have to be a HashMap
? Data.Map
only needs Ord
. The Hashable
class is a bit dodgy and could use a fix-up anyway.
Unless you know what you're doing and understand the flaws in the hashing behavior of Hashable
you should never use HashMap
where a Data.Map
would do.
This has the side effect of avoiding unnecessary orphan instances. (More things are Ord than Hashable)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With