1

我正在尝试学习持久库。

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

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, s&np返回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. 如果我要像这样测试那个 do 块中的函数

    (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)                                                             
    
4

1 回答 1

1

insertReport要从monad运行,IO您必须调用runAction connectionString insertReport. 这就是实际转换SqlPersistTIO.

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

但是,如果您真的需要 2 个不同的FoodEntryes,那么是的,您需要编写一个在它们之间转换的函数。

于 2019-07-16T07:28:55.860 回答