7

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

createtime UTCTime default=now()

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

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

编辑: 我展示了将 getCurrentTime 添加到 JSON 解析的三种不同失败。首先,目的是解析创建时间(如果可用),并且默认为服务器上的 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
4

2 回答 2

1

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

getCurrentTime尝试从 IO monad 中解除(使用liftIO)。

于 2014-07-11T12:43:29.163 回答
0

我现在面临着基本相同的问题。我目前的想法是,由于我不希望用户向我提供完整的记录,所以我不应该那样建模。相反,我应该对用户期望的请求主体进行建模,并自己对其进行转换以进行存储。

因此,您可能有 a 的概念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{..}

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

于 2017-08-01T09:25:00.010 回答