首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >左加入Opaleye

左加入Opaleye
EN

Stack Overflow用户
提问于 2017-10-20 16:07:08
回答 3查看 210关注 0票数 3

我一直试图在一个项目中使用Opaleye运行一个左联接,但我无法编译代码。我从两个表示关联表的“模型”开始:

第一:

代码语言:javascript
复制
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"))

还包括:

代码语言:javascript
复制
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上的表之间的左联接提供的。我以为它会看起来像:

代码语言:javascript
复制
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)

但这行不通。我还尝试了多个变体,特别是替换了查询中的类型签名,以显式地声明右边列的空性:

代码语言:javascript
复制
query :: Query (ModelAColumn, (Column (Nullable PGUuid), Column (Nullable PGText))

但这一做法失败了,原因是:

没有Data.Profunctor.Product.Default.Class.Default Opaleye.Internal.Join.NullMaker ModelBColumn的实例(列(可空的PGUuid),列(可空的PGText)。

如何在Opaleye中进行此查询?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-10-21 15:15:04

这里有一些误解。下面我制作了一个完整的工作版本。

首先,leftJoin的返回类型不是

代码语言:javascript
复制
Query (ModelAColumn, Maybe ModelBColumn)

你必须做

代码语言:javascript
复制
type ModelBNullableColumn = ModelB' (Column (Nullable PGUuid))
                                    (Column (Nullable PGText))

然后使用

代码语言:javascript
复制
Query (ModelAColumn, ModelBNullableColumn)

其次,runQuery的返回类型不是

代码语言:javascript
复制
IO [(ModelA, Maybe ModelB)]

你必须做

代码语言:javascript
复制
type ModelBMaybe = ModelB' (Maybe UUID) (Maybe String)

并使用

代码语言:javascript
复制
IO [(ModelA, ModelBMaybe)]

造成这些差异的原因是,NullableMaybe必须直接应用于ModelBColumnModelB中的每个列和值,而不是作为一个整体应用于值。

(还有一些奇怪的语法错误,如

代码语言:javascript
复制
ModelA { tableColumn "uuid", tableColumn "foreign" }

这意味着您的代码没有希望编译。我也修好了。)

代码语言:javascript
复制
{-# 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 ()
票数 3
EN

Stack Overflow用户

发布于 2017-10-21 13:50:47

尝试更改以下内容:

代码语言:javascript
复制
query :: Query (ModelAColumn, Maybe ModelBColumn)

代码语言:javascript
复制
query :: Query ((Column PGUuid) (Column (Nullable PGUuid))
               , (Column (Nullable PGUuid)) (Column (Nullable PGText)))

试着让它在不调用runQuery的情况下进行类型检查。一旦成功,请返回解决方案的其余部分。

票数 0
EN

Stack Overflow用户

发布于 2017-10-21 14:00:46

您需要使用Functional Join,特别是leftJoinF

看看这个https://hackage.haskell.org/package/opaleye-0.5.4.0/docs/Opaleye-FunctionalJoin.html

您需要在两个表上提供选择的结果,作为它的第4和第5参数。相当于foreignA == primB的第三个论点。

对于第二个参数,当返回的Maybe ModelBNothing时,您必须指定应该使用的默认值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46853074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档