Haskell Squeal SQL 库 - MonadReader 类型错误
Haskell Squeal SQL library - Type error with MonadReader
我正在使用名为 Squeal
的 SQL 库构建 Haskell Servant
API:
https://github.com/morphismtech/squeal
我需要帮助让类型正确以便应用程序编译。
我的架构是类型
type Schema = '["users" ::: UsersTable, ...]
type Schemas = Public Schema
其中 Public
是单个模式数据库的类型族。来自于:
http://hackage.haskell.org/package/squeal-postgresql-0.5.1.0/docs/Squeal-PostgreSQL-Schema.html
我正在尝试像这样在 Reader 中传递连接池:
import qualified Squeal.PostgreSQL as S
import qualified Squeal.PostgreSQL.Pool as SPG
newtype AppT m a
= AppT
{ runApp :: ReaderT SquealPool (ExceptT ServerError m) a
} deriving
( Functor, Applicative, Monad, MonadReader SquealPool, MonadError ServerError
, MonadIO
)
type App = AppT IO
type SquealPool = SPG.Pool (SQ.K S.Connection Schema)
我的 SQL 查询和会话是这样的:
emailQuery :: Query_ Schemas (Only Text) UserEmail
emailQuery = select (#email `as` #email)
(from (table #users) & where_ (#email .== param @1))
emailTakenSession
:: (MonadReader SquealPool m, MonadPQ Schemas m, MonadIO m)
=> Text
-> m UserEmail
emailTakenSession email = do
result <- runQueryParams emailQuery (Only email)
email <- getRow 1 result
return email
最后,我在 Servant
处理程序中使用它们,如下所示:
emailTaken :: MonadIO m => Text -> AppT m APIEmail
emailTaken emailStr = do
pool <- ask -- this produces error
result <- liftIO $ runPoolPQ (Q.emailTakenSession emailStr) pool
return $ APIEmail result True
问题
emailTaken
编译报错ask
:
* Couldn't match kind `[(ghc-prim-0.5.3:GHC.Types.Symbol,
Squeal.PostgreSQL.Schema.SchemumType)]'
with `Squeal.PostgreSQL.Schema.SchemumType'
据我了解,它试图将类型族 Schemas
与类型 Schema
.
匹配
问题
我需要如何编辑类型签名才能使其编译和工作?
特别是 emailTakenSession
至少可能是关闭的。
解决方案
为了其他读者的完整性,我需要更改
type SquealPool = SPG.Pool (SQ.K S.Connection Schema)
进入
type SquealPool = SPG.Pool (S.K S.Connection '["public" ::: Schema])
类型族无论如何都会解决这个问题,这样我就不会在 AppT
.
中为 MonadReader 派生提供非法构造(类型族)
这是我如何组合 Squeal 和 Servant 的框架。
{-# LANGUAGE
DataKinds
, OverloadedLabels
, OverloadedStrings
, PolyKinds
#-}
module SquealServant where
import Control.Monad.IO.Class
import Data.String
import Servant
import Squeal.PostgreSQL
import Data.Pool
type DB = Public Schema
type Schema = '[] -- your schema here
type API = Get '[JSON] String -- your api here
type PoolDB = Pool (K Connection DB)
application :: PoolDB -> Application
application pool = serve api (server pool)
server :: PoolDB -> Server API
server pool = hoistServer api (handler pool) serverT
handler :: PoolDB -> PQ DB DB IO x -> Handler x
handler pool session = do
errOrResult <- liftIO . usingConnectionPool pool $
trySqueal (transactionally_ session)
case errOrResult of
Left err -> throwError (sqlErr err)
Right result -> return result
sqlErr :: SquealException -> ServerError
sqlErr err = err500 { errBody = fromString (show err) }
api :: Proxy API
api = Proxy
serverT :: ServerT API (PQ DB DB IO)
serverT = hello
hello :: PQ DB DB IO String
hello = do
Only greeting <- getRow 0 =<< runQuery helloQ
return greeting
helloQ :: Query_ DB () (Only String)
helloQ = values_ ("hello world" `as` #fromOnly)
usingConnectionPool :: PoolDB -> PQ DB DB IO x -> IO x
usingConnectionPool pool (PQ session) = unK <$> withResource pool session
我正在使用名为 Squeal
的 SQL 库构建 Haskell Servant
API:
https://github.com/morphismtech/squeal
我需要帮助让类型正确以便应用程序编译。
我的架构是类型
type Schema = '["users" ::: UsersTable, ...]
type Schemas = Public Schema
其中 Public
是单个模式数据库的类型族。来自于:
http://hackage.haskell.org/package/squeal-postgresql-0.5.1.0/docs/Squeal-PostgreSQL-Schema.html
我正在尝试像这样在 Reader 中传递连接池:
import qualified Squeal.PostgreSQL as S
import qualified Squeal.PostgreSQL.Pool as SPG
newtype AppT m a
= AppT
{ runApp :: ReaderT SquealPool (ExceptT ServerError m) a
} deriving
( Functor, Applicative, Monad, MonadReader SquealPool, MonadError ServerError
, MonadIO
)
type App = AppT IO
type SquealPool = SPG.Pool (SQ.K S.Connection Schema)
我的 SQL 查询和会话是这样的:
emailQuery :: Query_ Schemas (Only Text) UserEmail
emailQuery = select (#email `as` #email)
(from (table #users) & where_ (#email .== param @1))
emailTakenSession
:: (MonadReader SquealPool m, MonadPQ Schemas m, MonadIO m)
=> Text
-> m UserEmail
emailTakenSession email = do
result <- runQueryParams emailQuery (Only email)
email <- getRow 1 result
return email
最后,我在 Servant
处理程序中使用它们,如下所示:
emailTaken :: MonadIO m => Text -> AppT m APIEmail
emailTaken emailStr = do
pool <- ask -- this produces error
result <- liftIO $ runPoolPQ (Q.emailTakenSession emailStr) pool
return $ APIEmail result True
问题
emailTaken
编译报错ask
:
* Couldn't match kind `[(ghc-prim-0.5.3:GHC.Types.Symbol,
Squeal.PostgreSQL.Schema.SchemumType)]'
with `Squeal.PostgreSQL.Schema.SchemumType'
据我了解,它试图将类型族 Schemas
与类型 Schema
.
问题
我需要如何编辑类型签名才能使其编译和工作?
特别是 emailTakenSession
至少可能是关闭的。
解决方案
为了其他读者的完整性,我需要更改
type SquealPool = SPG.Pool (SQ.K S.Connection Schema)
进入
type SquealPool = SPG.Pool (S.K S.Connection '["public" ::: Schema])
类型族无论如何都会解决这个问题,这样我就不会在 AppT
.
这是我如何组合 Squeal 和 Servant 的框架。
{-# LANGUAGE
DataKinds
, OverloadedLabels
, OverloadedStrings
, PolyKinds
#-}
module SquealServant where
import Control.Monad.IO.Class
import Data.String
import Servant
import Squeal.PostgreSQL
import Data.Pool
type DB = Public Schema
type Schema = '[] -- your schema here
type API = Get '[JSON] String -- your api here
type PoolDB = Pool (K Connection DB)
application :: PoolDB -> Application
application pool = serve api (server pool)
server :: PoolDB -> Server API
server pool = hoistServer api (handler pool) serverT
handler :: PoolDB -> PQ DB DB IO x -> Handler x
handler pool session = do
errOrResult <- liftIO . usingConnectionPool pool $
trySqueal (transactionally_ session)
case errOrResult of
Left err -> throwError (sqlErr err)
Right result -> return result
sqlErr :: SquealException -> ServerError
sqlErr err = err500 { errBody = fromString (show err) }
api :: Proxy API
api = Proxy
serverT :: ServerT API (PQ DB DB IO)
serverT = hello
hello :: PQ DB DB IO String
hello = do
Only greeting <- getRow 0 =<< runQuery helloQ
return greeting
helloQ :: Query_ DB () (Only String)
helloQ = values_ ("hello world" `as` #fromOnly)
usingConnectionPool :: PoolDB -> PQ DB DB IO x -> IO x
usingConnectionPool pool (PQ session) = unK <$> withResource pool session