Opaleye 新型
Opaleye newtype
我的 PostgreSQL 数据库中 table 的数据类型中的一个字段是一个名为 ItemId
.
的新类型包装 UUID
import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
import Data.DateTime (DateTime)
import Data.UUID
import GHC.Generics
import qualified Opaleye as O
import Data.Text (pack, Text)
newtype ItemId = ItemId UUID
deriving (Show, Eq, Generic)
toItemId :: UUID -> ItemId
toItemId = ItemId
fromItemId :: ItemId -> UUID
fromItemId (ItemId x) = x
data Item' id name desc num most
= Item {
_itemId :: id,
_itemName :: name,
_itemDesc :: desc,
_numTimesOrdered :: num,
_mostRecentOrder :: most
}
type ItemRead = Item' ItemId Text Text Int DateTime
type ItemWrite = Item' (Maybe ItemId) Text Text (Maybe Int) (Maybe DateTime)
type ItemColRead = Item' (O.Column O.PGUuid)
(O.Column O.PGText)
(O.Column O.PGText)
(O.Column O.PGInt4)
(O.Column O.PGTimestamptz)
type ItemColWrite = Item' (Maybe (O.Column O.PGUuid))
(O.Column O.PGText)
(O.Column O.PGText)
(Maybe (O.Column O.PGInt4))
(Maybe (O.Column O.PGTimestamptz))
$(makeAdaptorAndInstance "pItem" ''Item')
itemTable :: O.Table ItemColWrite ItemColRead
itemTable = O.Table "items" (pItem Item { _itemId = O.optional "id"
, _itemName = O.required "name"
, _itemDesc = O.required "desc"
, _numTimesOrdered = O.optional "numTimesOrdered"
, _mostRecentOrder = O.optional "mostRecentOrder"
})
itemToPG :: ItemWrite -> ItemColWrite
itemToPG = pItem Item { _itemId = const Nothing
, _itemName = O.pgStrictText
, _itemDesc = O.pgStrictText
, _numTimesOrdered = const Nothing
, _mostRecentOrder = const Nothing
}
然而,当我编译我的项目时,GHC 抛出:
/home/gigavinyl/Projects/ordermage/src/Api/Item.hs:34:3: error:
• No instance for (O.QueryRunnerColumnDefault O.PGUuid ItemId)
arising from a use of ‘O.runInsertManyReturning’
• In the second argument of ‘(<$>)’, namely
‘O.runInsertManyReturning con itemTable [itemToPG item] _itemId’
In the second argument of ‘($)’, namely
‘listToMaybe
<$> O.runInsertManyReturning con itemTable [itemToPG item] _itemId’
In the expression:
liftIO
$ listToMaybe
<$> O.runInsertManyReturning con itemTable [itemToPG item] _itemId
其中 src/Api/Item.hs
是:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
module Api.Item where
import Control.Monad.IO.Class (liftIO)
import Data.Maybe (listToMaybe)
import Database.PostgreSQL.Simple (Connection)
import Models.Item
import Queries.Item
import Servant
import qualified Opaleye as O
type ItemApi =
Get '[JSON] [ItemRead] :<|>
Capture "itemId" ItemId :> Get '[JSON] (Maybe ItemRead) :<|>
ReqBody '[JSON] ItemWrite :> Post '[JSON] (Maybe ItemId)
itemServer :: Connection -> Server ItemApi
itemServer con =
getItems con :<|>
getItemById con :<|>
postItem con
getItems :: Connection -> Handler [ItemRead]
getItems con = liftIO $ O.runQuery con itemsQuery
getItemById :: Connection -> ItemId -> Handler (Maybe ItemRead)
getItemById con itemID = liftIO $ listToMaybe <$> O.runQuery con (itemByIdQuery itemID)
postItem :: Connection -> ItemWrite -> Handler (Maybe ItemId)
postItem con item = liftIO $ listToMaybe <$>
O.runInsertManyReturning con itemTable [itemToPG item] _itemId
我对 Haskell 还是很陌生,但问题似乎是 Opaleye 不知道如何将 ItemId
转换为 PGUuid
但我知道它可以转换UUID
到 PGUuid
。我将如何着手编写实例以允许 Opaleye 进行此转换?
the issue appears to be that Opaleye doesn't know how to convert ItemId into a PGUuid but I know it can convert UUID to PGUuid
正好相反。它试图将 Column PGUuid
转换为 ItemId
,但它只知道如何将其转换为 UUID
。一种方法是自己添加实例:
instance O.QueryRunnerColumnDefault O.PGUuid ItemId where
queryRunnerColumnDefault =
O.queryRunnerColumn id ItemId queryRunnerColumnDefault
另一种方法是使 ItemId
多态:
newtype ItemId' a = ItemId a
$(makeAdaptorAndInstance "pItemId" ''ItemId')
然后您可以在 Haskell 端和 Opaleye 端使用它,而无需编写额外的实例。
我的 PostgreSQL 数据库中 table 的数据类型中的一个字段是一个名为 ItemId
.
UUID
import Data.Profunctor.Product.TH (makeAdaptorAndInstance)
import Data.DateTime (DateTime)
import Data.UUID
import GHC.Generics
import qualified Opaleye as O
import Data.Text (pack, Text)
newtype ItemId = ItemId UUID
deriving (Show, Eq, Generic)
toItemId :: UUID -> ItemId
toItemId = ItemId
fromItemId :: ItemId -> UUID
fromItemId (ItemId x) = x
data Item' id name desc num most
= Item {
_itemId :: id,
_itemName :: name,
_itemDesc :: desc,
_numTimesOrdered :: num,
_mostRecentOrder :: most
}
type ItemRead = Item' ItemId Text Text Int DateTime
type ItemWrite = Item' (Maybe ItemId) Text Text (Maybe Int) (Maybe DateTime)
type ItemColRead = Item' (O.Column O.PGUuid)
(O.Column O.PGText)
(O.Column O.PGText)
(O.Column O.PGInt4)
(O.Column O.PGTimestamptz)
type ItemColWrite = Item' (Maybe (O.Column O.PGUuid))
(O.Column O.PGText)
(O.Column O.PGText)
(Maybe (O.Column O.PGInt4))
(Maybe (O.Column O.PGTimestamptz))
$(makeAdaptorAndInstance "pItem" ''Item')
itemTable :: O.Table ItemColWrite ItemColRead
itemTable = O.Table "items" (pItem Item { _itemId = O.optional "id"
, _itemName = O.required "name"
, _itemDesc = O.required "desc"
, _numTimesOrdered = O.optional "numTimesOrdered"
, _mostRecentOrder = O.optional "mostRecentOrder"
})
itemToPG :: ItemWrite -> ItemColWrite
itemToPG = pItem Item { _itemId = const Nothing
, _itemName = O.pgStrictText
, _itemDesc = O.pgStrictText
, _numTimesOrdered = const Nothing
, _mostRecentOrder = const Nothing
}
然而,当我编译我的项目时,GHC 抛出:
/home/gigavinyl/Projects/ordermage/src/Api/Item.hs:34:3: error:
• No instance for (O.QueryRunnerColumnDefault O.PGUuid ItemId)
arising from a use of ‘O.runInsertManyReturning’
• In the second argument of ‘(<$>)’, namely
‘O.runInsertManyReturning con itemTable [itemToPG item] _itemId’
In the second argument of ‘($)’, namely
‘listToMaybe
<$> O.runInsertManyReturning con itemTable [itemToPG item] _itemId’
In the expression:
liftIO
$ listToMaybe
<$> O.runInsertManyReturning con itemTable [itemToPG item] _itemId
其中 src/Api/Item.hs
是:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
module Api.Item where
import Control.Monad.IO.Class (liftIO)
import Data.Maybe (listToMaybe)
import Database.PostgreSQL.Simple (Connection)
import Models.Item
import Queries.Item
import Servant
import qualified Opaleye as O
type ItemApi =
Get '[JSON] [ItemRead] :<|>
Capture "itemId" ItemId :> Get '[JSON] (Maybe ItemRead) :<|>
ReqBody '[JSON] ItemWrite :> Post '[JSON] (Maybe ItemId)
itemServer :: Connection -> Server ItemApi
itemServer con =
getItems con :<|>
getItemById con :<|>
postItem con
getItems :: Connection -> Handler [ItemRead]
getItems con = liftIO $ O.runQuery con itemsQuery
getItemById :: Connection -> ItemId -> Handler (Maybe ItemRead)
getItemById con itemID = liftIO $ listToMaybe <$> O.runQuery con (itemByIdQuery itemID)
postItem :: Connection -> ItemWrite -> Handler (Maybe ItemId)
postItem con item = liftIO $ listToMaybe <$>
O.runInsertManyReturning con itemTable [itemToPG item] _itemId
我对 Haskell 还是很陌生,但问题似乎是 Opaleye 不知道如何将 ItemId
转换为 PGUuid
但我知道它可以转换UUID
到 PGUuid
。我将如何着手编写实例以允许 Opaleye 进行此转换?
the issue appears to be that Opaleye doesn't know how to convert ItemId into a PGUuid but I know it can convert UUID to PGUuid
正好相反。它试图将 Column PGUuid
转换为 ItemId
,但它只知道如何将其转换为 UUID
。一种方法是自己添加实例:
instance O.QueryRunnerColumnDefault O.PGUuid ItemId where
queryRunnerColumnDefault =
O.queryRunnerColumn id ItemId queryRunnerColumnDefault
另一种方法是使 ItemId
多态:
newtype ItemId' a = ItemId a
$(makeAdaptorAndInstance "pItemId" ''ItemId')
然后您可以在 Haskell 端和 Opaleye 端使用它,而无需编写额外的实例。