2016-03-06 26 views
1

我的数据库中的每张表格都需要有一个created_atupdated_at字段用于一般卫生和家务管理。这导致持久性模型看起来是这样的:如何处理记录类型中的“内务”字段?

User 
    email String Maybe 
    name String Maybe 
    tgramUserId TgramUserId Maybe 
    createdAt UTCTime 
    updatedAt UTCTime 
    deriving Show 

现在,我有用于创建用户的一串的API,根据不同的业务情况。例如:

  • createUserFromWebForm
  • createUserFromTelegram
  • createUserFromOAuth

我想每个API的类型的签名是:

createUserFromX :: User -> SqlPersistM (Entity User) 

然而,这意味着每个呼叫站点createUserFromX需要拨打getCurrentTime并设置createdAtupdatedAt管家字段。在这些API中本地化这种复杂性的方法是什么?

一个不洁(IMO)的解决方案是将签名改为:

createUserFromTelegram :: Maybe TgramUserId -> SqlPersistM (Entity User) 

...但是,违背了摆在首位使用记录类型的目的(在这个特殊的例子,你可能支持这种方法,但如果记录类型有10个字段会怎么样)?

+1

您的所有功能处理'User'它应该要简单地重构一个像'updateTimes :: User - > IO User'这样的函数并使用它 - 如果你想为'User'做更多的事情,那么你可能想为这个引入一些类型类 – Carsten

回答

3

但是,这意味着每个createUserFromX的调用站点需要调用getCurrentTime并设置createdAt和updatedAt管家字段。

这是不正确的。的SqlPersistM的定义是:

type SqlPersistM = SqlPersistT (NoLoggingT (ResourceT IO)) 
type SqlPersistT = ReaderT SqlBackend 

所以SqlPersistM已MonadIO的实例,可以在里面你createUserFromX通过liftIO your_io_action执行任何IO动作:

createUserFromX :: User -> SqlPersistM (Entity User) 
createUserFromX user = do 
    utctime <- liftIO getCurrentTime 
    let user' = user { createdAt = utctime, updatedAt = utctime } 
    -- your codes