给出其整数键获取持久记录?

时间:2015-11-26 08:08:04

标签: haskell haskell-persistent

我正在尝试使用Persistent with Servant,因此我无法自动将URL段解析为Persistent键。相反,我已将路由设置为需要Int64,并且我想使用它来检索记录以执行主键查找。

Everything I've found points to using toSqlKey将一个整数转换为一个键,所以我尝试编写一个非常简单的函数来为我做这个:

runDB :: (MonadBaseControl IO m, MonadIO m) => (SqlPersistT (NoLoggingT (ResourceT m))) a -> m a
runDB actions = do
  filename <- liftIO $ getEnv "SQLITE_FILENAME"
  runSqlite (pack filename) actions

getRecordByKey :: Int64 -> IO (Maybe (Entity Record))
getRecordByKey recordId = runDB $ get (toSqlKey recordId)

不幸的是,这不起作用;我收到以下类型错误:

Couldn't match expected type ‘PersistEntityBackend
                                (Entity Record)’
            with actual type ‘SqlBackend’
In the second argument of ‘($)’, namely ‘get (toSqlKey recordId)’
In the expression: runDB $ get (toSqlKey recordId)
In an equation for ‘getRecordByKey’:
    getRecordByKey recordId = runDB $ get (toSqlKey recordId)

有点了解此错误 - 我查找了gettoSqlKey的类型,并且它们包含相关约束:

get :: (MonadIO m, backend ~ PersistEntityBackend val, PersistEntity val) => Key val -> ReaderT backend m (Maybe val)
toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record

如果我理解正确,backendPersistEntityBackend val必须是同一类型,但toSqlKey强制执行SqlBackend约束,因此类型不匹配。我的直觉告诉我PersistentEntityBackend (Entity Record) 应该是 SqlBackend,但显然我错了。不过,我不知道为什么或怎么做。

无论如何,我不知道在这个分析中我是对还是错,但不管怎样,我不知道如何解决这个问题或者做到这一点的正确方法是什么。在给定整数的情况下,如何从数据库中获取记录?

2 个答案:

答案 0 :(得分:2)

这对我有用(可能取决于你的软件包的版本......遗憾的是):

{-# LANGUAGE FlexibleContexts #-}
module Stackoverlflow where

import Control.Monad.IO.Class (MonadIO, liftIO)
import Control.Monad.Logger(NoLoggingT)
import Control.Monad.Trans.Control (MonadBaseControl)
import Control.Monad.Trans.Resource (ResourceT)
import Data.Int (Int64)
import Data.Text (pack)
import Database.Persist.Class (ToBackendKey, get)
import Database.Persist.Sql (SqlBackend, SqlPersistT, toSqlKey)
import Database.Persist.Sqlite(runSqlite)
import Database.Persist.Types (Entity)
import System.Environment (getEnv)

runDB :: (MonadBaseControl IO m, MonadIO m) =>
        (SqlPersistT (NoLoggingT (ResourceT m))) a -> m a
runDB actions = do
  filename <- liftIO $ getEnv "SQLITE_FILENAME"
  runSqlite (pack filename) actions

getRecordByKey :: (MonadIO m, ToBackendKey SqlBackend val, MonadBaseControl IO m) =>
                 Int64 -> m (Maybe val)
getRecordByKey recordId = runDB $ get (toSqlKey recordId)

正如你所看到的,我刚刚添加了很多类型的注释(GHC在我删除了签名并要求它告诉我之后就做了;)

另请注意,我没有Record,因此您应该可以轻松摆脱... val内容!

答案 1 :(得分:1)

那么直接将Key record设为FromText / ToText的实例并直接使用网址中的键会怎样?

{-# LANGUAGE FlexibleContexts               #-}
{-# LANGUAGE UndecidableInstances               #-}
instance ToBackendKey SqlBackend record => FromText (Key record) where
  fromText k = toSqlKey <$> fromText k
instance ToBackendKey SqlBackend record => ToText (Key record) where
  toText = toText . fromSqlKey