persistent-template 0.6.3.1 → 0.7.0
raw patch · 2 files changed
+292/−125 lines, 2 filesdep +containersdep ~persistentPVP ok
version bump matches the API change (PVP)
Dependencies added: containers
Dependency ranges changed: persistent
API changes (from Hackage documentation)
- Database.Persist.TH: instance Lift ColumnDef
+ Database.Persist.TH: instance Lift DBName
+ Database.Persist.TH: instance Lift FieldDef
+ Database.Persist.TH: instance Lift FieldType
+ Database.Persist.TH: instance Lift HaskellName
+ Database.Persist.TH: persistFileWith :: PersistSettings -> FilePath -> Q Exp
+ Database.Persist.TH: persistLowerCase :: QuasiQuoter
+ Database.Persist.TH: persistUpperCase :: QuasiQuoter
+ Database.Persist.TH: persistWith :: PersistSettings -> QuasiQuoter
Files
- Database/Persist/TH.hs +289/−123
- persistent-template.cabal +3/−2
Database/Persist/TH.hs view
@@ -1,26 +1,38 @@ {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS_GHC -fno-warn-orphans -fno-warn-missing-fields #-} -- | This module provides utilities for creating backends. Regular users do not -- need to use this module. module Database.Persist.TH- ( mkPersist- , share+ ( -- * Parse entity defs+ persistWith+ , persistUpperCase+ , persistLowerCase+ , persistFileWith+ -- ** Deprecated synonyms , persist , persistFile- , share2+ -- * Turn @EntityDef@s into types+ , mkPersist+ , MkPersistSettings (..)+ , sqlSettings+ -- * Various other TH functions+ , mkMigrate , mkSave , mkDeleteCascade+ , share , derivePersistField- , mkMigrate- , MkPersistSettings (..)- , sqlSettings+ -- ** Deprecated+ , share2 ) where -import Database.Persist.Base+import Prelude hiding ((++), take, concat, splitAt)+import Database.Persist.EntityDef+import Database.Persist.Quasi+import Database.Persist.Store+import Database.Persist.Query.Internal import Database.Persist.GenericSql (Migration, SqlPersist, migrate)-import Database.Persist.GenericSql.Internal (unRawName,rawFieldName,rawTableIdName) -- XXX-import Database.Persist.Quasi (parse) import Database.Persist.Util (nullable) import Database.Persist.TH.Library (apE) import Language.Haskell.TH.Quote@@ -34,57 +46,95 @@ import Control.Monad.IO.Control (MonadControlIO) #endif import qualified System.IO as SIO-import Data.Text (pack)-import Data.List (isSuffixOf)+import Data.Text (pack, Text, append, isSuffixOf, unpack, take, concat, uncons, cons, splitAt)+import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import Data.List (foldl')+import Data.Monoid (mappend, mconcat)+import qualified Data.Map as Map -- | Converts a quasi-quoted syntax into a list of entity definitions, to be -- used as input to the template haskell generation code (mkPersist).-persist :: QuasiQuoter-persist = QuasiQuoter- { quoteExp = lift . parse+persistWith :: PersistSettings -> QuasiQuoter+persistWith ps = QuasiQuoter+ { quoteExp = lift . parse ps . pack } -persistFile :: FilePath -> Q Exp-persistFile fp = do+-- | Deprecate synonym for 'persistUpperCase'.+persist :: QuasiQuoter+persist = persistUpperCase+{-# DEPRECATED persist "Please use persistUpperCase instead." #-}++-- | Apply 'persistWith' to 'upperCaseSettings'.+persistUpperCase :: QuasiQuoter+persistUpperCase = persistWith upperCaseSettings++-- | Apply 'persistWith' to 'lowerCaseSettings'.+persistLowerCase :: QuasiQuoter+persistLowerCase = persistWith lowerCaseSettings++-- | Same as 'persistWith', but uses an external file instead of a+-- quasiquotation.+persistFileWith :: PersistSettings -> FilePath -> Q Exp+persistFileWith ps fp = do h <- qRunIO $ SIO.openFile fp SIO.ReadMode qRunIO $ SIO.hSetEncoding h SIO.utf8_bom- s <- qRunIO $ SIO.hGetContents h- lift $ parse s+ s <- qRunIO $ TIO.hGetContents h+ lift $ parse ps s +-- | Deprecated function. Equivalent to @persistFileWith upperCaseSettings@.+persistFile :: FilePath -> Q Exp+persistFile = persistFileWith upperCaseSettings+ -- | Create data types and appropriate 'PersistEntity' instances for the given -- 'EntityDef's. Works well with the persist quasi-quoter. mkPersist :: MkPersistSettings -> [EntityDef] -> Q [Dec]-mkPersist mps = fmap concat . mapM (mkEntity mps)+mkPersist mps = fmap mconcat . mapM (mkEntity mps) +-- | Settings to be passed to the 'mkPersist' function. data MkPersistSettings = MkPersistSettings { mpsBackend :: Type+ -- ^ Which database backend we\'re using.+ --+ -- When generating data types, each type is given a generic version- which+ -- works with any backend- and a type synonym for the commonly used+ -- backend. This is where you specify that commonly used backend. } +-- | Use the 'SqlPersist' backend. sqlSettings :: MkPersistSettings sqlSettings = MkPersistSettings { mpsBackend = ConT ''SqlPersist } -recName :: String -> String -> String+recName :: Text -> Text -> Text recName dt f = lowerFirst dt ++ upperFirst f -lowerFirst :: String -> String-lowerFirst (x:xs) = toLower x : xs-lowerFirst [] = []+lowerFirst :: Text -> Text+lowerFirst t =+ case uncons t of+ Just (a, b) -> cons (toLower a) b+ Nothing -> t -upperFirst :: String -> String-upperFirst (x:xs) = toUpper x : xs-upperFirst [] = []+upperFirst :: Text -> Text+upperFirst t =+ case uncons t of+ Just (a, b) -> cons (toUpper a) b+ Nothing -> t dataTypeDec :: EntityDef -> Dec dataTypeDec t =- DataD [] nameG [PlainTV backend] [RecC name cols] $ map mkName $ entityDerives t+ DataD [] nameG [PlainTV backend] [RecC name cols]+ $ map (mkName . unpack) $ entityDerives t where- mkCol x (ColumnDef n ty as) =- (mkName $ recName x n, NotStrict, pairToType backend (ty, nullable as))- nameG = mkName $ entityName t ++ suffix- name = mkName $ entityName t- cols = map (mkCol $ entityName t) $ entityColumns t+ mkCol x (FieldDef n _ ty as) =+ (mkName $ unpack $ recName x $ unHaskellName n,+ NotStrict,+ pairToType backend (unFieldType ty, nullable as)+ )+ nameG = mkName $ unpack $ unHaskellName (entityHaskell t) ++ suffix+ name = mkName $ unpack $ unHaskellName $ entityHaskell t+ cols = map (mkCol $ unHaskellName $ entityHaskell t) $ entityFields t backend = mkName "backend" readMay :: Read a => String -> Maybe a@@ -93,15 +143,18 @@ (x, _):_ -> Just x [] -> Nothing -entityUpdates :: EntityDef -> [(String, String, Bool, PersistUpdate)]+entityUpdates :: EntityDef -> [(HaskellName, FieldType, Bool, PersistUpdate)] entityUpdates =- concatMap go . entityColumns+ concatMap go . entityFields where- go (ColumnDef x y as) = map (\a -> (x, y, nullable as, a)) [minBound..maxBound]+ go (FieldDef x _ y as) = map (\a -> (x, y, nullable as, a)) [minBound..maxBound] uniqueTypeDec :: EntityDef -> Dec uniqueTypeDec t =- DataInstD [] ''Unique [ConT (mkName (entityName t ++ suffix)) `AppT` VarT backend, VarT backend2]+ DataInstD [] ''Unique+ [ ConT (mkName $ unpack (unHaskellName (entityHaskell t) ++ suffix))+ `AppT` VarT backend, VarT backend2+ ] (map (mkUnique backend t) $ entityUniques t) (if null (entityUniques t) then [] else [''Show, ''Read, ''Eq]) where@@ -109,27 +162,36 @@ backend2 = mkName "backend2" mkUnique :: Name -> EntityDef -> UniqueDef -> Con-mkUnique backend t (UniqueDef constr fields) =- NormalC (mkName constr) types+mkUnique backend t (UniqueDef (HaskellName constr) _ fields) =+ NormalC (mkName $ unpack constr) types where- types = map (go . flip lookup3 (entityColumns t)) fields+ types = map (go . flip lookup3 (entityFields t))+ $ map (unHaskellName . fst) fields++ go :: (FieldType, Bool) -> (Strict, Type) go (_, True) = error "Error: cannot have nullables in unique"- go x = (NotStrict, pairToType backend x)+ go (FieldType x, y) = (NotStrict, pairToType backend (x, y))++ lookup3 :: Text -> [FieldDef] -> (FieldType, Bool) lookup3 s [] =- error $ "Column not found: " ++ s ++ " in unique " ++ constr- lookup3 x ((ColumnDef x' y z):rest)+ error $ unpack $ "Column not found: " ++ s ++ " in unique " ++ constr+ lookup3 x ((FieldDef (HaskellName x') _ y z):rest) | x == x' = (y, nullable z) | otherwise = lookup3 x rest pairToType :: Name -- ^ backend- -> (String, Bool) -> Type+ -> (Text, Bool) -> Type pairToType backend (s, False) = idType backend s pairToType backend (s, True) = ConT (mkName "Maybe") `AppT` idType backend s -idType :: Name -> String -> Type+idType :: Name -> Text -> Type idType backend typ- | "Id" `isSuffixOf` typ = ConT ''Key `AppT` VarT backend `AppT` ConT (mkName $ take (length typ - 2) typ)- | otherwise = ConT $ mkName typ+ | "Id" `isSuffixOf` typ =+ ConT ''Key+ `AppT` VarT backend+ `AppT` (ConT (mkName $ unpack $ take (T.length typ - 2) typ ++ "Generic")+ `AppT` VarT backend)+ | otherwise = ConT $ mkName $ unpack typ degen :: [Clause] -> [Clause] degen [] =@@ -151,14 +213,18 @@ let bod = ListE $ map (AppE sp . VarE) xs return $ Clause [pat] (NormalB bod) [] -mkToFieldNames :: [UniqueDef] -> Dec-mkToFieldNames pairs =- FunD (mkName "persistUniqueToFieldNames") $ degen $ map go pairs+mkToFieldNames :: [UniqueDef] -> Q Dec+mkToFieldNames pairs = do+ pairs' <- mapM go pairs+ return $ FunD (mkName "persistUniqueToFieldNames") $ degen pairs' where- go (UniqueDef constr names) =- Clause [RecP (mkName constr) []]- (NormalB $ ListE $ map (LitE . StringL) names)- []+ go (UniqueDef constr _ names) = do+ names' <- lift names+ return $+ Clause+ [RecP (mkName $ unpack $ unHaskellName constr) []]+ (NormalB names')+ [] mkToUpdate :: String -> [(String, PersistUpdate)] -> Q Dec mkToUpdate name pairs = do@@ -175,9 +241,9 @@ return $ FunD (mkName "persistUniqueToValues") $ degen pairs' where go :: UniqueDef -> Q Clause- go (UniqueDef constr names) = do+ go (UniqueDef constr _ names) = do xs <- mapM (const $ newName "x") names- let pat = ConP (mkName constr) $ map VarP xs+ let pat = ConP (mkName $ unpack $ unHaskellName constr) $ map VarP xs tpv <- [|toPersistValue|] let bod = ListE $ map (AppE tpv . VarE) xs return $ Clause [pat] (NormalB bod) []@@ -214,17 +280,17 @@ mkFromPersistValues :: EntityDef -> Q [Clause] mkFromPersistValues t = do- nothing <- [|Left "Invalid fromPersistValues input"|]- let cons = ConE $ mkName $ entityName t- xs <- mapM (const $ newName "x") $ entityColumns t+ nothing <- [|Left $(liftT "Invalid fromPersistValues input")|]+ let cons' = ConE $ mkName $ unpack $ unHaskellName $ entityHaskell t+ xs <- mapM (const $ newName "x") $ entityFields t fs <- [|fromPersistValue|] let xs' = map (AppE fs . VarE) xs let pat = ListP $ map VarP xs ap' <- [|apE|] just <- [|Right|]- let cons' = just `AppE` cons+ let cons'' = just `AppE` cons' return- [ Clause [pat] (NormalB $ foldl (go ap') cons' xs') []+ [ Clause [pat] (NormalB $ foldl (go ap') cons'' xs') [] , Clause [WildP] (NormalB nothing) [] ] where@@ -233,55 +299,100 @@ mkEntity :: MkPersistSettings -> EntityDef -> Q [Dec] mkEntity mps t = do t' <- lift t- let name = entityName t- let clazz = ConT ''PersistEntity `AppT` (ConT (mkName $ entityName t ++ suffix) `AppT` VarT (mkName "backend"))- tpf <- mkToPersistFields [(name, length $ entityColumns t)]+ let name = unpack $ unHaskellName $ entityHaskell t+ let clazz = ConT ''PersistEntity `AppT` (ConT (mkName $ unpack $ unHaskellName (entityHaskell t) ++ suffix) `AppT` VarT (mkName "backend"))+ tpf <- mkToPersistFields [(name, length $ entityFields t)] fpv <- mkFromPersistValues t utv <- mkUniqueToValues $ entityUniques t puk <- mkUniqueKeys t- let colnames = map (unRawName . rawFieldName) $ entityColumns t- idname = unRawName $ rawTableIdName t- idname_ = (if idname `elem` colnames then (++"_") else id) idname- fields <- mapM (mkField t) $ ColumnDef idname_ (entityName t ++ "Id") [] : entityColumns t+ fields <- mapM (mkField t) $ FieldDef+ (HaskellName "Id")+ (entityID t)+ (FieldType $ unHaskellName (entityHaskell t) ++ "Id") []+ : entityFields t+ toFieldNames <- mkToFieldNames $ entityUniques t return $ [ dataTypeDec t- , TySynD (mkName $ entityName t) [] $- ConT (mkName $ entityName t ++ suffix) `AppT` mpsBackend mps- , TySynD (mkName $ entityName t ++ "Id") [] $- ConT ''Key `AppT` mpsBackend mps `AppT` ConT (mkName $ entityName t)+ , TySynD (mkName $ unpack $ unHaskellName $ entityHaskell t) [] $+ ConT (mkName $ unpack $ unHaskellName (entityHaskell t) ++ suffix)+ `AppT` mpsBackend mps+ , TySynD (mkName $ unpack $ unHaskellName (entityHaskell t) ++ "Id") [] $+ ConT ''Key `AppT` mpsBackend mps `AppT` ConT (mkName $ unpack $ unHaskellName $ entityHaskell t) , InstanceD [] clazz $ [ uniqueTypeDec t , FunD (mkName "entityDef") [Clause [WildP] (NormalB t') []] , tpf , FunD (mkName "fromPersistValues") fpv- , mkHalfDefined name $ length $ entityColumns t- , mkToFieldNames $ entityUniques t+ , mkHalfDefined name $ length $ entityFields t+ , toFieldNames , utv , puk , DataInstD [] ''EntityField- [ ConT (mkName $ entityName t ++ suffix) `AppT` VarT (mkName "backend")+ [ ConT (mkName $ unpack $ unHaskellName (entityHaskell t) ++ suffix) `AppT` VarT (mkName "backend") , VarT $ mkName "typ" ] (map fst fields) []- , FunD (mkName "persistColumnDef") (map snd fields)+ , FunD (mkName "persistFieldDef") (map snd fields)+ , TySynInstD+ (mkName "PersistEntityBackend")+ [ConT (mkName $ unpack $ unHaskellName (entityHaskell t) ++ suffix) `AppT` VarT (mkName "backend")]+ (VarT (mkName "backend"))+ , FunD (mkName "persistIdField") [Clause [] (NormalB $ ConE $ mkName $ unpack $ unHaskellName (entityHaskell t) ++ "Id") []] ] ] -updateConName :: String -> String -> PersistUpdate -> String+-- | produce code similar to the following+-- instance PersistEntity e => PersistField e where+-- toPersistValue = PersistMap $ zip columNames (map toPersistValue . toPersistFields)+-- fromPersistValue (PersistMap o) = fromPersistValues $ map (\(_,v) ->+-- casefromPersistValue v of+-- Left e -> error e+-- Right r -> r) o+-- fromPersistValue x = Left $ "Expected PersistMap, received: " ++ show x +-- sqlType _ = SqlString+persistFieldFromEntity :: EntityDef -> Q [Dec]+persistFieldFromEntity e = do+ ss <- [|SqlString|]+ unexpected <- [|\x -> Left $ "Expected PersistMap, received: " ++ T.pack (show x)|]+ let columnNames = map (unpack . unHaskellName . fieldHaskell) (entityFields e)+ obj <- [|PersistMap $ zip (map pack columnNames) (map toPersistValue $ toPersistFields e)|]+ pmName <- newName "pm"+ fpv <- [|\x -> fromPersistValues $ map (\(_,v) -> case fromPersistValue v of+ Left e' -> error $ unpack e'+ Right r -> r) x|]+ return+ [ InstanceD [] (ConT ''PersistField `AppT` ConT (mkName $ unpack $ unHaskellName $ entityHaskell e))+ [ FunD (mkName "sqlType") [ Clause [WildP] (NormalB ss) [] ]+ , FunD (mkName "toPersistValue") [ Clause [] (NormalB obj) [] ]+ , FunD (mkName "fromPersistValue")+ [ Clause [ConP (mkName "PersistMap") [VarP pmName]]+ (NormalB $ fpv `AppE` VarE pmName) []+ , Clause [WildP] (NormalB unexpected) []+ ]+ ]+ ]++updateConName :: Text -> Text -> PersistUpdate -> Text updateConName name s pu = concat [ name , upperFirst s , case pu of Assign -> ""- _ -> show pu+ _ -> pack $ show pu ] +-- | Apply the given list of functions to the same @EntityDef@s.+--+-- This function is useful for cases such as:+--+-- >>> share [mkSave "myDefs", mkPersist sqlSettings] [persistLowerCase|...|] share :: [[EntityDef] -> Q [Dec]] -> [EntityDef] -> Q [Dec]-share fs x = fmap concat $ mapM ($ x) fs+share fs x = fmap mconcat $ mapM ($ x) fs +-- | Deprecated, restricted version of 'share'. share2 :: ([EntityDef] -> Q [Dec]) -> ([EntityDef] -> Q [Dec]) -> [EntityDef]@@ -289,8 +400,10 @@ share2 f g x = do y <- f x z <- g x- return $ y ++ z+ return $ y `mappend` z+{-# DEPRECATED share2 "Use share instead" #-} +-- | Save the @EntityDef@s passed in under the given name. mkSave :: String -> [EntityDef] -> Q [Dec] mkSave name' defs' = do let name = mkName name'@@ -300,12 +413,13 @@ ] data Dep = Dep- { depTarget :: String- , depSourceTable :: String- , depSourceField :: String+ { depTarget :: Text+ , depSourceTable :: HaskellName+ , depSourceField :: HaskellName , depSourceNull :: Bool } +-- | Generate a 'DeleteCascade' instance for the given @EntityDef@s. mkDeleteCascade :: [EntityDef] -> Q [Dec] mkDeleteCascade defs = do let deps = concatMap getDeps defs@@ -313,23 +427,25 @@ where getDeps :: EntityDef -> [Dep] getDeps def =- concatMap getDeps' $ entityColumns def+ concatMap getDeps' $ entityFields def where- getDeps' (ColumnDef name typ attribs) =+ getDeps' :: FieldDef -> [Dep]+ getDeps' (FieldDef name _ ftyp attribs) = let isNull = nullable attribs- l = length typ+ typ = unFieldType ftyp+ l = T.length typ (f, b) = splitAt (l - 2) typ in if b == "Id" then return Dep { depTarget = f- , depSourceTable = entityName def+ , depSourceTable = entityHaskell def , depSourceField = name , depSourceNull = isNull } else [] go :: [Dep] -> EntityDef -> Q Dec- go allDeps EntityDef{entityName = name} = do- let deps = filter (\x -> depTarget x == name) allDeps+ go allDeps EntityDef{entityHaskell = name} = do+ let deps = filter (\x -> depTarget x == unHaskellName name) allDeps key <- newName "key" del <- [|delete|] dcw <- [|deleteCascadeWhere|]@@ -337,27 +453,34 @@ filt <- [|Filter|] eq <- [|Eq|] left <- [|Left|]- let mkStmt dep = NoBindS+ let mkStmt :: Dep -> Stmt+ mkStmt dep = NoBindS $ dcw `AppE` ListE- [ filt `AppE` ConE (mkName filtName)+ [ filt `AppE` ConE (mkName $ unpack filtName) `AppE` (left `AppE` val (depSourceNull dep)) `AppE` eq ] where- filtName = depSourceTable dep ++ upperFirst (depSourceField dep)+ filtName = unHaskellName (depSourceTable dep) +++ upperFirst (unHaskellName $ depSourceField dep) val False = VarE key val True = just `AppE` VarE key - let stmts = map mkStmt deps ++ [NoBindS $ del `AppE` VarE key]+ let stmts :: [Stmt]+ stmts = map mkStmt deps `mappend`+ [NoBindS $ del `AppE` VarE key] return $ InstanceD- []+ [ ClassP ''PersistQuery [VarT $ mkName "backend", VarT $ mkName "m"]+ , ClassP ''Monad [VarT $ mkName "m"]+ ] (ConT ''DeleteCascade `AppT`- (ConT (mkName $ name ++ suffix) `AppT` VarT (mkName "backend"))+ (ConT (mkName $ unpack $ unHaskellName name ++ suffix) `AppT` VarT (mkName "backend")) `AppT` VarT (mkName "backend")+ `AppT` VarT (mkName "m") ) [ FunD (mkName "deleteCascade") [Clause [VarP key] (NormalB $ DoE stmts) []]@@ -369,14 +492,20 @@ return $ FunD (mkName "persistUniqueKeys") [c] where clause = do- xs <- forM (entityColumns def) $ \(ColumnDef x _ _) -> do- x' <- newName $ '_' : x+ xs <- forM (entityFields def) $ \(FieldDef x _ _ _) -> do+ x' <- newName $ '_' : unpack (unHaskellName x) return (x, x') let pcs = map (go xs) $ entityUniques def- let pat = ConP (mkName $ entityName def) $ map (VarP . snd) xs+ let pat = ConP+ (mkName $ unpack $ unHaskellName $ entityHaskell def)+ (map (VarP . snd) xs) return $ Clause [pat] (NormalB $ ListE pcs) []- go xs (UniqueDef name cols) =- foldl (go' xs) (ConE (mkName name)) cols++ go :: [(HaskellName, Name)] -> UniqueDef -> Exp+ go xs (UniqueDef name _ cols) =+ foldl' (go' xs) (ConE (mkName $ unpack $ unHaskellName name)) (map fst cols)++ go' :: [(HaskellName, Name)] -> Exp -> HaskellName -> Exp go' xs front col = let Just col' = lookup col xs in front `AppE` VarE col'@@ -392,7 +521,7 @@ case fromPersistValue v of Left e -> Left e Right s' ->- case reads s' of+ case reads $ unpack s' of (x, _):_ -> Right x [] -> Left $ "Invalid " ++ dt ++ ": " ++ s'|] return@@ -438,26 +567,52 @@ _ -> DoE `fmap` mapM toStmt defs toStmt :: EntityDef -> Q Stmt toStmt ed = do- let n = entityName ed+ let n = entityHaskell ed u <- [|undefined|] m <- [|migrate|]- let u' = SigE u $ ConT $ mkName n- return $ NoBindS $ m `AppE` u'+ defs' <- lift defs+ let u' = SigE u $ ConT $ mkName $ unpack $ unHaskellName n+ return $ NoBindS $ m `AppE` defs' `AppE` u' instance Lift EntityDef where- lift (EntityDef a b c d e) = do- x <- [|EntityDef|]- a' <- lift a- b' <- lift b- c' <- lift c- d' <- lift d- e' <- lift e- return $ x `AppE` a' `AppE` b' `AppE` c' `AppE` d' `AppE` e'-instance Lift ColumnDef where- lift (ColumnDef a b c) = [|ColumnDef $(lift a) $(lift b) $(lift c)|]+ lift (EntityDef a b c d e f g h) =+ [|EntityDef+ $(lift a)+ $(lift b)+ $(lift c)+ $(liftTs d)+ $(lift e)+ $(lift f)+ $(liftTs g)+ $(liftMap h)+ |]+instance Lift FieldDef where+ lift (FieldDef a b c d) = [|FieldDef $(lift a) $(lift b) $(lift c) $(liftTs d)|] instance Lift UniqueDef where- lift (UniqueDef a b) = [|UniqueDef $(lift a) $(lift b)|]+ lift (UniqueDef a b c) = [|UniqueDef $(lift a) $(lift b) $(lift c)|] +liftT :: Text -> Q Exp+liftT t = [|pack $(lift (unpack t))|]++liftTs :: [Text] -> Q Exp+liftTs = fmap ListE . mapM liftT++liftTss :: [[Text]] -> Q Exp+liftTss = fmap ListE . mapM liftTs++liftMap :: Map.Map Text [[Text]] -> Q Exp+liftMap m = [|Map.fromList $(fmap ListE $ mapM liftPair $ Map.toList m)|]++liftPair :: (Text, [[Text]]) -> Q Exp+liftPair (t, ts) = [|($(liftT t), $(liftTss ts))|]++instance Lift HaskellName where+ lift (HaskellName t) = [|HaskellName $(liftT t)|]+instance Lift DBName where+ lift (DBName t) = [|DBName $(liftT t)|]+instance Lift FieldType where+ lift (FieldType t) = [|FieldType $(liftT t)|]+ instance Lift PersistFilter where lift Eq = [|Eq|] lift Ne = [|Ne|]@@ -467,7 +622,7 @@ lift Le = [|Le|] lift In = [|In|] lift NotIn = [|NotIn|]- lift (BackendSpecificFilter x) = [|BackendSpecificFilter $(lift x)|]+ lift (BackendSpecificFilter x) = [|BackendSpecificFilter $(liftT x)|] instance Lift PersistUpdate where lift Assign = [|Assign|]@@ -476,7 +631,7 @@ lift Multiply = [|Multiply|] lift Divide = [|Divide|] -mkField :: EntityDef -> ColumnDef -> Q (Con, Clause)+mkField :: EntityDef -> FieldDef -> Q (Con, Clause) mkField et cd = do let con = ForallC []@@ -491,21 +646,32 @@ {- bod <- [|Field $(lift cd)|] return- [ SigD name $ ConT ''Field `AppT` ConT (mkName $ entityName et) `AppT` typ+ [ SigD name $ ConT ''Field `AppT` ConT (mkName $ entityHaskell et) `AppT` typ , FunD name [Clause [] (NormalB bod) []] ] -} where- name = mkName $ concat [entityName et, upperFirst $ columnName cd]+ name = mkName $ unpack $ concat+ [ unHaskellName $ entityHaskell et+ , upperFirst $ unHaskellName $ fieldHaskell cd+ ] base =- if "Id" `isSuffixOf` columnType cd+ if "Id" `isSuffixOf` unFieldType (fieldType cd) then ConT ''Key `AppT` (VarT $ mkName "backend")- `AppT` (ConT (mkName $ take (length (columnType cd) - 2) (columnType cd) ++ suffix) `AppT` VarT (mkName "backend"))- else ConT (mkName $ columnType cd)- typ = if nullable $ columnAttribs cd+ `AppT`+ let len = T.length (unFieldType $ fieldType cd) - 2+ ft = take len $ unFieldType $ fieldType cd+ con = ConT $ mkName $ unpack $ ft ++ suffix+ in con `AppT` VarT (mkName "backend")+ else ConT $ mkName $ unpack $ unFieldType $ fieldType cd+ typ = if nullable $ fieldAttrs cd then ConT ''Maybe `AppT` base else base -suffix :: String+suffix :: Text suffix = "Generic"++infixr 5 +++(++) :: Text -> Text -> Text+(++) = append
persistent-template.cabal view
@@ -1,5 +1,5 @@ name: persistent-template-version: 0.6.3.1+version: 0.7.0 license: BSD3 license-file: LICENSE author: Michael Snoyman <michael@snoyman.com>@@ -15,10 +15,11 @@ library build-depends: base >= 4 && < 5 , template-haskell- , persistent >= 0.6.2 && < 0.7+ , persistent >= 0.7 && < 0.8 , monad-control >= 0.2 && < 0.4 , text >= 0.5 && < 1.0 , transformers >= 0.2+ , containers exposed-modules: Database.Persist.TH ghc-options: -Wall