Вставить отметку времени по умолчанию в fromJson

У меня есть вызов ajax, отправляющий json на маршрут в Yesod, и я хочу, чтобы маршрут анализировал json и вставлял его непосредственно в базу данных. В моем файле модели у меня есть

createtime UTCTime default=now()

что препятствует синтаксическому анализу json, поскольку клиент не отправляет время создания. Я попытался написать свой собственный parseJson для записей журнала, но мне не удалось вставить UTCTime по умолчанию, так как getCurrentTime возвращает значение в монаде IO. Я бы хотел, чтобы база данных установила значение, если это возможно.

Единственное, что я могу придумать на данный момент, это создать тип, подобный 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

person user3776949    schedule 01.07.2014    source источник
comment
Вы разобрались с этой проблемой? Я борюсь с этим сейчас.   -  person Christopher Gillis    schedule 23.07.2015
comment
Извините, мне не удалось найти хорошее решение.   -  person user3776949    schedule 03.08.2015


Ответы (2)


Проблема с атрибутом default, определенным в модели, заключается в том, что вам все равно нужно определить все значения при сохранении объектов. Насколько мне известно, значения по умолчанию существуют только для автоматической миграции и определения схемы.

Попробуйте поднять getCurrentTime из монады IO (с liftIO).

person ms.    schedule 11.07.2014
comment
Я вижу, что файл модели не влияет на код Haskell, поэтому я написал необработанный SQL для вставки строки. Я пытался использовать liftIO, когда задавал этот вопрос, и это не сработало, но я не помню точную ошибку. Я думаю, он пытался поместить его в другую монаду, но другой монады не было. - person user3776949; 14.07.2014
comment
Нет экземпляра для (MonadIO aeson-0.8.0.2:Data.Aeson.Types.Internal.Parser) - person Christopher Gillis; 23.07.2015

Я сейчас столкнулся практически с той же проблемой. В настоящее время я думаю, что, поскольку я не ожидаю, что пользователь предоставит мне полную запись, я не должен моделировать ее таким образом. Вместо этого я должен смоделировать тело запроса, которое я ожидаю от пользователя, и преобразовать его для хранения.

Таким образом, у вас может быть концепция 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, потому что мы можем захотеть, чтобы это значение пришло из аутентифицированного сеанса; пользователю не нужно сообщать нам свой идентификатор.

person Jezen Thomas    schedule 01.08.2017