2017-10-20 83 views
3

我一直在嘗試在項目中使用Opaleye運行左連接,但我無法編譯代碼。我開始與兩個 「模型」,它代表了關聯的表:左加入Opaleye

第一:

data ModelA' a b = Model { primA :: a, foreignA :: b } 
type ModelA = ModelA' UUID UUID 
type ModelAColumn = ModelA' (Column PGUuid) (Column (Nullable PGUuid)) 

$(makeAdaptorAndInstance "pModelA" ''ModelA') 

table :: Table ModelAColumn ModelAColumn 
table = Opaleye.table "model_a" $ pModelA (ModelA (tableColumn "uuid") (tableColumn "foreign")) 

而且也:

data ModelB' a b = Model { primB :: a, valB :: b } 
type ModelB = ModelB' UUID String 
type ModelBColumn = ModelB' (Column PGUuid) (Column PGText) 

$(makeAdaptorAndInstance "pModelB" ''ModelB') 

table :: Table ModelBColumn ModelBColumn 
table = Opaleye.table "model_b" $ pModelB (ModelB (tableColumn "uuid") (tableColumn "val")) 

的各類反映,MODELA可以沒有ModelB與相關。

我需要一個查詢來獲得由外部A == primB上的表之間的左連接給出的(ModelA,Maybe ModelB)對。我期待它看起來像:

doJoin :: Connection -> IO [(ModelA, Maybe ModelB)] 
doJoin conn = runQuery conn query 
    where 
    query :: Query (ModelAColumn, Maybe ModelBColumn) 
    query = leftJoin (queryTable ModelA.table) (queryTable ModelB.table) (\(ma, mb) -> foreignA ma .== primB mb) 

但這不起作用。我也試了多個變種,尤其是我在替換查詢類型簽名的權利,明確規定列的空性:

query :: Query (ModelAColumn, (Column (Nullable PGUuid), Column (Nullable PGText)) 

但這種失敗:

沒有實例Data.Profunctor.Product.Default.Class.Default Opaleye.Internal.Join.NullMaker ModelBColumn(欄(可空 PGUuid),柱(可空PGText)。

我怎樣才能讓這個查詢在Opaleye?

+0

你需要使用'通過'FunctionalJoin'連接''模塊? –

回答

3

有幾個誤解,這裏應該使用一些默認值。我在下面製作了完整的工作版本。

首先,leftJoin的返回類型不是

Query (ModelAColumn, Maybe ModelBColumn) 

你要做

type ModelBNullableColumn = ModelB' (Column (Nullable PGUuid)) 
            (Column (Nullable PGText)) 

然後用

Query (ModelAColumn, ModelBNullableColumn) 

其次,runQuery的返回類型不是

IO [(ModelA, Maybe ModelB)] 

你要做

type ModelBMaybe = ModelB' (Maybe UUID) (Maybe String) 

,並使用

IO [(ModelA, ModelBMaybe)] 

之所以這些差異是NullableMaybe必須在ModelBColumnModelB不能直接應用到每一列和值作爲一個整體的價值。

(也有像

ModelA { tableColumn "uuid", tableColumn "foreign" } 

一些奇怪的語法錯誤,這意味着你的代碼有沒有編制,我固定的,也希望。)

{-# LANGUAGE TemplateHaskell #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE MultiParamTypeClasses #-} 

import   Opaleye hiding (table) 
import qualified Opaleye 
import Data.Profunctor.Product.TH 
import Database.PostgreSQL.Simple hiding (Query) 
import Data.UUID 

data ModelA' a b = ModelA { primA :: a, foreignA :: b } 
type ModelA = ModelA' UUID (Maybe UUID) 
type ModelAColumn = ModelA' (Column PGUuid) (Column (Nullable PGUuid)) 

$(makeAdaptorAndInstance "pModelA" ''ModelA') 

modelAtable :: Table ModelAColumn ModelAColumn 
modelAtable = Opaleye.table "model_a" $ pModelA ModelA { primA = tableColumn "uuid", foreignA = tableColumn "foreign" } 

data ModelB' a b = ModelB { primB :: a, valB :: b } 
type ModelB = ModelB' UUID String 
type ModelBMaybe = ModelB' (Maybe UUID) (Maybe String) 
type ModelBColumn = ModelB' (Column PGUuid) (Column PGText) 
type ModelBNullableColumn = ModelB' (Column (Nullable PGUuid)) (Column (Nullable PGText)) 

$(makeAdaptorAndInstance "pModelB" ''ModelB') 

modelBtable :: Table ModelBColumn ModelBColumn 
modelBtable = Opaleye.table "model_b" $ pModelB ModelB { primB = tableColumn "uuid", valB = tableColumn "val" } 

doJoin :: Connection -> IO [(ModelA, ModelBMaybe)] 
doJoin conn = runQuery conn query 
    where 
    query :: Query (ModelAColumn, ModelBNullableColumn) 
    query = leftJoin (queryTable modelAtable) (queryTable modelBtable) (\(ma, mb) -> matchNullable (pgBool False) (.== primB mb) (foreignA ma)) 

main :: IO() 
main = return() 
+0

非常感謝!併爲奇怪的語法表示歉意。 – Jesuspc

+1

不客氣!我很樂意回答您對Opaleye的更多問題。 –

0

試圖改變如下:

query :: Query (ModelAColumn, Maybe ModelBColumn) 

query :: Query ((Column PGUuid) (Column (Nullable PGUuid)) 
       , (Column (Nullable PGUuid)) (Column (Nullable PGText))) 

試圖獲取類型檢查,而無需調用就可以了runQuery。一旦有效,回到解決方案的其餘部分。