{-# LANGUAGE ScopedTypeVariables, TypeOperators, KindSignatures #-}
{-# LANGUAGE TypeFamilies, FlexibleInstances, MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleContexts, UndecidableInstances #-}
module Database.Selda.MakeSelectors
( Selectors, GSelectors
, selectors, tableWithSelectors
) where
import Control.Monad.State.Strict
import Data.Proxy
import GHC.Generics hiding (Selector, (:*:))
import qualified GHC.Generics as G
import Database.Selda.Generic (Relational)
import Database.Selda.Selectors
import Database.Selda.SqlRow
import Database.Selda.SqlType
import Database.Selda.Table
import Database.Selda.Types
selectors :: forall a. (Relational a, GSelectors a (Rep a))
=> Table a
-> Selectors a
selectors _ = selectorsFor (Proxy :: Proxy a)
tableWithSelectors :: forall a. (Relational a, GSelectors a (Rep a))
=> TableName
-> [Attr a]
-> (Table a, Selectors a)
tableWithSelectors name cs = (t, s)
where
t = table name cs
s = selectors t
selectorsFor :: forall r. GSelectors r (Rep r) => Proxy r -> Selectors r
selectorsFor = flip evalState 0 . mkSel (Proxy :: Proxy (Rep r))
type Selectors r = Sels r (Rep r)
type family Sels t f where
Sels t ((a G.:*: b) G.:*: c) = Sels t (a G.:*: (b G.:*: c))
Sels t (a G.:*: b) = Sels t a :*: Sels t b
Sels t (M1 x y f) = Sels t f
Sels t (K1 i a) = Selector t a
class GSelectors t (f :: * -> *) where
mkSel :: Proxy f -> Proxy t -> State Int (Sels t f)
instance (SqlRow t, SqlType a) => GSelectors t (K1 i a) where
mkSel _ _ = unsafeSelector <$> state (\n -> (n, n+1))
instance (GSelectors t f, Sels t f ~ Sels t (M1 x y f)) =>
GSelectors t (M1 x y f) where
mkSel _ = mkSel (Proxy :: Proxy f)
instance GSelectors t (a G.:*: (b G.:*: c)) =>
GSelectors t ((a G.:*: b) G.:*: c) where
mkSel _ = mkSel (Proxy :: Proxy (a G.:*: (b G.:*: c)))
instance {-# OVERLAPPABLE #-}
( GSelectors t a
, GSelectors t b
, Sels t (a G.:*: b) ~ (Sels t a :*: Sels t b)
) => GSelectors t (a G.:*: b) where
mkSel _ p = do
x <- mkSel (Proxy :: Proxy a) p
xs <- mkSel (Proxy :: Proxy b) p
return (x :*: xs)