packages feed

rel8-1.0.0.0: src/Rel8/Column/Either.hs

{-# language DataKinds #-}
{-# language FlexibleContexts #-}
{-# language LambdaCase #-}
{-# language MultiParamTypeClasses #-}
{-# language StandaloneKindSignatures #-}
{-# language TypeFamilies #-}
{-# language UndecidableInstances #-}

module Rel8.Column.Either
  ( HEither, AHEither(..)
  )
where

-- base
import Control.Applicative ( liftA2 )
import Data.Bifunctor ( Bifunctor, bimap )
import Data.Kind ( Type )
import Prelude

-- rel8
import Rel8.Aggregate ( Aggregate )
import Rel8.Expr ( Expr )
import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
import Rel8.Schema.Context ( Col )
import Rel8.Schema.HTable.Either ( HEitherTable )
import qualified Rel8.Schema.Kind as K
import Rel8.Schema.Name ( Name(..) )
import Rel8.Schema.Reify ( Reify, hreify, hunreify )
import Rel8.Schema.Result ( Result )
import Rel8.Table
  ( Table, Columns, Context, fromColumns, toColumns
  , Unreify, reify, unreify
  )
import Rel8.Table.Either ( EitherTable )
import Rel8.Table.Recontextualize ( Recontextualize )


-- | Nest an 'Either' value within a 'Rel8able'. @HEither f a b@ will produce a
-- 'EitherTable' @a b@ in the 'Expr' context, and a 'Either' @a b@ in the
-- 'Result' context.
type HEither :: K.Context -> Type -> Type -> Type
type family HEither context where
  HEither (Reify context) = AHEither context
  HEither Aggregate = EitherTable
  HEither Expr = EitherTable
  HEither Name = EitherTable
  HEither Result = Either


type AHEither :: K.Context -> Type -> Type -> Type
newtype AHEither context a b = AHEither (HEither context a b)


instance Reifiable context => Bifunctor (AHEither context) where
  bimap = sbimapEither contextSing


instance Reifiable context => Functor (AHEither context a) where
  fmap = bimap id


instance (Reifiable context, Table (Reify context) a, Table (Reify context) b)
  => Table (Reify context) (AHEither context a b)
 where
  type Context (AHEither context a b) = Reify context
  type Columns (AHEither context a b) = HEitherTable (Columns a) (Columns b)
  type Unreify (AHEither context a b) = HEither context (Unreify a) (Unreify b)

  fromColumns = sfromColumnsEither contextSing
  toColumns = stoColumnsEither contextSing
  reify proof = liftA2 bimap reify reify proof . AHEither
  unreify proof = (\(AHEither a) -> a) . liftA2 bimap unreify unreify proof


instance
  ( Reifiable context, Reifiable context'
  , Recontextualize (Reify context) (Reify context') a a'
  , Recontextualize (Reify context) (Reify context') b b'
  ) =>
  Recontextualize
    (Reify context)
    (Reify context')
    (AHEither context a b)
    (AHEither context' a' b')


sbimapEither :: ()
  => SContext context
  -> (a -> c)
  -> (b -> d)
  -> AHEither context a b
  -> AHEither context c d
sbimapEither = \case
  SAggregate -> \f g (AHEither a) -> AHEither (bimap f g a)
  SExpr -> \f g (AHEither a) -> AHEither (bimap f g a)
  SResult -> \f g (AHEither a) -> AHEither (bimap f g a)
  SName -> \f g (AHEither a) -> AHEither (bimap f g a)
  SReify context -> \f g (AHEither a) -> AHEither (sbimapEither context f g a)


sfromColumnsEither :: (Table (Reify context) a, Table (Reify context) b)
  => SContext context
  -> HEitherTable (Columns a) (Columns b) (Col (Reify context))
  -> AHEither context a b
sfromColumnsEither = \case
  SAggregate ->
    AHEither .
    bimap (fromColumns . hreify) (fromColumns . hreify) .
    fromColumns .
    hunreify
  SExpr ->
    AHEither .
    bimap (fromColumns . hreify) (fromColumns . hreify) .
    fromColumns .
    hunreify
  SResult ->
    AHEither .
    bimap (fromColumns . hreify) (fromColumns . hreify) .
    fromColumns .
    hunreify
  SName ->
    AHEither .
    bimap (fromColumns . hreify) (fromColumns . hreify) .
    fromColumns .
    hunreify
  SReify context ->
    AHEither .
    sbimapEither context (fromColumns . hreify) (fromColumns . hreify) .
    sfromColumnsEither context .
    hunreify


stoColumnsEither :: (Table (Reify context) a, Table (Reify context) b)
  => SContext context
  -> AHEither context a b
  -> HEitherTable (Columns a) (Columns b) (Col (Reify context))
stoColumnsEither = \case
  SAggregate ->
    hreify .
    toColumns .
    bimap (hunreify . toColumns) (hunreify . toColumns) .
    (\(AHEither a) -> a)
  SExpr ->
    hreify .
    toColumns .
    bimap (hunreify . toColumns) (hunreify . toColumns) .
    (\(AHEither a) -> a)
  SResult ->
    hreify .
    toColumns .
    bimap (hunreify . toColumns) (hunreify . toColumns) .
    (\(AHEither a) -> a)
  SName ->
    hreify .
    toColumns .
    bimap (hunreify . toColumns) (hunreify . toColumns) .
    (\(AHEither a) -> a)
  SReify context ->
    hreify .
    stoColumnsEither context .
    sbimapEither context (hunreify . toColumns) (hunreify . toColumns) .
    (\(AHEither a) -> a)