«Нет экземпляра для (MonadLevelDB IO)» ошибка компиляции в наборе тестов - PullRequest
0 голосов
/ 25 апреля 2019

Я пытаюсь использовать upper-leveldb в своем приложении на Haskell, и в моем тестовом наборе я получаю ошибку компиляции, которую я не понимаю (или, по крайней мере, у меня нет знаний дляисправьте это правильно).

Для контекста у меня есть следующий помощник для извлечения и декодирования пользователя из базы данных:

getUser :: (MonadLevelDB m) => Text -> m (Maybe User)
getUser uuid = do
  let key = toStrict . encode $ uuid
  result <- LevelDB.get key -- m (Maybe Value)
  case result of
      Just value -> return ( decodeStrict' value :: Maybe User) -- Ideal type
      Nothing    -> return Nothing

И следующий набор тестов:


type EuphrateMonad m = (MonadLevelDB m, MonadUnliftIO m, MonadIO m)

main :: IO ()
main = runCreateLevelDB "/tmp/mydb" "test" levelDBMain

levelDBMain :: (EuphrateMonad m) => m ()
levelDBMain = do
    setup
    test <- liftIO $ testSpec "euphrate" spec
    liftIO $ Test.Tasty.defaultMain test


spec :: Spec
spec = parallel $ do
    it "Fetch an already-existing user" $ do
        user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
        user `shouldBe` ( Just $ User "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "" )

    it "Delete a user" $ do
      deleteUser "2e940724-936e-4700-826b-367faabac141"
      user <- getUser "2e940724-936e-4700-826b-367faabac141"
      user `shouldBe` Nothing

users :: [User]
users = [ User "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" ""
        , User "Jérôme" "2e940724-936e-4700-826b-367faabac141" False "jéjédu32" "nah."
        ]

setup :: (EuphrateMonad m) => m ()
setup =
  for_ users createUser

Теперь ошибка, которую я получаю:

euphrate/test/Main.hs:29:17: error:
    • No instance for (MonadLevelDB IO) arising from a use of ‘getUser’
    • In a stmt of a 'do' block:
        user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
      In the second argument of ‘($)’, namely
        ‘do user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
            user
              `shouldBe`
                (Just
                   $ User
                       "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "")’
      In a stmt of a 'do' block:
        _ <- it "Fetch an already-existing user"
               $ do user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
                    user
                      `shouldBe`
                        (Just
                           $ User
                               "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "")
   |
29 |         user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Я в первую очередь ищу способы лучше понять ситуации такого типа.У меня есть некоторые базовые знания о преобразователях через Reader и Writer, но мне не очень помогает то, что я знаю об этом.

Спасибо за чтение:)

1 Ответ

1 голос
/ 25 апреля 2019

Я не знаком с более высокоуровневой БД, но, судя по виду кода, проблема, вероятно, заключается в том, что когда вы пишете такие строки:

spec :: Spec
spec = parallel $ do
    it "Fetch an already-existing user" $ do
        user <- getUser "664798e1-7fac-4e0b-9fc6-757f4fb0409c"
        user `shouldBe` ( Just $ User "toto" "664798e1-7fac-4e0b-9fc6-757f4fb0409c" True "toto92" "" )

Вы находитесь не в монадическом контексте, который вам нужен. Используя it, вы живете только в контексте hspec, который не знает всех вещей, связанных с БД. Взгляните на (довольно абстрактную) подпись it:

it :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)

Мы далеки от ограничения вашего стека EuphrateMonad. Поэтому вам нужно добавить что-то промежуточное, чтобы ввести требуемый контекст (получение соединения с levelDB, управление транзакциями и т. Д.).

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

...