packages feed

rel8-1.0.0.0: src/Rel8/Schema/HTable/Label.hs

{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE LambdaCase #-}
{-# language ConstraintKinds #-}
{-# language DataKinds #-}
{-# language FlexibleInstances #-}
{-# language GADTs #-}
{-# language MultiParamTypeClasses #-}
{-# language QuantifiedConstraints #-}
{-# language RankNTypes #-}
{-# language RecordWildCards #-}
{-# language ScopedTypeVariables #-}
{-# language StandaloneKindSignatures #-}
{-# language TypeFamilies #-}
{-# language TypeOperators #-}
{-# language UndecidableInstances #-}

module Rel8.Schema.HTable.Label
  ( HLabel, Label
  , hlabel, hunlabel
  )
where

-- base
import Data.Proxy ( Proxy( Proxy ) )
import GHC.TypeLits ( KnownSymbol, Symbol )
import Prelude

-- rel8
import Rel8.Kind.Labels ( SLabels( SCons ) )
import Rel8.Schema.HTable
  ( HTable
  , hfield, htabulate, hspecs
  )
import qualified Rel8.Schema.Kind as K
import Rel8.Schema.Spec ( Spec( Spec ), SSpec(..) )
import Rel8.FCF
import Rel8.Schema.HTable.MapTable
import GHC.Generics (Generic)


type HLabel :: Symbol -> K.HTable -> K.HTable
newtype HLabel label table context = HLabel (HMapTable (Label label) table context)
  deriving stock Generic
  deriving anyclass HTable


data Label :: Symbol -> Spec -> Exp Spec


type instance Eval (Label label ('Spec labels a)) = 'Spec (label : labels) a


instance KnownSymbol l => MapSpec (Label l) where
  mapInfo = \case
    SSpec {..} -> SSpec {labels = SCons Proxy labels, ..}


hlabel :: (HTable t, KnownSymbol label)
  => (forall labels a. ()
    => context ('Spec labels a)
    -> context ('Spec (label ': labels) a))
  -> t context
  -> HLabel label t context
hlabel labeler a = HLabel $ htabulate $ \(HMapTableField field) ->
  case hfield hspecs field of
    SSpec {} -> labeler (hfield a field)
{-# INLINABLE hlabel #-}


hunlabel :: (HTable t, KnownSymbol label)
  => (forall labels a. ()
    => context ('Spec (label ': labels) a)
    -> context ('Spec labels a))
  -> HLabel label t context
  -> t context
hunlabel unlabler (HLabel as) =
  htabulate $ \field -> 
    case hfield hspecs field of
      SSpec {} -> case hfield as (HMapTableField field) of
        a -> unlabler a
{-# INLINABLE hunlabel #-}