packages feed

sqel-0.0.1.0: lib/Sqel/Migration/Ddl.hs

module Sqel.Migration.Ddl where

import Generics.SOP (NP (Nil, (:*)))
import Sqel.ColumnConstraints (ColumnConstraints, columnConstraints)
import Sqel.Data.Dd (CompInc (Merge, Nest), Dd (Dd), DdK (DdK), DdStruct (DdComp, DdPrim), Struct (Comp, Prim))
import Sqel.Data.MigrationParams (MigrationDeleteK, MigrationRenameK, MigrationRenameTypeK)
import Sqel.Data.Mods (Mods (Mods))
import Sqel.Data.PgType (ColumnType (ColumnComp, ColumnPrim), pgTypeRefSym)
import Sqel.Data.PgTypeName (MkPgTypeName (pgTypeName))
import Sqel.Data.Sel (ReifySel, Sel (SelSymbol), SelW (SelWSymbol), TSel (TSel), TSelW (TSelW), TypeName)
import Sqel.Kind (type (++))
import Sqel.ReifyDd (ReifyPrimName (reifyPrimName))

import Sqel.Migration.Data.Ddl (DdlColumn (DdlColumn), DdlColumnK (DdlColumnK), DdlType (DdlType), DdlTypeK (DdlTypeK))

appendNP :: NP f as -> NP f bs -> NP f (as ++ bs)
appendNP Nil bs =
  bs
appendNP (h :* t) bs =
  h :* appendNP t bs

type DdCols :: [DdK] -> [DdlColumnK] -> [DdlTypeK] -> Constraint
class DdCols s cols types | s -> cols types where
  ddCols :: NP Dd s -> (NP DdlColumn cols, NP DdlType types)

instance DdCols '[] '[] '[] where
  ddCols Nil = (Nil, Nil)

-- TODO the migration params could be extracted in OldColumnsChanges and passed to OldColumnChanges.
instance (
    ReifySel sel name,
    ReifyPrimName a mods,
    ColumnConstraints mods,
    DdCols ss cols types,
    rename ~ MigrationRenameK mods,
    renameType ~ MigrationRenameTypeK mods,
    delete ~ MigrationDeleteK mods
  ) => DdCols ('DdK sel mods a 'Prim : ss) ('DdlColumnK name 'Nothing mods rename renameType delete a : cols) types where
    ddCols (Dd _ m@(Mods mods) DdPrim :* t) =
      (DdlColumn Proxy (ColumnPrim (reifyPrimName @a mods) unique constr) m :* cols, types)
      where
        (unique, constr) = columnConstraints m
        (cols, types) = ddCols t

instance (
    ColumnConstraints mods,
    DdlTypes 'False ('DdK ('SelSymbol name) mods a ('Comp ('TSel tprefix tname) c 'Nest sub)) hTypes,
    DdCols ss cols types,
    allTypes ~ hTypes ++ types,
    rename ~ MigrationRenameK mods,
    renameType ~ MigrationRenameTypeK mods,
    delete ~ MigrationDeleteK mods,
    TypeName tprefix tname pgName
  ) => DdCols ('DdK ('SelSymbol name) mods a ('Comp ('TSel tprefix tname) c 'Nest sub) : ss) ('DdlColumnK name ('Just pgName) mods rename renameType delete a : cols) allTypes where
    ddCols (h@(Dd (SelWSymbol Proxy) mods (DdComp (TSelW Proxy) _ _ _)) :* t) =
      (DdlColumn Proxy (ColumnComp (pgTypeRefSym @pgName) unique constr) mods :* tailCols, appendNP subTypes tailTypes)
      where
        (unique, constr) = columnConstraints mods
        subTypes = ddTypes @'False @_ @hTypes h
        (tailCols, tailTypes) = ddCols t

instance (
    DdCols sub mergeCols subTypes,
    DdCols ss cols types,
    allCols ~ mergeCols ++ cols,
    allTypes ~ subTypes ++ types
  ) => DdCols ('DdK sel mods a ('Comp ('TSel tprefix tname) c 'Merge sub) : ss) allCols allTypes where
    ddCols (Dd _ _ (DdComp _ _ _ sub) :* t) =
      (appendNP subCols tailCols, appendNP subTypes tailTypes)
      where
        (subCols, subTypes) = ddCols sub
        (tailCols, tailTypes) = ddCols t

type DdlTypes :: Bool -> DdK -> [DdlTypeK] -> Constraint
class DdlTypes table s types | table s -> types where
  ddTypes :: Dd s -> NP DdlType types

instance (
    DdCols sub cols types,
    rename ~ MigrationRenameTypeK mods,
    MkPgTypeName tprefix tname table pgName
  ) => DdlTypes table ('DdK sel mods a ('Comp ('TSel tprefix tname) c i sub)) ('DdlTypeK table pgName rename cols : types) where
  ddTypes (Dd _ _ (DdComp (TSelW Proxy) _ _ sub)) =
    DdlType (pgTypeName @tprefix @tname) cols :* types
    where
      (cols, types) = ddCols sub

ddTable ::
  DdlTypes 'True s (table : types) =>
  Dd s ->
  (DdlType table, NP DdlType types)
ddTable dd =
  (table, types)
  where
    table :* types = ddTypes @'True dd