Yesod Persistent использует Aeson для анализа UTCTime в записи

У меня есть моя модель от models.persistentmodels

...

Thing
    title Text
    price Int 
    kosher Bool
    optionalstuff [Text] Maybe
    createdat UTCTime
    updatedat UTCTime
    deriving Show

...

Он содержит два поля времени: UTCTime.

Через AJAX я получаю почти Thing в формате JSON. Но у пользователя JSON не должно быть createdat и updatedat или kosher. Значит, нам нужно их заполнить.

postNewEventR = do
    inputjson <- requireCheckJsonBody :: Handler Value
...
    -- get rawstringofthings from inputjson
...

    let objectsMissingSomeFields = case (decode (BL.fromStrict $ TE.encodeUtf8 rawstringofthings) :: Maybe [Object]) of
                        Nothing -> error "Failed to get a list of raw objects."
                        Just x  -> x

    now <- liftIO getCurrentTime

    -- Solution needs to go here:
    let objectsWithAllFields = objectsMissingSomeFields

    -- We hope to be done
    let things = case (eitherDecode $ encode objectsWithAllFields) :: Either String [Thing] of
                        Left err -> error $ "Failed to get things because: " <> err
                        Right xs  -> xs

Ошибка «Не удалось получить вещи» появляется здесь, потому что в проанализированных нами объектах JSON отсутствуют поля, необходимые в модели.


person bg2000 Reinstate Monica    schedule 29.12.2019    source источник


Ответы (1)


Решение

let objectsWithAllFields = Import.map (tackOnNeccessaryThingFields now True) objectsMissingSomeFields

Итак, мы берем текущий объект и добавляем недостающие поля, например. kosher и createdat.

Но есть какая-то странная разница в том, как UTCTime read по сравнению с способом aeon анализировать UTCTime. Поэтому, когда я печатаю UTCTime в Aeson String, мне нужно распечатать UTCTime в формате, который ожидается позже:

tackOnNeccessaryThingFields :: UTCTime -> Bool -> Object -> Object
tackOnNeccessaryThingFields t b hm = G.fromList $ (G.toList hm) <> [
                                                                              ("createdat", String (pack $ formatTime defaultTimeLocale "%FT%T%QZ" t)),
                                                                              ("updatedat", String (pack $ formatTime defaultTimeLocale "%FT%T%QZ" t)),
                                                                              ("kosher", Bool b)
                                                                 ]

tackOnNeccessaryThingFields _ _ _ = error "This isn't an object."

После этого исправления у объекта есть все поля, необходимые для создания записи, поэтому код дает [Thing]. А также код работает без ошибок времени выполнения, вместо того, чтобы не анализировать tshow t как UTCTime.

Примечание. Эта проблема aeson github, посвященная этой проблеме, похоже, закрыта, но, похоже, она больше не разрешительна: https://github.com/bos/aeson/issues/197

Спасибо Артёму: https://artyom.me/aeson#records-and-json-generics

Спасибо Pbrisbin: https://pbrisbin.com/posts/writing_json_apis_with_yesod/

Спасибо Snoyman: за все

person bg2000 Reinstate Monica    schedule 29.12.2019