{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module Database.Esqueleto.Experimental.From
where
import qualified Control.Monad.Trans.Writer as W
import Data.Coerce (coerce)
import Data.Proxy
import qualified Data.Text.Lazy.Builder as TLB
import Database.Esqueleto.Experimental.ToAlias
import Database.Esqueleto.Experimental.ToAliasReference
import Database.Esqueleto.Internal.Internal hiding (From(..), from, on)
import Database.Esqueleto.Internal.PersistentImport
from :: ToFrom a a' => a -> SqlQuery a'
from :: forall a a'. ToFrom a a' => a -> SqlQuery a'
from a
f = do
(a'
a, RawFn
clause) <- forall a. From a -> SqlQuery (a, RawFn)
unFrom (forall a r. ToFrom a r => a -> From r
toFrom a
f)
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{sdFromClause :: [FromClause]
sdFromClause=[RawFn -> FromClause
FromRaw forall a b. (a -> b) -> a -> b
$ RawFn
clause]}
forall (f :: * -> *) a. Applicative f => a -> f a
pure a'
a
type RawFn = NeedParens -> IdentInfo -> (TLB.Builder, [PersistValue])
newtype From a = From
{ forall a. From a -> SqlQuery (a, RawFn)
unFrom :: SqlQuery (a, RawFn)}
class ToFrom a r | a -> r where
toFrom :: a -> From r
instance ToFrom (From a) a where
toFrom :: From a -> From a
toFrom = forall a. a -> a
id
{-# DEPRECATED Table "@since 3.5.0.0 - use 'table' instead" #-}
data Table a = Table
instance PersistEntity ent => ToFrom (Table ent) (SqlExpr (Entity ent)) where
toFrom :: Table ent -> From (SqlExpr (Entity ent))
toFrom Table ent
_ = forall ent. PersistEntity ent => From (SqlExpr (Entity ent))
table
table :: forall ent. PersistEntity ent => From (SqlExpr (Entity ent))
table :: forall ent. PersistEntity ent => From (SqlExpr (Entity ent))
table = forall a. SqlQuery (a, RawFn) -> From a
From forall a b. (a -> b) -> a -> b
$ do
let ed :: EntityDef
ed = forall record (proxy :: * -> *).
PersistEntity record =>
proxy record -> EntityDef
entityDef (forall {k} (t :: k). Proxy t
Proxy @ent)
Ident
ident <- DBName -> SqlQuery Ident
newIdentFor (coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ EntityDef -> EntityNameDB
getEntityDBName EntityDef
ed)
let entity :: SqlExpr (Entity ent)
entity = forall ent. PersistEntity ent => Ident -> SqlExpr (Entity ent)
unsafeSqlEntity Ident
ident
forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ ( SqlExpr (Entity ent)
entity, forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall {b}.
Monoid b =>
Ident -> EntityDef -> IdentInfo -> (Builder, b)
base Ident
ident EntityDef
ed )
where
base :: Ident -> EntityDef -> IdentInfo -> (Builder, b)
base ident :: Ident
ident@(I Text
identText) EntityDef
def IdentInfo
info =
let db :: Text
db = coerce :: forall a b. Coercible a b => a -> b
coerce forall a b. (a -> b) -> a -> b
$ EntityDef -> EntityNameDB
getEntityDBName EntityDef
def
in ( (IdentInfo -> DBName -> Builder
fromDBName IdentInfo
info (coerce :: forall a b. Coercible a b => a -> b
coerce Text
db)) forall a. Semigroup a => a -> a -> a
<>
if Text
db forall a. Eq a => a -> a -> Bool
== Text
identText
then forall a. Monoid a => a
mempty
else Builder
" AS " forall a. Semigroup a => a -> a -> a
<> IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
ident
, forall a. Monoid a => a
mempty
)
{-# DEPRECATED SubQuery "/Since: 3.4.0.0/ - It is no longer necessary to tag 'SqlQuery' values with @SubQuery@" #-}
newtype SubQuery a = SubQuery a
instance (SqlSelect a r, ToAlias a, ToAliasReference a) => ToFrom (SubQuery (SqlQuery a)) a where
toFrom :: SubQuery (SqlQuery a) -> From a
toFrom (SubQuery SqlQuery a
q) = forall a r.
(SqlSelect a r, ToAlias a, ToAliasReference a) =>
SqlQuery a -> From a
selectQuery SqlQuery a
q
instance (SqlSelect a r, ToAlias a, ToAliasReference a) => ToFrom (SqlQuery a) a where
toFrom :: SqlQuery a -> From a
toFrom = forall a r.
(SqlSelect a r, ToAlias a, ToAliasReference a) =>
SqlQuery a -> From a
selectQuery
selectQuery :: (SqlSelect a r, ToAlias a, ToAliasReference a) => SqlQuery a -> From a
selectQuery :: forall a r.
(SqlSelect a r, ToAlias a, ToAliasReference a) =>
SqlQuery a -> From a
selectQuery SqlQuery a
subquery = forall a. SqlQuery (a, RawFn) -> From a
From forall a b. (a -> b) -> a -> b
$ 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
subquery
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
subqueryAlias <- DBName -> SqlQuery Ident
newIdentFor (Text -> DBName
DBName Text
"q")
a
ref <- forall a. ToAliasReference a => Ident -> a -> SqlQuery a
toAliasReference Ident
subqueryAlias a
aliasedValue
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
ref, \NeedParens
_ IdentInfo
info ->
let (Builder
queryText,[PersistValue]
queryVals) = 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
in
( (Builder -> Builder
parens Builder
queryText) forall a. Semigroup a => a -> a -> a
<> Builder
" AS " forall a. Semigroup a => a -> a -> a
<> IdentInfo -> Ident -> Builder
useIdent IdentInfo
info Ident
subqueryAlias
, [PersistValue]
queryVals
)
)