{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE UndecidableInstances #-}
module Database.Beam.Schema.Lenses
( tableLenses
, TableLens(..)
, dbLenses ) where
import Database.Beam.Schema.Tables
import Control.Monad.Identity
import Data.Kind (Type)
import Data.Proxy
import GHC.Generics
import Lens.Micro hiding (to)
class GTableLenses t (m :: Type -> Type) a (lensType :: Type -> Type) where
gTableLenses :: Proxy a -> Lens' (t m) (a p) -> lensType ()
instance GTableLenses t m a al => GTableLenses t m (M1 s d a) (M1 s d al) where
gTableLenses (Proxy :: Proxy (M1 s d a)) lensToHere = M1 $ gTableLenses (Proxy :: Proxy a) (\f -> lensToHere (\(M1 x) -> M1 <$> f x))
instance (GTableLenses t m a aLens, GTableLenses t m b bLens) => GTableLenses t m (a :*: b) (aLens :*: bLens) where
gTableLenses (Proxy :: Proxy (a :*: b)) lensToHere = leftLenses :*: rightLenses
where leftLenses = gTableLenses (Proxy :: Proxy a) (\f -> lensToHere (\(a :*: b) -> (:*: b) <$> f a))
rightLenses = gTableLenses (Proxy :: Proxy b) (\f -> lensToHere (\(a :*: b) -> (a :*:) <$> f b))
instance Generic (t m) => GTableLenses t m (K1 R x) (K1 R (LensFor (t m) x)) where
gTableLenses _ lensToHere = K1 (LensFor (\f -> lensToHere (\(K1 x) -> K1 <$> f x)))
instance ( Generic (sub m)
, Generic (sub (Lenses t m))
, GTableLenses t m (Rep (sub m)) (Rep (sub (Lenses t m))) ) =>
GTableLenses t m (K1 R (sub m)) (K1 R (sub (Lenses t m))) where
gTableLenses _ lensToHere = K1 (to (gTableLenses (Proxy :: Proxy (Rep (sub m))) (\f -> lensToHere (\(K1 x) -> K1 . to <$> f (from x)))))
instance ( Generic (sub (Nullable m))
, Generic (sub (Nullable (Lenses t m)))
, GTableLenses t m (Rep (sub (Nullable m))) (Rep (sub (Nullable (Lenses t m))))) =>
GTableLenses t m (K1 R (sub (Nullable m))) (K1 R (sub (Nullable (Lenses t m)))) where
gTableLenses _ lensToHere = K1 (to (gTableLenses (Proxy :: Proxy (Rep (sub (Nullable m)))) (\f -> lensToHere (\(K1 x) -> K1 . to <$> f (from x)))))
tableLenses' :: ( lensType ~ Lenses t f
, Generic (t lensType)
, Generic (t f)
, GTableLenses t f (Rep (t f)) (Rep (t lensType)) ) =>
Proxy t -> Proxy f -> t lensType
tableLenses' (Proxy :: Proxy t) (Proxy :: Proxy f) =
to (gTableLenses (Proxy :: Proxy (Rep (t f))) ((\f x -> to <$> f (from x)) :: Lens' (t f) (Rep (t f) ())))
tableLenses :: ( lensType ~ Lenses t f
, Generic (t lensType)
, Generic (t f)
, GTableLenses t f (Rep (t f)) (Rep (t lensType)) ) =>
t (Lenses t f)
tableLenses = let res = tableLenses' (tProxy res) (fProxy res)
tProxy :: t (Lenses t f) -> Proxy t
tProxy _ = Proxy
fProxy :: t (Lenses t f) -> Proxy f
fProxy _ = Proxy
in res
newtype TableLens f db (x :: k) = TableLens (Lens' (db f) (f x))
class GDatabaseLenses outer structure lensType where
gDatabaseLenses :: Lens' outer (structure p) -> lensType ()
instance GDatabaseLenses db a al => GDatabaseLenses db (M1 s d a) (M1 s d al) where
gDatabaseLenses lensToHere = M1 $ gDatabaseLenses (\f -> lensToHere (\(M1 x) -> M1 <$> f x))
instance (GDatabaseLenses db a al, GDatabaseLenses db b bl) => GDatabaseLenses db (a :*: b) (al :*: bl) where
gDatabaseLenses lensToHere = leftLenses :*: rightLenses
where leftLenses = gDatabaseLenses (\f -> lensToHere (\(a :*: b) -> (:*: b) <$> f a))
rightLenses = gDatabaseLenses (\f -> lensToHere (\(a :*: b) -> (a :*:) <$> f b))
instance GDatabaseLenses (db f) (K1 R (f x))
(K1 R (TableLens f db x)) where
gDatabaseLenses lensToHere = K1 (TableLens (\f -> lensToHere (\(K1 x) -> K1 <$> f x)))
dbLenses :: ( Generic (db (TableLens f db))
, Generic (db f)
, GDatabaseLenses (db f) (Rep (db f)) (Rep (db (TableLens f db))) )
=> db (TableLens f db)
dbLenses = fix $ \(_ :: db (TableLens f db)) ->
to (gDatabaseLenses (\f (x :: db f) -> to <$> f (from x)) :: Rep (db (TableLens f db)) ())