{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
module Database.Esqueleto.Experimental.From.CommonTableExpression
where
import qualified Control.Monad.Trans.Writer as W
import qualified Data.Text.Lazy.Builder as TLB
import Database.Esqueleto.Experimental.From
import Database.Esqueleto.Experimental.From.SqlSetOperation
import Database.Esqueleto.Experimental.ToAlias
import Database.Esqueleto.Experimental.ToAliasReference
import Database.Esqueleto.Internal.Internal hiding (From(..), from, on)
with :: ( ToAlias a
, ToAliasReference a
, SqlSelect a r
) => SqlQuery a -> SqlQuery (From a)
with :: forall a r.
(ToAlias a, ToAliasReference a, SqlSelect a r) =>
SqlQuery a -> SqlQuery (From a)
with SqlQuery a
query = do
(ret, sideData) <- WriterT SideData (State IdentState) (a, SideData)
-> SqlQuery (a, SideData)
forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q (WriterT SideData (State IdentState) (a, SideData)
-> SqlQuery (a, SideData))
-> WriterT SideData (State IdentState) (a, SideData)
-> SqlQuery (a, SideData)
forall a b. (a -> b) -> a -> b
$ (SideData -> SideData)
-> WriterT SideData (State IdentState) (a, SideData)
-> WriterT SideData (State IdentState) (a, SideData)
forall (m :: * -> *) w a.
Monad m =>
(w -> w) -> WriterT w m a -> WriterT w m a
W.censor (\SideData
_ -> SideData
forall a. Monoid a => a
mempty) (WriterT SideData (State IdentState) (a, SideData)
-> WriterT SideData (State IdentState) (a, SideData))
-> WriterT SideData (State IdentState) (a, SideData)
-> WriterT SideData (State IdentState) (a, SideData)
forall a b. (a -> b) -> a -> b
$ WriterT SideData (State IdentState) a
-> WriterT SideData (State IdentState) (a, SideData)
forall (m :: * -> *) w a.
Monad m =>
WriterT w m a -> WriterT w m (a, w)
W.listen (WriterT SideData (State IdentState) a
-> WriterT SideData (State IdentState) (a, SideData))
-> WriterT SideData (State IdentState) a
-> WriterT SideData (State IdentState) (a, SideData)
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> WriterT SideData (State IdentState) a
forall a. SqlQuery a -> WriterT SideData (State IdentState) a
unQ SqlQuery a
query
aliasedValue <- toAlias ret
let aliasedQuery = WriterT SideData (State IdentState) a -> SqlQuery a
forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q (WriterT SideData (State IdentState) a -> SqlQuery a)
-> WriterT SideData (State IdentState) a -> SqlQuery a
forall a b. (a -> b) -> a -> b
$ State IdentState (a, SideData)
-> WriterT SideData (State IdentState) a
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
W.WriterT (State IdentState (a, SideData)
-> WriterT SideData (State IdentState) a)
-> State IdentState (a, SideData)
-> WriterT SideData (State IdentState) a
forall a b. (a -> b) -> a -> b
$ (a, SideData) -> State IdentState (a, SideData)
forall a. a -> StateT IdentState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
aliasedValue, SideData
sideData)
ident <- newIdentFor (DBName "cte")
let clause = CommonTableExpressionKind
-> CommonTableExpressionModifierAfterAs
-> Ident
-> (IdentInfo -> (Builder, [PersistValue]))
-> CommonTableExpressionClause
CommonTableExpressionClause CommonTableExpressionKind
NormalCommonTableExpression (\CommonTableExpressionClause
_ IdentInfo
_ -> Builder
"") Ident
ident (\IdentInfo
info -> Mode -> IdentInfo -> SqlQuery a -> (Builder, [PersistValue])
forall a r backend.
(SqlSelect a r, BackendCompatible SqlBackend backend) =>
Mode
-> (backend, IdentState) -> SqlQuery a -> (Builder, [PersistValue])
toRawSql Mode
SELECT IdentInfo
info SqlQuery a
aliasedQuery)
Q $ W.tell mempty{sdCteClause = [clause]}
ref <- toAliasReference ident aliasedValue
pure $ From $ do
newIdent <- newIdentFor (DBName "cte")
localRef <- toAliasReference newIdent ref
let makeLH IdentInfo
info = IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
ident Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
" AS " Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
newIdent
pure (localRef, (\NeedParens
_ IdentInfo
info -> (IdentInfo -> Builder
makeLH IdentInfo
info, [PersistValue]
forall a. Monoid a => a
mempty)))
withRecursive :: ( ToAlias a
, ToAliasReference a
, SqlSelect a r
)
=> SqlQuery a
-> UnionKind
-> (From a -> SqlQuery a)
-> SqlQuery (From a)
withRecursive :: forall a r.
(ToAlias a, ToAliasReference a, SqlSelect a r) =>
SqlQuery a
-> UnionKind -> (From a -> SqlQuery a) -> SqlQuery (From a)
withRecursive SqlQuery a
baseCase UnionKind
unionKind From a -> SqlQuery a
recursiveCase = do
(ret, sideData) <- WriterT SideData (State IdentState) (a, SideData)
-> SqlQuery (a, SideData)
forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q (WriterT SideData (State IdentState) (a, SideData)
-> SqlQuery (a, SideData))
-> WriterT SideData (State IdentState) (a, SideData)
-> SqlQuery (a, SideData)
forall a b. (a -> b) -> a -> b
$ (SideData -> SideData)
-> WriterT SideData (State IdentState) (a, SideData)
-> WriterT SideData (State IdentState) (a, SideData)
forall (m :: * -> *) w a.
Monad m =>
(w -> w) -> WriterT w m a -> WriterT w m a
W.censor (\SideData
_ -> SideData
forall a. Monoid a => a
mempty) (WriterT SideData (State IdentState) (a, SideData)
-> WriterT SideData (State IdentState) (a, SideData))
-> WriterT SideData (State IdentState) (a, SideData)
-> WriterT SideData (State IdentState) (a, SideData)
forall a b. (a -> b) -> a -> b
$ WriterT SideData (State IdentState) a
-> WriterT SideData (State IdentState) (a, SideData)
forall (m :: * -> *) w a.
Monad m =>
WriterT w m a -> WriterT w m (a, w)
W.listen (WriterT SideData (State IdentState) a
-> WriterT SideData (State IdentState) (a, SideData))
-> WriterT SideData (State IdentState) a
-> WriterT SideData (State IdentState) (a, SideData)
forall a b. (a -> b) -> a -> b
$ SqlQuery a -> WriterT SideData (State IdentState) a
forall a. SqlQuery a -> WriterT SideData (State IdentState) a
unQ SqlQuery a
baseCase
aliasedValue <- toAlias ret
let aliasedQuery = WriterT SideData (State IdentState) a -> SqlQuery a
forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q (WriterT SideData (State IdentState) a -> SqlQuery a)
-> WriterT SideData (State IdentState) a -> SqlQuery a
forall a b. (a -> b) -> a -> b
$ State IdentState (a, SideData)
-> WriterT SideData (State IdentState) a
forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
W.WriterT (State IdentState (a, SideData)
-> WriterT SideData (State IdentState) a)
-> State IdentState (a, SideData)
-> WriterT SideData (State IdentState) a
forall a b. (a -> b) -> a -> b
$ (a, SideData) -> State IdentState (a, SideData)
forall a. a -> StateT IdentState Identity a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
aliasedValue, SideData
sideData)
ident <- newIdentFor (DBName "cte")
ref <- toAliasReference ident aliasedValue
let refFrom = SqlQuery (a, RawFn) -> From a
forall a. SqlQuery (a, RawFn) -> From a
From ((a, RawFn) -> SqlQuery (a, RawFn)
forall a. a -> SqlQuery a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
ref, (\NeedParens
_ IdentInfo
info -> (IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
ident, [PersistValue]
forall a. Monoid a => a
mempty))))
let recursiveQuery = From a -> SqlQuery a
recursiveCase From a
refFrom
let noModifier p
_ p
_ = a
""
let clause = CommonTableExpressionKind
-> CommonTableExpressionModifierAfterAs
-> Ident
-> (IdentInfo -> (Builder, [PersistValue]))
-> CommonTableExpressionClause
CommonTableExpressionClause CommonTableExpressionKind
RecursiveCommonTableExpression CommonTableExpressionModifierAfterAs
forall {a} {p} {p}. IsString a => p -> p -> a
noModifier Ident
ident
(\IdentInfo
info -> (Mode -> IdentInfo -> SqlQuery a -> (Builder, [PersistValue])
forall a r backend.
(SqlSelect a r, BackendCompatible SqlBackend backend) =>
Mode
-> (backend, IdentState) -> SqlQuery a -> (Builder, [PersistValue])
toRawSql Mode
SELECT IdentInfo
info SqlQuery a
aliasedQuery)
(Builder, [PersistValue])
-> (Builder, [PersistValue]) -> (Builder, [PersistValue])
forall a. Semigroup a => a -> a -> a
<> (Builder
"\n" Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> (UnionKind -> Builder
unUnionKind UnionKind
unionKind) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
"\n", [PersistValue]
forall a. Monoid a => a
mempty)
(Builder, [PersistValue])
-> (Builder, [PersistValue]) -> (Builder, [PersistValue])
forall a. Semigroup a => a -> a -> a
<> (Mode -> IdentInfo -> SqlQuery a -> (Builder, [PersistValue])
forall a r backend.
(SqlSelect a r, BackendCompatible SqlBackend backend) =>
Mode
-> (backend, IdentState) -> SqlQuery a -> (Builder, [PersistValue])
toRawSql Mode
SELECT IdentInfo
info SqlQuery a
recursiveQuery)
)
Q $ W.tell mempty{sdCteClause = [clause]}
pure refFrom
newtype UnionKind = UnionKind { UnionKind -> Builder
unUnionKind :: TLB.Builder }
instance Union_ UnionKind where
union_ :: UnionKind
union_ = Builder -> UnionKind
UnionKind Builder
"UNION"
instance UnionAll_ UnionKind where
unionAll_ :: UnionKind
unionAll_ = Builder -> UnionKind
UnionKind Builder
"UNION ALL"