2017-04-13 10 views
1

내 PostgreSQL 데이터베이스의 테이블에 대한 내 데이터 유형 중 하나의 필드는 ItemId이라는 UUID을 감싸는 newtype입니다. src/Api/Item.hs이 어디Opaleye newtype

/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 

을 : 하스켈에

{-# 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 

난 여전히 비교적 새로운 해요하지만 문제는 것으로 보인다 내 프로젝트를 컴파일 할 때

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 던졌습니다 Opaleye는 ItemIdPGUuid으로 변환하는 방법을 모르지만, UUIDPGUuid으로 변환 할 수 있음을 알고 있습니다. Opaleye가이 변환 작업을 수행 할 수 있도록 인스턴스를 작성하려면 어떻게해야합니까?

답변

1

문제는 Opaleye가 PGUuid에 항목 Id를 변환하는 방법을 알고하지 않는 것으로 보인다 그러나 나는

그것은 다른 방법 라운드의를 PGUuid하는 UUID를 변환 할 수 있습니다 알고 있습니다. Column PGUuidItemId으로 변환하려고 시도하고 있으며이를 UUID으로 변환하는 방법 만 알고 있습니다. 한 가지 방법은 인스턴스 자신을 추가하는 것입니다

instance O.QueryRunnerColumnDefault O.PGUuid ItemId where 
    queryRunnerColumnDefault = 
     O.queryRunnerColumn id ItemId queryRunnerColumnDefault 

또 다른 방법은 ItemId 다형성 수 있도록하는 것입니다 :

newtype ItemId' a = ItemId a 
$(makeAdaptorAndInstance "pItemId" ''ItemId') 

을 그리고 당신은 작성하지 않고도 하스켈 측과 Opaleye 측면 모두에서 사용할 수 있습니다 여분의 인스턴스.