packages feed

sqel-0.0.1.0: lib/Sqel/ReifyDd.hs

module Sqel.ReifyDd where

import Generics.SOP (I (I), NP (Nil, (:*)), tl)

import Sqel.Class.Mods (MaybeMod (maybeMod))
import Sqel.Codec (PrimColumn (pgType))
import Sqel.ColumnConstraints (ColumnConstraints, columnConstraints)
import Sqel.Data.Dd (Dd (Dd), DdK (DdK), DdStruct (DdComp, DdPrim), Struct (Comp, Prim))
import Sqel.Data.Mods (
  ArrayColumn (ArrayColumn),
  Mods (Mods),
  Newtype (Newtype),
  Nullable (Nullable),
  SetTableName,
  unSetTableName,
  )
import Sqel.Data.PgType (PgPrimName, pgColumnName)
import Sqel.Data.Sel (ReifySel (reifySel), SelW (SelWSymbol), TSelW (TSelW))
import qualified Sqel.Data.Term as Term
import Sqel.Data.Term (DdTerm (DdTerm), demoteComp, demoteInc)
import Sqel.SOP.Constraint (symbolText)

class ReifyPrimName a mods where
  reifyPrimName :: NP I mods -> PgPrimName

instance {-# overlappable #-} (
    ReifyPrimName a mods
  ) => ReifyPrimName a (p : mods) where
    reifyPrimName = reifyPrimName @a . tl

instance (
    PrimColumn a
  ) => ReifyPrimName a '[] where
    reifyPrimName Nil = pgType @a

instance (
    ReifyPrimName a mods
  ) => ReifyPrimName (Maybe a) (Nullable : mods) where
    reifyPrimName (I Nullable :* mods) = reifyPrimName @a mods

instance (
    ReifyPrimName a mods
  ) => ReifyPrimName (f a) (ArrayColumn f : mods) where
    reifyPrimName (I ArrayColumn :* mods) = reifyPrimName @a mods <> "[]"

instance (
    ReifyPrimName w mods
  ) => ReifyPrimName a (Newtype a w : mods) where
    reifyPrimName (I (Newtype _ _) :* mods) = reifyPrimName @w mods

instance ReifyPrimName a (PgPrimName : mods) where
  reifyPrimName (I t :* _) = t

class ReifyDd s where
  reifyDd :: Dd s -> DdTerm

instance (
    ColumnConstraints mods,
    MaybeMod SetTableName mods,
    ReifyPrimName a mods,
    ReifySel sel name
  ) => ReifyDd ('DdK sel mods a 'Prim) where
    reifyDd (Dd sel mods@(Mods ms) DdPrim) =
      DdTerm (pgColumnName name) (unSetTableName <$> maybeMod mods) unique constraints (Term.Prim (reifyPrimName @a ms))
      where
        (unique, constraints) = columnConstraints mods
        name = reifySel sel

instance (
    ColumnConstraints mods,
    MaybeMod SetTableName mods,
    ReifyDdComp sub
  ) => ReifyDd ('DdK sel mods a ('Comp tsel c i sub)) where
    reifyDd (Dd sel mods (DdComp (TSelW (Proxy :: Proxy '(tname, tpe))) c i sub)) =
      DdTerm (pgColumnName name) (unSetTableName <$> maybeMod mods) unique constraints struct
      where
        (unique, constraints) = columnConstraints mods
        struct = Term.Comp typeName (demoteComp c) (demoteInc i) (reifyDdComp sub)
        name = case sel of
          SelWSymbol (Proxy :: Proxy name) -> symbolText @name
          _ -> symbolText @tname
        typeName = symbolText @tpe

-- TODO this is probably only necessary because of a bug in GHC that's fixed in master
class ReifyDdComp s where
  reifyDdComp :: NP Dd s -> [DdTerm]

instance ReifyDdComp '[] where
  reifyDdComp Nil = []

instance (
    ReifyDd s,
    ReifyDdComp ss
  ) => ReifyDdComp (s : ss) where
    reifyDdComp (s :* ss) = reifyDd s : reifyDdComp ss