在fromJson中插入默认时间戳

时间:2014-07-01 02:05:34

标签: haskell yesod aeson

我有一个ajax调用将json发送到Yesod中的路由,我希望路由解析json并将其直接插入数据库。在我的模型文件中我有

createtime UTCTime default=now()

因为客户端没有向下发送创建时间而阻止解析json。我尝试为日志条目编写自己的parseJson,但由于getCurrentTime在IO monad中返回一个值,因此我无法插入UTCTime默认值。如果可能,我希望数据库设置值。

此时我唯一能想到的是创建类似LogEntryWithoutTime的类型,将JSON解析为该类并转换为LogEntry。有更简单的方法吗?

修改 我展示了三个不同的失败,将getCurrentTime添加到JSON解析中。首先,目的是解析createtime(如果可用),并默认为服务器上的getCurrentTime。这无论如何都是对的,因为我们不应该依赖客户的时间。

instance FromJSON Log where
    parseJSON (Object o) = Log
        <$> o .: "userid"
        ...
        <*> o .:? "createtime" .!= liftIO getCurrentTime

错误是

Model.hs:58:32:
Couldn't match expected type ‘UTCTime’
            with actual type ‘m0 UTCTime’
In the second argument of ‘(.!=)’, namely ‘liftIO getCurrentTime’
In the second argument of ‘(<*>)’, namely
  ‘o .:? "createtime" .!= liftIO getCurrentTime’

其次,我试着获取当前时间。

<*> liftIO getCurrentTime

我收到了错误

Model.hs:58:9:
No instance for (MonadIO
                   aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser)
  arising from a use of ‘liftIO’
In the second argument of ‘(<*>)’, namely ‘liftIO getCurrentTime’

如果我将行更改为

<*> getCurrentTime

然后我得到

Model.hs:58:9:
Couldn't match type ‘IO’
              with ‘aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser’
Expected type: aeson-0.7.0.6:Data.Aeson.Types.Internal.Parser
                 UTCTime
  Actual type: IO UTCTime

2 个答案:

答案 0 :(得分:1)

在模型中定义default属性的事情是,在持久化实体时仍需要定义所有值。据我所知,默认值仅适用于自动迁移和模式定义。

尝试从IO monad中提取getCurrentTime(使用liftIO)。

答案 1 :(得分:0)

我现在面临着同样的问题。我目前的想法是,由于我不希望用户向我提供完整的记录,因此我不应该以这种方式对其进行建模。相反,我应该模拟我期望从用户那里获得的请求主体,并将其转换为存储空间。

所以,你可能有PartialLog的概念,它只有你希望用户发送的字段:

data PartialLog = PartialLog { partialLogMessage :: Text }

然后你可能有一个填补空白的功能并为你提供完整的记录:

{-# LANGUAGE RecordWildCards #-}

logFromPartial :: PartialLog -> UserId -> IO Log
logFromPartial p u = do
  let logUserId  = u
      logMessage = partialLogMessage p
  logCreatetime <- liftIO getCurrentTime
  return Log{..}

n.b。我正在传递UserId,因为我们可能希望该值来自经过身份验证的会话;用户无需告诉我们他们的ID是什么。