packages feed

large-generics-0.1.0.0: test/Test/Record/Generic/Infra/Beam/Mini.hs

{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE KindSignatures       #-}
{-# LANGUAGE RankNTypes           #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE TypeFamilies         #-}
{-# LANGUAGE UndecidableInstances #-}

-- TODO: cleanup

module Test.Record.Generic.Infra.Beam.Mini (
    Columnar
  , Columnar'(..)
  , applyColumnar'
  , PrimaryKey
  , Table
  , Lenses
  , Beamable(..)
  , WrapLens(..)
  ) where

import Data.Functor.Identity
import Data.Kind
import Data.Proxy
import Lens.Micro (Lens')

data Nullable (c :: Type -> Type) x

data Lenses (tbl :: (Type -> Type) -> Type) (f :: Type -> Type) (x :: Type)

data WrapLens a b = WrapLens (Lens' a b)

type family Columnar (f :: Type -> Type) x where
  Columnar Identity       x = x
  Columnar (Nullable c)   x = Columnar c (Maybe x)
  Columnar (Lenses tbl f) x = WrapLens (tbl f) (Columnar f x)
  Columnar f              x = f x

newtype Columnar' f a = Columnar' { getColumnar' :: Columnar f a }

applyColumnar' :: forall m f g h x.
     Functor m
  => Proxy x
  -> (Columnar' f x -> Columnar' g x -> m (Columnar' h x))
  -> (Columnar  f x -> Columnar  g x -> m (Columnar  h x))
applyColumnar' _ f fx gx = getColumnar' <$> f (Columnar' fx) (Columnar' gx)

class Beamable (table :: (Type -> Type) -> Type) where
  zipBeamFieldsM ::
       Applicative m
    => (forall a. Columnar' f a -> Columnar' g a -> m (Columnar' h a))
    -> table f -> table g -> m (table h)

-- | Primary key of a table
--
-- In beam this is an associated type of the 'Table' class; we split this off
-- so that we can define the basic table definitions without needing to define
-- the transform ('zipBeamFieldsM') at the same time.
data family PrimaryKey (table :: (Type -> Type) -> Type) :: (Type -> Type) -> Type

class (Beamable table, Beamable (PrimaryKey table)) => Table table where