Библиотека Haskell Squeal SQL - ошибка типа с MonadReader

Я создаю Haskell Servant API, используя библиотеку SQL под названием Squeal: 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

Проблема

Компилятор сообщает об ошибке в ask в emailTaken:

 * 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])

Семейство типов в любом случае разрешит это, и таким образом я не предоставляю недопустимую конструкцию (семейство типов) для наследования MonadReader в AppT.


person Hopia    schedule 26.11.2019    source источник
comment
Я не смог найти вопрос. Не могли бы вы указать, что это такое?   -  person Michael Litchard    schedule 27.11.2019
comment
Спасибо что подметил это. Я добавил вопрос в конце. Проблема заключается в типах/видах, в основном со схемами и схемами и в том, как соответственно писать сигнатуры типов функций.   -  person Hopia    schedule 27.11.2019
comment
Пожалуйста, включите свой вопрос в раздел выше. Это облегчает будущим читателям.   -  person Michael Litchard    schedule 27.11.2019


Ответы (1)


Вот схема того, как я комбинирую 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
person user2052597    schedule 26.11.2019
comment
Спасибо! Моя проблема заключается в том, что я не могу получить экземпляр MonadReader из моего AppT, если я использую Schemas вместо Schema в type SquealPool (type PoolDB в вашем). Поскольку Schemas является семейством типов - person Hopia; 27.11.2019
comment
Вероятно, вы можете оценить семейство типов как '["public" ::: Schema] - person user2052597; 27.11.2019