2017-10-20 7 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")) 

も:私が関連付けられているテーブルを表す2つの "モデル" で始まる種類が反映するように

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を持つことはできませんが関連付けられています。

(ModelA、おそらくModelB)のペアを取得するためには、foreignA == primBのテーブル間の左結合によってクエリを取得する必要があります。

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) 

しかし、これは動作しません。また、私は明示的に右の列のNULL値を許可するかどうかを述べるために、クエリ内の型シグネチャを置き換え特に複数のバリアント、試してみた:

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

をしかし、これはで失敗します。

ませインスタンスのData.Profunctor.Product.Default.Class.Default Opaleye.Internal.Join.NullMaker ModelBColumn(列(NULL可能 PGUuid)、列(NULL可能PGText)。私はこのクエリを行うことができますどのように

Opaleyeで?

+0

あなたは 'を使用する必要がありますかJoin'モジュールを 'FunctionalJoin'に追加しましたか? –

答えて

3

であるために。私は以下の完全版を制作しました。

まず、leftJoinの戻り値の型は、あなたが

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

を行い、その後、第二runQueryの戻り値の型を

Query (ModelAColumn, ModelBNullableColumn) 

を使用する必要はありませ

Query (ModelAColumn, Maybe ModelBColumn) 

ですはありません

012あなたは

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

を行うと、これらの違いの理由はNullableMaybeModelBColumnModelBないですべての列と値に直接適用されなければならないということである

IO [(ModelA, ModelBMaybe)] 

を使用する必要が

IO [(ModelA, Maybe ModelB)] 

値全体に

あなたのコードはコンパイルのない希望を持っていないことを意味
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 ((Column PGUuid) (Column (Nullable PGUuid)) 
       , (Column (Nullable PGUuid)) (Column (Nullable PGText))) 

query :: Query (ModelAColumn, Maybe ModelBColumn) 

それはそれでrunQueryを呼び出さずにチェックを入力するために取得してください。それが機能したら、ソリューションの残りの部分に戻ってください。

0

Functional Join、具体的にはleftJoinFを使用する必要があります。

チェックアウトこのhttps://hackage.haskell.org/package/opaleye-0.5.4.0/docs/Opaleye-FunctionalJoin.html

あなたはそれに4番目と5番目の引数としての二つのテーブルの上の選択の結果を提供する必要があります。 第3引数としてforeignA == primBに相当します。

誤解のカップルがここにあります。あなたはMaybe ModelBが返されるたびに使用されなければならないいくつかのデフォルト値を指定する必要がありますあなたの第二引数はNothing