{-# 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
(a
ret, SideData
sideData) <- forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w a.
Monad m =>
(w -> w) -> WriterT w m a -> WriterT w m a
W.censor (\SideData
_ -> forall a. Monoid a => a
mempty) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w a.
Monad m =>
WriterT w m a -> WriterT w m (a, w)
W.listen forall a b. (a -> b) -> a -> b
$ forall a. SqlQuery a -> WriterT SideData (State IdentState) a
unQ SqlQuery a
query
a
aliasedValue <- forall a. ToAlias a => a -> SqlQuery a
toAlias a
ret
let aliasedQuery :: SqlQuery a
aliasedQuery = forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q forall a b. (a -> b) -> a -> b
$ forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
W.WriterT forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
aliasedValue, SideData
sideData)
Ident
ident <- DBName -> SqlQuery Ident
newIdentFor (Text -> DBName
DBName Text
"cte")
let clause :: CommonTableExpressionClause
clause = CommonTableExpressionKind
-> Ident
-> (IdentInfo -> (Builder, [PersistValue]))
-> CommonTableExpressionClause
CommonTableExpressionClause CommonTableExpressionKind
NormalCommonTableExpression Ident
ident (\IdentInfo
info -> 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)
forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
W.tell forall a. Monoid a => a
mempty{sdCteClause :: [CommonTableExpressionClause]
sdCteClause = [CommonTableExpressionClause
clause]}
a
ref <- forall a. ToAliasReference a => Ident -> a -> SqlQuery a
toAliasReference Ident
ident a
aliasedValue
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall a. SqlQuery (a, RawFn) -> From a
From forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
ref, (\NeedParens
_ IdentInfo
info -> (IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
ident, 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
(a
ret, SideData
sideData) <- forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w a.
Monad m =>
(w -> w) -> WriterT w m a -> WriterT w m a
W.censor (\SideData
_ -> forall a. Monoid a => a
mempty) forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w a.
Monad m =>
WriterT w m a -> WriterT w m (a, w)
W.listen forall a b. (a -> b) -> a -> b
$ forall a. SqlQuery a -> WriterT SideData (State IdentState) a
unQ SqlQuery a
baseCase
a
aliasedValue <- forall a. ToAlias a => a -> SqlQuery a
toAlias a
ret
let aliasedQuery :: SqlQuery a
aliasedQuery = forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q forall a b. (a -> b) -> a -> b
$ forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
W.WriterT forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
aliasedValue, SideData
sideData)
Ident
ident <- DBName -> SqlQuery Ident
newIdentFor (Text -> DBName
DBName Text
"cte")
a
ref <- forall a. ToAliasReference a => Ident -> a -> SqlQuery a
toAliasReference Ident
ident a
aliasedValue
let refFrom :: From a
refFrom = forall a. SqlQuery (a, RawFn) -> From a
From (forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
ref, (\NeedParens
_ IdentInfo
info -> (IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
ident, forall a. Monoid a => a
mempty))))
let recursiveQuery :: SqlQuery a
recursiveQuery = From a -> SqlQuery a
recursiveCase From a
refFrom
let clause :: CommonTableExpressionClause
clause = CommonTableExpressionKind
-> Ident
-> (IdentInfo -> (Builder, [PersistValue]))
-> CommonTableExpressionClause
CommonTableExpressionClause CommonTableExpressionKind
RecursiveCommonTableExpression Ident
ident
(\IdentInfo
info -> (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)
forall a. Semigroup a => a -> a -> a
<> (Builder
"\n" forall a. Semigroup a => a -> a -> a
<> (UnionKind -> Builder
unUnionKind UnionKind
unionKind) forall a. Semigroup a => a -> a -> a
<> Builder
"\n", forall a. Monoid a => a
mempty)
forall a. Semigroup a => a -> a -> a
<> (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)
)
forall a. WriterT SideData (State IdentState) a -> SqlQuery a
Q forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
W.tell forall a. Monoid a => a
mempty{sdCteClause :: [CommonTableExpressionClause]
sdCteClause = [CommonTableExpressionClause
clause]}
forall (f :: * -> *) a. Applicative f => a -> f a
pure From a
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"