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

module Rel8.Column.Field
  ( Field, AField(..)
  )
where

-- base
import Data.Kind ( Type )
import Prelude

-- rel8
import Rel8.Aggregate ( Aggregate, Col( A ) )
import Rel8.Expr ( Expr, Col( E ) )
import Rel8.Kind.Context ( SContext(..), Reifiable( contextSing ) )
import Rel8.Kind.Necessity
  ( Necessity( Required, Optional )
  , SNecessity( SRequired, SOptional )
  , KnownNecessity, necessitySing
  )
import Rel8.Schema.HTable.Identity ( HIdentity( HIdentity ) )
import Rel8.Schema.Insert ( Col( I ), Create(..), Insert )
import qualified Rel8.Schema.Kind as K
import Rel8.Schema.Name ( Name(..), Col( N ) )
import Rel8.Schema.Null ( Sql )
import Rel8.Schema.Reify ( Reify, Col(..) )
import Rel8.Schema.Result ( Col( R ), Result )
import Rel8.Schema.Spec ( Spec( Spec ) )
import Rel8.Table
  ( Table, Columns, Context, fromColumns, toColumns
  , Unreify, reify, unreify
  )
import Rel8.Table.Recontextualize ( Recontextualize )
import Rel8.Type ( DBType )


type Field :: K.Context -> Necessity -> Type -> Type
type family Field context necessity a where
  Field (Reify context) necessity  a = AField context necessity a
  Field Aggregate       _necessity a = Aggregate a
  Field Expr            _necessity a = Expr a
  Field Insert          'Required  a = Expr a
  Field Insert          'Optional  a = Maybe (Expr a)
  Field Name            _necessity a = Name a
  Field Result          _necessity a = a


type AField :: K.Context -> Necessity -> Type -> Type
newtype AField context necessity a = AField (Field context necessity a)


instance (Reifiable context, KnownNecessity necessity, Sql DBType a) =>
  Table (Reify context) (AField context necessity a)
 where
  type Context (AField context necessity a) = Reify context
  type Columns (AField context necessity a) = HIdentity ('Spec '[] necessity a)
  type Unreify (AField context necessity a) = Field context necessity a

  fromColumns :: Columns (AField context necessity a) (Col (Reify context))
-> AField context necessity a
fromColumns (HIdentity (Reify a)) = SContext context
-> SNecessity necessity
-> Col context ('Spec '[] necessity a)
-> AField context necessity a
forall (context :: Context) (necessity :: Necessity)
       (labels :: Labels) a.
SContext context
-> SNecessity necessity
-> Col context ('Spec labels necessity a)
-> AField context necessity a
sfromColumn SContext context
forall (context :: Context). Reifiable context => SContext context
contextSing SNecessity necessity
forall (necessity :: Necessity).
KnownNecessity necessity =>
SNecessity necessity
necessitySing Col context ('Spec '[] necessity a)
a
  toColumns :: AField context necessity a
-> Columns (AField context necessity a) (Col (Reify context))
toColumns = Col (Reify context) ('Spec '[] necessity a)
-> HIdentity ('Spec '[] necessity a) (Col (Reify context))
forall (spec :: Spec) (context :: HContext).
context spec -> HIdentity spec context
HIdentity (Col (Reify context) ('Spec '[] necessity a)
 -> HIdentity ('Spec '[] necessity a) (Col (Reify context)))
-> (AField context necessity a
    -> Col (Reify context) ('Spec '[] necessity a))
-> AField context necessity a
-> HIdentity ('Spec '[] necessity a) (Col (Reify context))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Col context ('Spec '[] necessity a)
-> Col (Reify context) ('Spec '[] necessity a)
forall (context :: Context) (spec :: Spec).
Col context spec -> Col (Reify context) spec
Reify (Col context ('Spec '[] necessity a)
 -> Col (Reify context) ('Spec '[] necessity a))
-> (AField context necessity a
    -> Col context ('Spec '[] necessity a))
-> AField context necessity a
-> Col (Reify context) ('Spec '[] necessity a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SContext context
-> SNecessity necessity
-> AField context necessity a
-> Col context ('Spec '[] necessity a)
forall (context :: Context) (necessity :: Necessity) a
       (labels :: Labels).
SContext context
-> SNecessity necessity
-> AField context necessity a
-> Col context ('Spec labels necessity a)
stoColumn SContext context
forall (context :: Context). Reifiable context => SContext context
contextSing SNecessity necessity
forall (necessity :: Necessity).
KnownNecessity necessity =>
SNecessity necessity
necessitySing
  reify :: (Reify context :~: Reify ctx)
-> Unreify (AField context necessity a)
-> AField context necessity a
reify Reify context :~: Reify ctx
_ = Unreify (AField context necessity a) -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField
  unreify :: (Reify context :~: Reify ctx)
-> AField context necessity a
-> Unreify (AField context necessity a)
unreify Reify context :~: Reify ctx
_ (AField Field context necessity a
a) = Unreify (AField context necessity a)
Field context necessity a
a


instance
  ( Reifiable context, Reifiable context'
  , KnownNecessity necessity, Sql DBType a
  ) =>
  Recontextualize
    (Reify context)
    (Reify context')
    (AField context necessity a)
    (AField context' necessity a)


sfromColumn :: ()
  => SContext context
  -> SNecessity necessity
  -> Col context ('Spec labels necessity a)
  -> AField context necessity a
sfromColumn :: SContext context
-> SNecessity necessity
-> Col context ('Spec labels necessity a)
-> AField context necessity a
sfromColumn = \case
  SContext context
SAggregate -> \SNecessity necessity
_ (A a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField Aggregate a
Field context necessity a
a
  SContext context
SExpr -> \SNecessity necessity
_ (E a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField Expr a
Field context necessity a
a
  SContext context
SInsert -> \case
    SNecessity necessity
SRequired -> \case
      I (Value a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField Expr a
Field context necessity a
a
    SNecessity necessity
SOptional -> \case
      I Default -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField Field context necessity a
forall a. Maybe a
Nothing
      I (Value a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField (Expr a -> Maybe (Expr a)
forall a. a -> Maybe a
Just Expr a
a)
  SContext context
SName -> \SNecessity necessity
_ (N a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField Name a
Field context necessity a
a
  SContext context
SResult -> \SNecessity necessity
_ (R a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField a
Field context necessity a
a
  SReify SContext context
context ->
    \SNecessity necessity
necessity (Reify a) -> Field context necessity a -> AField context necessity a
forall (context :: Context) (necessity :: Necessity) a.
Field context necessity a -> AField context necessity a
AField (SContext context
-> SNecessity necessity
-> Col context ('Spec labels necessity a)
-> AField context necessity a
forall (context :: Context) (necessity :: Necessity)
       (labels :: Labels) a.
SContext context
-> SNecessity necessity
-> Col context ('Spec labels necessity a)
-> AField context necessity a
sfromColumn SContext context
context SNecessity necessity
necessity Col context ('Spec labels necessity a)
a)


stoColumn :: ()
  => SContext context
  -> SNecessity necessity
  -> AField context necessity a
  -> Col context ('Spec labels necessity a)
stoColumn :: SContext context
-> SNecessity necessity
-> AField context necessity a
-> Col context ('Spec labels necessity a)
stoColumn = \case
  SContext context
SAggregate -> \SNecessity necessity
_ (AField Field context necessity a
a) -> Aggregate a -> Col Aggregate ('Spec labels necessity a)
forall a (labels :: Labels) (necessity :: Necessity).
Aggregate a -> Col Aggregate ('Spec labels necessity a)
A Aggregate a
Field context necessity a
a
  SContext context
SExpr -> \SNecessity necessity
_ (AField Field context necessity a
a) -> Expr a -> Col Expr ('Spec labels necessity a)
forall a (labels :: Labels) (necessity :: Necessity).
Expr a -> Col Expr ('Spec labels necessity a)
E Expr a
Field context necessity a
a
  SContext context
SInsert -> \case
    SNecessity necessity
SRequired -> \(AField Field context necessity a
a) -> Create necessity a -> Col Insert ('Spec labels necessity a)
forall (necessity :: Necessity) a (labels :: Labels).
Create necessity a -> Col Insert ('Spec labels necessity a)
I (Expr a -> Create necessity a
forall a (necessity :: Necessity). Expr a -> Create necessity a
Value Expr a
Field context necessity a
a)
    SNecessity necessity
SOptional -> \(AField Field context necessity a
ma) -> Create 'Optional a -> Col Insert ('Spec labels 'Optional a)
forall (necessity :: Necessity) a (labels :: Labels).
Create necessity a -> Col Insert ('Spec labels necessity a)
I (Create 'Optional a -> Col Insert ('Spec labels 'Optional a))
-> Create 'Optional a -> Col Insert ('Spec labels 'Optional a)
forall a b. (a -> b) -> a -> b
$ Create 'Optional a
-> (Expr a -> Create 'Optional a)
-> Maybe (Expr a)
-> Create 'Optional a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Create 'Optional a
forall a. Create 'Optional a
Default Expr a -> Create 'Optional a
forall a (necessity :: Necessity). Expr a -> Create necessity a
Value Maybe (Expr a)
Field context necessity a
ma
  SContext context
SName -> \SNecessity necessity
_ (AField Field context necessity a
a) -> Name a -> Col Name ('Spec labels necessity a)
forall a (labels :: Labels) (necessity :: Necessity).
Name a -> Col Name ('Spec labels necessity a)
N Name a
Field context necessity a
a
  SContext context
SResult -> \SNecessity necessity
_ (AField Field context necessity a
a) -> a -> Col Result ('Spec labels necessity a)
forall a (labels :: Labels) (necessity :: Necessity).
a -> Col Result ('Spec labels necessity a)
R a
Field context necessity a
a
  SReify SContext context
context ->
    \SNecessity necessity
necessity (AField Field context necessity a
a) -> Col context ('Spec labels necessity a)
-> Col (Reify context) ('Spec labels necessity a)
forall (context :: Context) (spec :: Spec).
Col context spec -> Col (Reify context) spec
Reify (SContext context
-> SNecessity necessity
-> AField context necessity a
-> Col context ('Spec labels necessity a)
forall (context :: Context) (necessity :: Necessity) a
       (labels :: Labels).
SContext context
-> SNecessity necessity
-> AField context necessity a
-> Col context ('Spec labels necessity a)
stoColumn SContext context
context SNecessity necessity
necessity AField context necessity a
Field context necessity a
a)