sqel-0.0.1.0: lib/Sqel/Data/Dd.hs
module Sqel.Data.Dd where
import Generics.SOP (I, NP (Nil, (:*)))
import Prettyprinter (Doc, Pretty (pretty), brackets, nest, parens, vsep, (<+>))
import Sqel.Data.Mods (Mods)
import Sqel.Data.Sel (Sel (SelSymbol), SelW, TSel, TSelW, showSelW, showTSelW)
data ProductField =
ProductField {
name :: Symbol,
tpe :: Type
}
newtype ConCol (name :: Symbol) (record :: Bool) (fields :: [ProductField]) as =
ConCol { unConCol :: NP I as }
data ProdType = Reg | Con [Type]
data Comp = Prod ProdType | Sum
data CompInc = Merge | Nest
data Struct =
Prim
|
Comp {
typeName :: TSel,
compKind :: Comp,
compInc :: CompInc,
sub :: [DdK]
}
data DdK =
DdK {
columnName :: Sel,
mods :: [Type],
hsType :: Type,
struct :: Struct
}
type DdSort :: Comp -> Type
data DdSort c where
DdProd :: DdSort ('Prod 'Reg)
DdCon :: DdSort ('Prod ('Con as))
DdSum :: DdSort 'Sum
type MkDdSort :: Comp -> Constraint
class MkDdSort c where ddSort :: DdSort c
instance MkDdSort ('Prod 'Reg) where ddSort = DdProd
instance MkDdSort ('Prod ('Con as)) where ddSort = DdCon
instance MkDdSort 'Sum where ddSort = DdSum
type DdInc :: CompInc -> Type
data DdInc c where
DdMerge :: DdInc 'Merge
DdNest :: DdInc 'Nest
type MkDdInc :: CompInc -> Constraint
class MkDdInc c where ddInc :: DdInc c
instance MkDdInc 'Merge where ddInc = DdMerge
instance MkDdInc 'Nest where ddInc = DdNest
type DdStruct :: Struct -> Type
data DdStruct s where
DdPrim :: DdStruct 'Prim
DdComp :: TSelW sel -> DdSort c -> DdInc i -> NP Dd sub -> DdStruct ('Comp sel c i sub)
-- TODO maybe this could be a data family so that after using the dsl, the index is changed so that all Sels are present
-- also to stuff different metadata in there, like DdlColumn?
type Dd :: DdK -> Type
data Dd s where
Dd :: SelW sel -> Mods mods -> DdStruct s -> Dd ('DdK sel mods a s)
data QOp =
QAnd
|
QOr
deriving stock (Eq, Show, Generic)
type DdType :: DdK -> Type
type family DdType s where
DdType ('DdK _ _ a _) = a
type DdTypes :: [DdK] -> [Type]
type family DdTypes s where
DdTypes '[] = '[]
DdTypes (s : ss) = DdType s : DdTypes ss
type DdSel :: DdK -> Sel
type family DdSel s where
DdSel ('DdK sel _ _ _) = sel
type family DdName (s :: DdK) :: Symbol where
DdName ('DdK ('SelSymbol name) _ _ _) = name
DdName ('DdK _ _ a _) = TypeError ("This Dd for type " <> a <> " has no name")
type DdTypeSel :: DdK -> TSel
type family DdTypeSel s where
DdTypeSel ('DdK _ _ _ ('Comp sel _ _ _)) = sel
sel :: Dd s -> SelW (DdSel s)
sel (Dd s _ _) = s
typeSel :: Dd ('DdK sel p a ('Comp tsel c i sub)) -> TSelW tsel
typeSel (Dd _ _ (DdComp s _ _ _)) = s
showSel :: Dd s -> Text
showSel =
showSelW . sel
showTypeSel :: Dd ('DdK sel p a ('Comp tsel c i sub)) -> Text
showTypeSel =
showTSelW . typeSel
data a :> b = a :> b
infixr 3 :>
class PrettyNP s where
prettyNP :: NP Dd s -> [Doc ann]
instance PrettyNP '[] where
prettyNP Nil = mempty
instance (
Pretty (Dd s),
PrettyNP ss
) => PrettyNP (s : ss) where
prettyNP (dd :* dds) =
pretty dd : prettyNP dds
instance Pretty (DdStruct 'Prim) where
pretty DdPrim = "prim"
instance (
PrettyNP sub
) => Pretty (Dd ('DdK sel p a ('Comp tsel c i sub))) where
pretty (Dd s _ (DdComp ts c i sub)) =
nest 2 (vsep ((var <> brackets (pretty (showTSelW ts)) <+> pretty (showSelW s) <+> parens inc) : prettyNP sub))
where
var = case c of
DdProd -> "prod"
DdSum -> "sum"
DdCon -> "con"
inc = case i of
DdNest -> "nest"
DdMerge -> "merge"
instance (
Pretty (Mods p)
) => Pretty (Dd ('DdK sel p a 'Prim)) where
pretty (Dd s p DdPrim) =
"prim" <+> pretty (showSelW s) <+> pretty p
type Sqel' :: Sel -> [Type] -> Type -> Struct -> Type
type family Sqel' sel mods a s = r | r -> sel mods a s where
Sqel' sel mods a s = Dd ('DdK sel mods a s)
type Sqel :: Type -> (Sel, [Type], Struct) -> Type
type family Sqel a p = r | r -> p a where
Sqel a '(sel, mods, s) = Dd ('DdK sel mods a s)