fradrive/src/Model/Migration/Version.hs
Gregor Kleen f2fb7d8c26 feat(migration): switch from versions to enum
BREAKING CHANGE: ManualMigration
2020-11-24 15:18:37 +01:00

98 lines
2.8 KiB
Haskell

{-# OPTIONS_GHC -fno-warn-orphans #-}
module Model.Migration.Version
( MigrationVersion(..)
, version, migrationVersion
, module Data.Version
) where
import ClassyPrelude.Yesod
import Database.Persist.Sql
import Text.ParserCombinators.ReadP
import Data.Maybe (fromJust)
import Data.Version
import Data.Aeson.TH
import Language.Haskell.TH.Lib (viewP)
import Language.Haskell.TH.Quote
import Language.Haskell.TH.Syntax (Lift)
import qualified Language.Haskell.TH.Syntax as TH (lift)
import Data.Data (Data)
import Utils (assertM')
deriving instance Lift Version
data MigrationVersion = InitialVersion | MigrationVersion Version
deriving (Eq, Ord, Show, Read, Generic, Typeable, Data, Lift)
deriveJSON defaultOptions
{ constructorTagModifier = toLower . fromJust . stripSuffix "Version"
, sumEncoding = UntaggedValue
} ''MigrationVersion
instance PersistField MigrationVersion where
toPersistValue InitialVersion = PersistText "initial"
toPersistValue (MigrationVersion v) = PersistText . pack $ showVersion v
fromPersistValue (PersistText t)
| t == "initial" = return InitialVersion
| otherwise = case [ x | (x, "") <- readP_to_S parseVersion $ unpack t] of
[x] -> Right $ MigrationVersion x
[] -> Left "No parse"
_ -> Left "Ambiguous parse"
fromPersistValue x = Left $ "Expected PersistText, received: " <> tshow x
instance PersistFieldSql MigrationVersion where
sqlType _ = SqlString
instance PersistField Version where
toPersistValue = PersistText . pack . showVersion
fromPersistValue (PersistText t) = case [ x | (x, "") <- readP_to_S parseVersion $ unpack t] of
[x] -> Right x
[] -> Left "No parse"
_ -> Left "Ambiguous parse"
fromPersistValue x = Left $ "Expected PersistText, received: " <> tshow x
instance PersistFieldSql Version where
sqlType _ = SqlString
version, migrationVersion :: QuasiQuoter
version = undefinedQuote{quoteExp, quotePat}
where
withP f v = case [ x | (x, "") <- readP_to_S parseVersion v] of
[x] -> f x
[] -> error "No parse"
_ -> error "Ambiguous parse"
quoteExp = withP TH.lift
quotePat = withP $ \p -> viewP [e|assertM' (== $(TH.lift p))|] [p|Just _|]
migrationVersion = undefinedQuote{quoteExp, quotePat}
where
withP f "initial" = f InitialVersion
withP f v = case [ x | (x, "") <- readP_to_S parseVersion v] of
[x] -> f $ MigrationVersion x
[] -> error "No parse"
_ -> error "Ambiguous parse"
quoteExp = withP TH.lift
quotePat = withP $ \p -> viewP [e|assertM' (== $(TH.lift p))|] [p|Just _|]
undefinedQuote :: QuasiQuoter
undefinedQuote = QuasiQuoter{..}
where
quoteExp = error "qq cannot be used as expression"
quotePat = error "qq cannot be used as pattern"
quoteType = error "qq cannot be used as type"
quoteDec = error "qq cannot be used as declaration"