使用PostGreSQL和Persistent

时间:2019-07-15 16:05:55

标签: postgresql haskell haskell-persistent

我正在尝试学习持久性库。

我有两个文件,其中一个具有为项目定义的所有类型(饮食跟踪器)

Report.hs

data FoodEntry = FoodEntry { report :: Report
                           , date   :: UTCTime
                           }

data Report = Report { ...
                       ...
                     }

和另一个用于生成表格的文件

Storage.hs

import           Database.Persist.Sql                                                                                        
import qualified Database.Persist.TH  as PTH                                                                                 


PTH.share [ PTH.mkPersist PTH.sqlSettings                                                                                    
          , PTH.mkMigrate "migrateAll"                                                                                       
          ]                                                                                                                  
  [PTH.persistLowerCase|                                                                                                     
   FoodEntry sql=entries                                                                                                     
    report Report                                                                                                            
    date UTCTime default=now()                                                                                               
    UniqueDate date                                                                                                          
   Report sql=reports                                                                                                        
    name Text                                                                                                                
    reportingUnit Text                                                                                                       
    nutrients [Nutrient]                                                                                                     
   Nutrient sql=nutrients                                                                                                    
    nutrientName Text                                                                                                        
    nutrientUnit Text                                                                                                        
    nutrientValue Double Maybe                                                                                               
    deriving Show Read                                                                                                       
|] 

和一个处理迁移的文件

import           Control.Monad.Logger                                                                                        
import           Database.Persist                                                                                            
import           Database.Persist.Postgresql                                                                                 
import           Types.Storage                                                                                               

connString :: ConnectionString                                                                                               
connString = "host=127.0.0.1 port=5432 user=postgres dbname=postgres password=password"                                      

runAction                                                                                                                    
  :: (MonadUnliftIO m, IsPersistBackend r,                                                                                   
      BaseBackend r ~ SqlBackend) =>                                                                                         
     ConnectionString -> ReaderT r (LoggingT m) a -> m a                                                                     
runAction connectionString action = runStdoutLoggingT                                                                        
                                    $ withPostgresqlConn connectionString                                                    
                                    $ \backend ->                                                                            
                                        runReaderT action backend                                                            

migrateDB :: IO ()                                                                                                           
migrateDB = runAction connString (runMigration migrateAll) 

在我的[ProjectName.hs]所调用的main文件中

  args <- parseArgs -- args - optparse-applicative                                                                                                          

  if generateDB args == Just True                                                                                            
    then migrateDB                                                                                                           
    else case (...) of                                         
           ...                                 -> ...  
           ...                                 -> ...                                                
           (s, n, p, Just True)                -> undefined 

对于最后一种情况,我想将用户条目添加到数据库中。

我还有一个函数searchReport,该函数使用snp返回Report类型。

我想做这样的事情

insertReport :: (MonadIO m) => UTCTime -> Report -> SqlPersistT m (Key FoodEntry)          
insertReport time report' = insert (FoodEntry report' time)

do date' <- Data.Time.Clock.getCurrentTime :: IO UTCTime
   report' <- searchReport s n p :: IO Report
   insertReport $ date' report'

但是(AFAIK)有两个问题

  1. Report.FoodEntry的类型与该类型不匹配 Storage.FoodEntry我可以编写一个函数,将其转换为 另一个,但我想知道是否还有更好的方法。

  2. 如果我要像这样测试该功能块

    (s, n, p, Just True)                -> insertReport undefined undefined 
    

    我遇到错误

    • Couldn't match type ‘ReaderT                                      
                         Database.Persist.Sql.Types.Internal.SqlBackend m0’                                                  
             with ‘IO’                            
    Expected type: IO ()                                                
    Actual type: persistent-2.9.2:Database.Persist.Sql.Types.SqlPersistT
                m0                                                                                                        
               (persistent-2.9.2:Database.Persist.Class.PersistEntity.Key          
                      Types.Storage.FoodEntry)                                                             
    

1 个答案:

答案 0 :(得分:1)

要从insertReport monad运行IO,您必须调用runAction connectionString insertReport。这实际上就是将SqlPersistT转换为IO的原因。

对于Report.FoodEntryStorage.FoodEntry之间的区别-为什么您首先要使用两种数据类型?您在PTH.share准引用中声明的实体也是有效的Haskell数据类型,因此您可以像其他任何类型一样使用它。

但是,如果您确实需要两个不同的FoodEntry,那么可以,您需要编写一个在它们之间转换的函数。