2017-10-20 88 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。一旦有效,回到解决方案的其余部分。