{-# LANGUAGE TypeOperators, TypeFamilies, FlexibleInstances, FlexibleContexts #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE CPP, DataKinds, UndecidableInstances #-}
module Database.Selda.Inner where
import Database.Selda.Column
import Database.Selda.SQL (SQL)
import Database.Selda.SqlType (SqlType)
import Database.Selda.Types
import Data.Text (Text)
import Data.Typeable
import GHC.TypeLits as TL
newtype Aggr s a = Aggr {unAggr :: Exp SQL a}
liftAggr :: (Col s a -> Col s b) -> Aggr s a -> Aggr s b
liftAggr f = Aggr . unOne . f . One . unAggr
where unOne (One x) = x
data Inner s
deriving Typeable
aggr :: SqlType a => Text -> Col s a -> Aggr s b
aggr f (One x) = Aggr (AggrEx f x)
type family OuterCols a where
OuterCols (Col (Inner s) a :*: b) = Col s a :*: OuterCols b
OuterCols (Col (Inner s) a) = Col s a
OuterCols (Row (Inner s) a :*: b) = Row s a :*: OuterCols b
OuterCols (Row (Inner s) a) = Row s a
OuterCols (Col s a) = TypeError
( 'TL.Text "An inner query can only return rows and columns from its own scope."
)
OuterCols (Row s a) = TypeError
( 'TL.Text "An inner query can only return rows and columns from its own scope."
)
OuterCols a = TypeError
( 'TL.Text "Only (inductive tuples of) row and columns can be returned from" ':$$:
'TL.Text "an inner query."
)
type family AggrCols a where
AggrCols (Aggr (Inner s) a :*: b) = Col s a :*: AggrCols b
AggrCols (Aggr (Inner s) a) = Col s a
AggrCols (Aggr s a) = TypeError
( 'TL.Text "An aggregate query can only return columns from its own" ':$$:
'TL.Text "scope."
)
AggrCols a = TypeError
( 'TL.Text "Only (inductive tuples of) aggregates can be returned from" ':$$:
'TL.Text "an aggregate query."
)
type family LeftCols a where
LeftCols (Col (Inner s) (Maybe a) :*: b) = Col s (Maybe a) :*: LeftCols b
LeftCols (Col (Inner s) a :*: b) = Col s (Maybe a) :*: LeftCols b
LeftCols (Col (Inner s) (Maybe a)) = Col s (Maybe a)
LeftCols (Col (Inner s) a) = Col s (Maybe a)
LeftCols (Row (Inner s) (Maybe a) :*: b) = Row s (Maybe a) :*: LeftCols b
LeftCols (Row (Inner s) a :*: b) = Row s (Maybe a) :*: LeftCols b
LeftCols (Row (Inner s) (Maybe a)) = Row s (Maybe a)
LeftCols (Row (Inner s) a) = Row s (Maybe a)
LeftCols a = TypeError
( 'TL.Text "Only (inductive tuples of) rows and columns can be returned" ':$$:
'TL.Text "from a join."
)
class Aggregates a where
unAggrs :: a -> [UntypedCol SQL]
instance Aggregates (Aggr (Inner s) a) where
unAggrs (Aggr x) = [Untyped x]
instance Aggregates b => Aggregates (Aggr (Inner s) a :*: b) where
unAggrs (Aggr a :*: b) = Untyped a : unAggrs b