给定完整密钥获取持久记录?
Fetch a Persistent record given its integral key?
我正在尝试将 Persistent 与 Servant 一起使用,因此我无法将 URL 段自动解析为 Persistent 键。相反,我已经将我的路由设置为需要 Int64
,并且我想使用它来检索记录以执行主键查找。
Everything I've found 将整数转换为键,所以我尝试编写一个非常简单的函数来为我完成此操作:
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)
我有点理解这个错误——我查找了get
和toSqlKey
的类型,它们包括相关的约束:
get :: (MonadIO m, backend ~ PersistEntityBackend val, PersistEntity val) => Key val -> ReaderT backend m (Maybe val)
toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record
如果我理解正确,backend
和 PersistEntityBackend val
需要是同一类型,但 toSqlKey
强制执行 SqlBackend
约束,因此类型不匹配。我的直觉告诉我 PersistentEntityBackend (Entity Record)
应该是 SqlBackend
,但显然我错了。不过,我不知道为什么或如何。
无论如何,我不知道我的分析是对还是错,但无论哪种方式,我都不确定如何解决这个问题或者这样做的正确方法是什么。 can/should 我如何从我的数据库中获取一个整数的记录?
这对我有用(可能取决于你的包的版本......遗憾的是):
{-# 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
的东西!
那么如何使 Key record
直接成为 FromText
/ToText
的实例并直接使用 URL 中的键呢?
{-# 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
我正在尝试将 Persistent 与 Servant 一起使用,因此我无法将 URL 段自动解析为 Persistent 键。相反,我已经将我的路由设置为需要 Int64
,并且我想使用它来检索记录以执行主键查找。
Everything I've found
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)
我有点理解这个错误——我查找了get
和toSqlKey
的类型,它们包括相关的约束:
get :: (MonadIO m, backend ~ PersistEntityBackend val, PersistEntity val) => Key val -> ReaderT backend m (Maybe val)
toSqlKey :: ToBackendKey SqlBackend record => Int64 -> Key record
如果我理解正确,backend
和 PersistEntityBackend val
需要是同一类型,但 toSqlKey
强制执行 SqlBackend
约束,因此类型不匹配。我的直觉告诉我 PersistentEntityBackend (Entity Record)
应该是 SqlBackend
,但显然我错了。不过,我不知道为什么或如何。
无论如何,我不知道我的分析是对还是错,但无论哪种方式,我都不确定如何解决这个问题或者这样做的正确方法是什么。 can/should 我如何从我的数据库中获取一个整数的记录?
这对我有用(可能取决于你的包的版本......遗憾的是):
{-# 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
的东西!
那么如何使 Key record
直接成为 FromText
/ToText
的实例并直接使用 URL 中的键呢?
{-# 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