{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE Arrows #-}
module Opaleye.Internal.Join where
import qualified Opaleye.Internal.HaskellDB.PrimQuery as HPQ
import qualified Opaleye.Internal.PackMap as PM
import qualified Opaleye.Internal.Tag as T
import qualified Opaleye.Internal.Unpackspec as U
import Opaleye.Internal.Column (Field_(Column), FieldNullable)
import qualified Opaleye.Internal.QueryArr as Q
import qualified Opaleye.Internal.Operators as Op
import qualified Opaleye.Internal.PrimQuery as PQ
import qualified Opaleye.Internal.PGTypesExternal as T
import qualified Opaleye.Internal.Rebind as Rebind
import qualified Opaleye.SqlTypes as T
import qualified Opaleye.Field as C
import Opaleye.Field (Field)
import Opaleye.Internal.MaybeFields (MaybeFields(MaybeFields),
mfPresent, mfFields)
import qualified Opaleye.Select as S
import qualified Control.Applicative as A
import qualified Control.Arrow
import Data.Profunctor (Profunctor, dimap)
import qualified Data.Profunctor.Product as PP
import qualified Data.Profunctor.Product.Default as D
newtype NullMaker a b = NullMaker (a -> b)
toNullable :: NullMaker a b -> a -> b
toNullable :: NullMaker a b -> a -> b
toNullable (NullMaker a -> b
f) = a -> b
f
instance D.Default NullMaker (Field a) (FieldNullable a) where
def :: NullMaker (Field a) (FieldNullable a)
def = (Field a -> FieldNullable a)
-> NullMaker (Field a) (FieldNullable a)
forall a b. (a -> b) -> NullMaker a b
NullMaker Field a -> FieldNullable a
forall a. Field a -> FieldNullable a
C.toNullable
instance D.Default NullMaker (FieldNullable a) (FieldNullable a) where
def :: NullMaker (FieldNullable a) (FieldNullable a)
def = (FieldNullable a -> FieldNullable a)
-> NullMaker (FieldNullable a) (FieldNullable a)
forall a b. (a -> b) -> NullMaker a b
NullMaker FieldNullable a -> FieldNullable a
forall a. a -> a
id
joinExplicit :: U.Unpackspec columnsA columnsA
-> U.Unpackspec columnsB columnsB
-> (columnsA -> returnedColumnsA)
-> (columnsB -> returnedColumnsB)
-> PQ.JoinType
-> Q.Query columnsA -> Q.Query columnsB
-> ((columnsA, columnsB) -> Field T.PGBool)
-> Q.Query (returnedColumnsA, returnedColumnsB)
joinExplicit :: Unpackspec columnsA columnsA
-> Unpackspec columnsB columnsB
-> (columnsA -> returnedColumnsA)
-> (columnsB -> returnedColumnsB)
-> JoinType
-> Query columnsA
-> Query columnsB
-> ((columnsA, columnsB) -> Field PGBool)
-> Query (returnedColumnsA, returnedColumnsB)
joinExplicit Unpackspec columnsA columnsA
uA Unpackspec columnsB columnsB
uB columnsA -> returnedColumnsA
returnColumnsA columnsB -> returnedColumnsB
returnColumnsB JoinType
joinType
Query columnsA
qA Query columnsB
qB (columnsA, columnsB) -> Field PGBool
cond = (() -> State Tag ((returnedColumnsA, returnedColumnsB), PrimQuery))
-> Query (returnedColumnsA, returnedColumnsB)
forall a b. (a -> State Tag (b, PrimQuery)) -> QueryArr a b
Q.productQueryArr' ((()
-> State Tag ((returnedColumnsA, returnedColumnsB), PrimQuery))
-> Query (returnedColumnsA, returnedColumnsB))
-> (()
-> State Tag ((returnedColumnsA, returnedColumnsB), PrimQuery))
-> Query (returnedColumnsA, returnedColumnsB)
forall a b. (a -> b) -> a -> b
$ \() -> do
(columnsA
columnsA, PrimQuery
primQueryA) <- Query columnsA -> () -> State Tag (columnsA, PrimQuery)
forall a b. QueryArr a b -> a -> State Tag (b, PrimQuery)
Q.runSimpleQueryArr' Query columnsA
qA ()
(columnsB
columnsB, PrimQuery
primQueryB) <- Query columnsB -> () -> State Tag (columnsB, PrimQuery)
forall a b. QueryArr a b -> a -> State Tag (b, PrimQuery)
Q.runSimpleQueryArr' Query columnsB
qB ()
Tag
endTag <- State Tag Tag
T.fresh
let (columnsA
newColumnsA, [(Symbol, PrimExpr)]
ljPEsA) =
PM [(Symbol, PrimExpr)] columnsA
-> (columnsA, [(Symbol, PrimExpr)])
forall a r. PM [a] r -> (r, [a])
PM.run (Unpackspec columnsA columnsA
-> (PrimExpr
-> StateT ([(Symbol, PrimExpr)], Int) Identity PrimExpr)
-> columnsA
-> PM [(Symbol, PrimExpr)] columnsA
forall (f :: * -> *) columns b.
Applicative f =>
Unpackspec columns b -> (PrimExpr -> f PrimExpr) -> columns -> f b
U.runUnpackspec Unpackspec columnsA columnsA
uA (Int
-> Tag
-> PrimExpr
-> StateT ([(Symbol, PrimExpr)], Int) Identity PrimExpr
extractLeftJoinFields Int
1 Tag
endTag) columnsA
columnsA)
(columnsB
newColumnsB, [(Symbol, PrimExpr)]
ljPEsB) =
PM [(Symbol, PrimExpr)] columnsB
-> (columnsB, [(Symbol, PrimExpr)])
forall a r. PM [a] r -> (r, [a])
PM.run (Unpackspec columnsB columnsB
-> (PrimExpr
-> StateT ([(Symbol, PrimExpr)], Int) Identity PrimExpr)
-> columnsB
-> PM [(Symbol, PrimExpr)] columnsB
forall (f :: * -> *) columns b.
Applicative f =>
Unpackspec columns b -> (PrimExpr -> f PrimExpr) -> columns -> f b
U.runUnpackspec Unpackspec columnsB columnsB
uB (Int
-> Tag
-> PrimExpr
-> StateT ([(Symbol, PrimExpr)], Int) Identity PrimExpr
extractLeftJoinFields Int
2 Tag
endTag) columnsB
columnsB)
nullableColumnsA :: returnedColumnsA
nullableColumnsA = columnsA -> returnedColumnsA
returnColumnsA columnsA
newColumnsA
nullableColumnsB :: returnedColumnsB
nullableColumnsB = columnsB -> returnedColumnsB
returnColumnsB columnsB
newColumnsB
Column PrimExpr
cond' = (columnsA, columnsB) -> Field PGBool
cond (columnsA
columnsA, columnsB
columnsB)
primQueryR :: PrimQuery
primQueryR = JoinType
-> PrimExpr
-> (Lateral, PrimQuery)
-> (Lateral, PrimQuery)
-> PrimQuery
forall a.
JoinType
-> PrimExpr
-> (Lateral, PrimQuery' a)
-> (Lateral, PrimQuery' a)
-> PrimQuery' a
PQ.Join JoinType
joinType PrimExpr
cond'
(Lateral
PQ.NonLateral, (Bool -> [(Symbol, PrimExpr)] -> PrimQuery -> PrimQuery
forall a.
Bool -> [(Symbol, PrimExpr)] -> PrimQuery' a -> PrimQuery' a
PQ.Rebind Bool
True [(Symbol, PrimExpr)]
ljPEsA PrimQuery
primQueryA))
(Lateral
PQ.NonLateral, (Bool -> [(Symbol, PrimExpr)] -> PrimQuery -> PrimQuery
forall a.
Bool -> [(Symbol, PrimExpr)] -> PrimQuery' a -> PrimQuery' a
PQ.Rebind Bool
True [(Symbol, PrimExpr)]
ljPEsB PrimQuery
primQueryB))
((returnedColumnsA, returnedColumnsB), PrimQuery)
-> State Tag ((returnedColumnsA, returnedColumnsB), PrimQuery)
forall (f :: * -> *) a. Applicative f => a -> f a
pure ((returnedColumnsA
nullableColumnsA, returnedColumnsB
nullableColumnsB), PrimQuery
primQueryR)
leftJoinAExplicit :: U.Unpackspec a a
-> NullMaker a nullableA
-> Q.Query a
-> Q.QueryArr (a -> Field T.PGBool) nullableA
leftJoinAExplicit :: Unpackspec a a
-> NullMaker a nullableA
-> Query a
-> QueryArr (a -> Field PGBool) nullableA
leftJoinAExplicit Unpackspec a a
uA NullMaker a nullableA
nullmaker Query a
rq =
((a -> Field PGBool) -> State Tag (nullableA, PrimExpr, PrimQuery))
-> QueryArr (a -> Field PGBool) nullableA
forall a b.
(a -> State Tag (b, PrimExpr, PrimQuery)) -> QueryArr a b
Q.leftJoinQueryArr' (((a -> Field PGBool)
-> State Tag (nullableA, PrimExpr, PrimQuery))
-> QueryArr (a -> Field PGBool) nullableA)
-> ((a -> Field PGBool)
-> State Tag (nullableA, PrimExpr, PrimQuery))
-> QueryArr (a -> Field PGBool) nullableA
forall a b. (a -> b) -> a -> b
$ \a -> Field PGBool
p -> do
(a
newColumnsR, PrimQuery
right) <- (Query a -> () -> State Tag (a, PrimQuery))
-> () -> Query a -> State Tag (a, PrimQuery)
forall a b c. (a -> b -> c) -> b -> a -> c
flip Query a -> () -> State Tag (a, PrimQuery)
forall a b. QueryArr a b -> a -> State Tag (b, PrimQuery)
Q.runSimpleQueryArr' () (Query a -> State Tag (a, PrimQuery))
-> Query a -> State Tag (a, PrimQuery)
forall a b. (a -> b) -> a -> b
$ proc () -> do
a
a <- Query a
rq -< ()
Unpackspec a a -> SelectArr a a
forall a b. Unpackspec a b -> SelectArr a b
Rebind.rebindExplicit Unpackspec a a
uA -< a
a
let renamedNullable :: nullableA
renamedNullable = NullMaker a nullableA -> a -> nullableA
forall a b. NullMaker a b -> a -> b
toNullable NullMaker a nullableA
nullmaker a
newColumnsR
Column PrimExpr
cond = a -> Field PGBool
p a
newColumnsR
(nullableA, PrimExpr, PrimQuery)
-> State Tag (nullableA, PrimExpr, PrimQuery)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (nullableA
renamedNullable, PrimExpr
cond, PrimQuery
right)
optionalRestrict :: D.Default U.Unpackspec a a
=> S.Select a
-> S.SelectArr (a -> Field T.SqlBool) (MaybeFields a)
optionalRestrict :: Select a -> SelectArr (a -> Field PGBool) (MaybeFields a)
optionalRestrict = Unpackspec a a
-> Select a -> SelectArr (a -> Field PGBool) (MaybeFields a)
forall a.
Unpackspec a a
-> Select a -> SelectArr (a -> Field PGBool) (MaybeFields a)
optionalRestrictExplicit Unpackspec a a
forall (p :: * -> * -> *) a b. Default p a b => p a b
D.def
optionalRestrictExplicit :: U.Unpackspec a a
-> S.Select a
-> S.SelectArr (a -> Field T.SqlBool) (MaybeFields a)
optionalRestrictExplicit :: Unpackspec a a
-> Select a -> SelectArr (a -> Field PGBool) (MaybeFields a)
optionalRestrictExplicit Unpackspec a a
uA Select a
q =
((a -> Field PGBool) -> (Field PGBool, a) -> Field PGBool)
-> ((Field PGBool, a) -> MaybeFields a)
-> SelectArr ((Field PGBool, a) -> Field PGBool) (Field PGBool, a)
-> SelectArr (a -> Field PGBool) (MaybeFields a)
forall (p :: * -> * -> *) a b c d.
Profunctor p =>
(a -> b) -> (c -> d) -> p b c -> p a d
dimap ((a -> Field PGBool)
-> ((Field PGBool, a) -> a) -> (Field PGBool, a) -> Field PGBool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Field PGBool, a) -> a
forall a b. (a, b) -> b
snd) (\(Field PGBool
nonNullIfPresent, a
rest) ->
let present :: Field PGBool
present = Field PGBool -> Field PGBool
Op.not (FieldNullable Any -> Field PGBool
forall a. FieldNullable a -> Field PGBool
C.isNull (Field PGBool -> FieldNullable Any
forall (n :: Nullability) a (n' :: Nullability) b.
Field_ n a -> Field_ n' b
C.unsafeCoerceField Field PGBool
nonNullIfPresent))
in MaybeFields :: forall fields. Column PGBool -> fields -> MaybeFields fields
MaybeFields { mfPresent :: Column PGBool
mfPresent = Column PGBool
Field PGBool
present
, mfFields :: a
mfFields = a
rest
}) (SelectArr ((Field PGBool, a) -> Field PGBool) (Field PGBool, a)
-> SelectArr (a -> Field PGBool) (MaybeFields a))
-> SelectArr ((Field PGBool, a) -> Field PGBool) (Field PGBool, a)
-> SelectArr (a -> Field PGBool) (MaybeFields a)
forall a b. (a -> b) -> a -> b
$
Unpackspec (Field PGBool, a) (Field PGBool, a)
-> NullMaker (Field PGBool, a) (Field PGBool, a)
-> Query (Field PGBool, a)
-> SelectArr ((Field PGBool, a) -> Field PGBool) (Field PGBool, a)
forall a nullableA.
Unpackspec a a
-> NullMaker a nullableA
-> Query a
-> QueryArr (a -> Field PGBool) nullableA
leftJoinAExplicit ((Unpackspec (Field PGBool) (Field PGBool), Unpackspec a a)
-> Unpackspec (Field PGBool, a) (Field PGBool, a)
forall (p :: * -> * -> *) a0 a1 b0 b1.
ProductProfunctor p =>
(p a0 b0, p a1 b1) -> p (a0, a1) (b0, b1)
PP.p2 (Unpackspec (Field PGBool) (Field PGBool)
forall (n :: Nullability) a. Unpackspec (Field_ n a) (Field_ n a)
U.unpackspecField, Unpackspec a a
uA))
(((Field PGBool, a) -> (Field PGBool, a))
-> NullMaker (Field PGBool, a) (Field PGBool, a)
forall a b. (a -> b) -> NullMaker a b
Opaleye.Internal.Join.NullMaker (Field PGBool, a) -> (Field PGBool, a)
forall a. a -> a
id)
((a -> (Field PGBool, a)) -> Select a -> Query (Field PGBool, a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\a
x -> (Bool -> Field PGBool
T.sqlBool Bool
True, a
x)) Select a
q)
leftJoinInTermsOfOptionalRestrict :: D.Default U.Unpackspec fieldsR fieldsR
=> S.Select fieldsL
-> S.Select fieldsR
-> ((fieldsL, fieldsR) -> Field T.SqlBool)
-> S.Select (fieldsL, MaybeFields fieldsR)
leftJoinInTermsOfOptionalRestrict :: Select fieldsL
-> Select fieldsR
-> ((fieldsL, fieldsR) -> Field PGBool)
-> Select (fieldsL, MaybeFields fieldsR)
leftJoinInTermsOfOptionalRestrict Select fieldsL
qL Select fieldsR
qR (fieldsL, fieldsR) -> Field PGBool
cond = proc () -> do
fieldsL
fieldsL <- Select fieldsL
qL -< ()
MaybeFields fieldsR
maybeFieldsR <- Select fieldsR
-> SelectArr (fieldsR -> Field PGBool) (MaybeFields fieldsR)
forall a.
Default Unpackspec a a =>
Select a -> SelectArr (a -> Field PGBool) (MaybeFields a)
optionalRestrict Select fieldsR
qR -< ((fieldsL, fieldsR) -> Field PGBool)
-> fieldsL -> fieldsR -> Field PGBool
forall a b c. ((a, b) -> c) -> a -> b -> c
curry (fieldsL, fieldsR) -> Field PGBool
cond fieldsL
fieldsL
SelectArr
(fieldsL, MaybeFields fieldsR) (fieldsL, MaybeFields fieldsR)
forall (a :: * -> * -> *) b. Arrow a => a b b
Control.Arrow.returnA -< (fieldsL
fieldsL, MaybeFields fieldsR
maybeFieldsR)
extractLeftJoinFields :: Int
-> T.Tag
-> HPQ.PrimExpr
-> PM.PM [(HPQ.Symbol, HPQ.PrimExpr)] HPQ.PrimExpr
Int
n = String
-> Tag
-> PrimExpr
-> StateT ([(Symbol, PrimExpr)], Int) Identity PrimExpr
forall primExpr.
String -> Tag -> primExpr -> PM [(Symbol, primExpr)] PrimExpr
PM.extractAttr (String
"result" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_")
instance Functor (NullMaker a) where
fmap :: (a -> b) -> NullMaker a a -> NullMaker a b
fmap a -> b
f (NullMaker a -> a
g) = (a -> b) -> NullMaker a b
forall a b. (a -> b) -> NullMaker a b
NullMaker ((a -> b) -> (a -> a) -> a -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f a -> a
g)
instance A.Applicative (NullMaker a) where
pure :: a -> NullMaker a a
pure = (a -> a) -> NullMaker a a
forall a b. (a -> b) -> NullMaker a b
NullMaker ((a -> a) -> NullMaker a a) -> (a -> a -> a) -> a -> NullMaker a a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a -> a
forall (f :: * -> *) a. Applicative f => a -> f a
A.pure
NullMaker a -> a -> b
f <*> :: NullMaker a (a -> b) -> NullMaker a a -> NullMaker a b
<*> NullMaker a -> a
x = (a -> b) -> NullMaker a b
forall a b. (a -> b) -> NullMaker a b
NullMaker (a -> a -> b
f (a -> a -> b) -> (a -> a) -> a -> b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
A.<*> a -> a
x)
instance Profunctor NullMaker where
dimap :: (a -> b) -> (c -> d) -> NullMaker b c -> NullMaker a d
dimap a -> b
f c -> d
g (NullMaker b -> c
h) = (a -> d) -> NullMaker a d
forall a b. (a -> b) -> NullMaker a b
NullMaker ((a -> b) -> (c -> d) -> (b -> c) -> a -> d
forall (p :: * -> * -> *) a b c d.
Profunctor p =>
(a -> b) -> (c -> d) -> p b c -> p a d
dimap a -> b
f c -> d
g b -> c
h)
instance PP.ProductProfunctor NullMaker where
purePP :: b -> NullMaker a b
purePP = b -> NullMaker a b
forall (f :: * -> *) a. Applicative f => a -> f a
pure
**** :: NullMaker a (b -> c) -> NullMaker a b -> NullMaker a c
(****) = NullMaker a (b -> c) -> NullMaker a b -> NullMaker a c
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
(<*>)