nlql / picard / src / Language / SQL / SpiderSQL / Syntax.hs
Syntax.hs
Raw
{-# LANGUAGE EmptyDataDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE StandaloneKindSignatures #-}
{-# LANGUAGE TypeFamilies #-}

module Language.SQL.SpiderSQL.Syntax where

import Data.Hashable (Hashable)
import Data.Kind (Type)
import GHC.Generics (Generic)

data SpiderTyp
  = TBoolean
  | TNumber
  | TText
  | TOthers
  | TTime
  | TStar
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Hashable)

data X = UD | TC

data SX :: X -> Type where
  SUD :: SX 'UD
  STC :: SX 'TC

type XSpiderSQL :: X -> Type
type family XSpiderSQL x where
  XSpiderSQL 'UD = ()
  XSpiderSQL 'TC = [SpiderTyp]

type SpiderSQL :: X -> Type
data SpiderSQL x = SpiderSQL
  { spiderSQLX :: XSpiderSQL x,
    spiderSQLSelect :: Select x,
    spiderSQLFrom :: From x,
    spiderSQLWhere :: Maybe (Cond x),
    spiderSQLGroupBy :: [ColUnit x],
    spiderSQLOrderBy :: Maybe (OrderBy x),
    spiderSQLHaving :: Maybe (Cond x),
    spiderSQLLimit :: Maybe Int,
    spiderSQLIntersect :: Maybe (SpiderSQL x),
    spiderSQLExcept :: Maybe (SpiderSQL x),
    spiderSQLUnion :: Maybe (SpiderSQL x)
  }
  deriving stock (Generic)

type SpiderSQLUD = SpiderSQL 'UD

pattern SpiderSQLUD ::
  SelectUD ->
  FromUD ->
  Maybe CondUD ->
  [ColUnitUD] ->
  Maybe OrderByUD ->
  Maybe CondUD ->
  Maybe Int ->
  Maybe SpiderSQLUD ->
  Maybe SpiderSQLUD ->
  Maybe SpiderSQLUD ->
  SpiderSQLUD
pattern SpiderSQLUD sqlSelect sqlFrom sqlWhere sqlGroupBy sqlOrderBy sqlHaving sqlLimit sqlIntersect sqlExcept sqlUnion <-
  SpiderSQL _ sqlSelect sqlFrom sqlWhere sqlGroupBy sqlOrderBy sqlHaving sqlLimit sqlIntersect sqlExcept sqlUnion
  where
    SpiderSQLUD sqlSelect sqlFrom sqlWhere sqlGroupBy sqlOrderBy sqlHaving sqlLimit sqlIntersect sqlExcept sqlUnion =
      SpiderSQL () sqlSelect sqlFrom sqlWhere sqlGroupBy sqlOrderBy sqlHaving sqlLimit sqlIntersect sqlExcept sqlUnion

deriving stock instance Eq SpiderSQLUD

deriving stock instance Show SpiderSQLUD

deriving anyclass instance Hashable SpiderSQLUD

spiderSQLTyp :: SpiderSQL x -> XSpiderSQL x
spiderSQLTyp SpiderSQL {..} = spiderSQLX

type SpiderSQLTC = SpiderSQL 'TC

deriving stock instance Eq SpiderSQLTC

deriving stock instance Show SpiderSQLTC

deriving anyclass instance Hashable SpiderSQLTC

type family XSelect x where
  XSelect 'UD = ()
  XSelect 'TC = [SpiderTyp]

data Select x
  = Select (XSelect x) [Agg x]
  | SelectDistinct (XSelect x) [Agg x]
  deriving stock (Generic)

pattern SelectUD :: [AggUD] -> SelectUD
pattern SelectUD aggs <-
  Select _ aggs
  where
    SelectUD aggs = Select () aggs

pattern SelectDistinctUD :: [AggUD] -> SelectUD
pattern SelectDistinctUD aggs <-
  SelectDistinct _ aggs
  where
    SelectDistinctUD aggs = SelectDistinct () aggs

type SelectUD = Select 'UD

deriving stock instance Eq SelectUD

deriving stock instance Show SelectUD

deriving anyclass instance Hashable SelectUD

selectTyp :: Select x -> XSelect x
selectTyp (Select typ _) = typ
selectTyp (SelectDistinct typ _) = typ

type SelectTC = Select 'TC

deriving stock instance Eq SelectTC

deriving stock instance Show SelectTC

deriving anyclass instance Hashable SelectTC

data From x = From
  { fromTableUnits :: [TableUnit x],
    fromCond :: Maybe (Cond x)
  }
  deriving stock (Generic)

type FromUD = From 'UD

deriving stock instance Eq FromUD

deriving stock instance Show FromUD

deriving anyclass instance Hashable FromUD

type FromTC = From 'TC

deriving stock instance Eq FromTC

deriving stock instance Show FromTC

deriving anyclass instance Hashable FromTC

type Cond :: X -> Type
data Cond x
  = And (Cond x) (Cond x)
  | Or (Cond x) (Cond x)
  | Not (Cond x)
  | Between (ValUnit x) (ValUnit x) (ValUnit x)
  | Eq (ValUnit x) (ValUnit x)
  | Gt (ValUnit x) (ValUnit x)
  | Lt (ValUnit x) (ValUnit x)
  | Ge (ValUnit x) (ValUnit x)
  | Le (ValUnit x) (ValUnit x)
  | Ne (ValUnit x) (ValUnit x)
  | In (ValUnit x) (ValUnit x)
  | Like (ValUnit x) (ValUnit x)
  deriving stock (Generic)

type CondUD = Cond 'UD

deriving stock instance Eq CondUD

deriving stock instance Show CondUD

deriving anyclass instance Hashable CondUD

type CondTC = Cond 'TC

deriving stock instance Eq CondTC

deriving stock instance Show CondTC

deriving anyclass instance Hashable CondTC

type family XValUnit x where
  XValUnit 'UD = ()
  XValUnit 'TC = SpiderTyp

type ValUnit :: X -> Type
data ValUnit x
  = Column (XValUnit x) (Val x)
  | Minus (XValUnit x) (Val x) (Val x)
  | Plus (XValUnit x) (Val x) (Val x)
  | Times (XValUnit x) (Val x) (Val x)
  | Divide (XValUnit x) (Val x) (Val x)
  deriving stock (Generic)

valUnitTyp :: forall x. ValUnit x -> XValUnit x
valUnitTyp (Column typ _) = typ
valUnitTyp (Minus typ _ _) = typ
valUnitTyp (Plus typ _ _) = typ
valUnitTyp (Times typ _ _) = typ
valUnitTyp (Divide typ _ _) = typ

pattern ColumnUD :: ValUD -> ValUnitUD
pattern ColumnUD val <-
  Column _ val
  where
    ColumnUD val = Column () val

type ValUnitUD = ValUnit 'UD

deriving stock instance Eq ValUnitUD

deriving stock instance Show ValUnitUD

deriving anyclass instance Hashable ValUnitUD

type ValUnitTC = ValUnit 'TC

deriving stock instance Eq ValUnitTC

deriving stock instance Show ValUnitTC

deriving anyclass instance Hashable ValUnitTC

type XValColUnit :: X -> Type

type XValColUnit x = XColUnit x

type XValSQL :: X -> Type

type XValSQL x = XSpiderSQL x

type Val :: X -> Type
data Val x
  = ValColUnit {columnX :: XValColUnit x, columnValue :: ColUnit x}
  | Number {numberValue :: Double}
  | ValString {stringValue :: String}
  | ValSQL {sqlValueX :: XValSQL x, sqlValue :: SpiderSQL x}
  deriving stock (Generic)

type ValUD = Val 'UD

deriving stock instance Eq ValUD

deriving stock instance Show ValUD

deriving anyclass instance Hashable ValUD

type ValTC = Val 'TC

deriving stock instance Eq ValTC

deriving stock instance Show ValTC

deriving anyclass instance Hashable ValTC

type XColUnit :: X -> Type
type family XColUnit x where
  XColUnit 'UD = ()
  XColUnit 'TC = SpiderTyp

data ColUnit x
  = ColUnit
      { colUnitX :: XColUnit x,
        colUnitAggId :: Maybe AggType,
        colUnitTable :: Maybe (Either TableId Alias),
        colUnitColId :: ColumnId x
      }
  | DistinctColUnit
      { distinctColUnitX :: XColUnit x,
        distinctColUnitAggId :: Maybe AggType,
        distinctColUnitTable :: Maybe (Either TableId Alias),
        distinctColUnitColdId :: ColumnId x
      }
  deriving stock (Generic)

pattern ColUnitUD :: Maybe AggType -> Maybe (Either TableId Alias) -> ColumnIdUD -> ColUnitUD
pattern ColUnitUD at tidOrAlias cid <-
  ColUnit _ at tidOrAlias cid
  where
    ColUnitUD at tidOrAlias cid = ColUnit () at tidOrAlias cid

pattern DistinctColUnitUD :: Maybe AggType -> Maybe (Either TableId Alias) -> ColumnIdUD -> ColUnitUD
pattern DistinctColUnitUD at tidOrAlias cid <-
  DistinctColUnit _ at tidOrAlias cid
  where
    DistinctColUnitUD at tidOrAlias cid = DistinctColUnit () at tidOrAlias cid

type ColUnitUD = ColUnit 'UD

deriving stock instance Eq ColUnitUD

deriving stock instance Show ColUnitUD

deriving anyclass instance Hashable ColUnitUD

colUnitTyp :: forall x. ColUnit x -> XColUnit x
colUnitTyp ColUnit {..} = colUnitX
colUnitTyp DistinctColUnit {..} = distinctColUnitX

type ColUnitTC = ColUnit 'TC

deriving stock instance Eq ColUnitTC

deriving stock instance Show ColUnitTC

deriving anyclass instance Hashable ColUnitTC

type OrderBy :: X -> Type
newtype OrderBy x = OrderBy [(ValUnit x, OrderByOrder)]
  deriving stock (Generic)

type OrderByUD = OrderBy 'UD

deriving stock instance Eq OrderByUD

deriving stock instance Show OrderByUD

deriving anyclass instance Hashable OrderByUD

type OrderByTC = OrderBy 'TC

deriving stock instance Eq OrderByTC

deriving stock instance Show OrderByTC

deriving anyclass instance Hashable OrderByTC

data OrderByOrder = Asc | Desc
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Hashable)

type XAgg :: X -> Type
type family XAgg x where
  XAgg 'UD = ()
  XAgg 'TC = SpiderTyp

type Agg :: X -> Type
data Agg x = Agg (XAgg x) (Maybe AggType) (ValUnit x)
  deriving stock (Generic)

pattern AggUD :: Maybe AggType -> ValUnitUD -> AggUD
pattern AggUD aggType vu <-
  Agg _ aggType vu
  where
    AggUD aggType vu = Agg () aggType vu

type AggUD = Agg 'UD

deriving stock instance Eq AggUD

deriving stock instance Show AggUD

deriving anyclass instance Hashable AggUD

type AggTC = Agg 'TC

deriving stock instance Eq AggTC

deriving stock instance Show AggTC

deriving anyclass instance Hashable AggTC

type TableUnit :: X -> Type
data TableUnit x
  = TableUnitSQL (SpiderSQL x) (Maybe Alias)
  | Table TableId (Maybe Alias)
  deriving stock (Generic)

type TableUnitUD = TableUnit 'UD

deriving stock instance Eq TableUnitUD

deriving stock instance Show TableUnitUD

deriving anyclass instance Hashable TableUnitUD

type TableUnitTC = TableUnit 'TC

deriving stock instance Eq TableUnitTC

deriving stock instance Show TableUnitTC

deriving anyclass instance Hashable TableUnitTC

data AggType = Max | Min | Count | Sum | Avg
  deriving stock (Eq, Show, Generic)
  deriving anyclass (Hashable)

type XColumnID :: X -> Type
type family XColumnID x where
  XColumnID 'UD = ()
  XColumnID 'TC = SpiderTyp

data ColumnId x
  = Star
  | ColumnId {columnIdX :: XColumnID x, columnName :: String}
  deriving stock (Generic)

pattern ColumnIdUD :: String -> ColumnIdUD
pattern ColumnIdUD colName <-
  ColumnId _ colName
  where
    ColumnIdUD colName = ColumnId () colName

type ColumnIdUD = ColumnId 'UD

deriving stock instance Eq ColumnIdUD

deriving stock instance Show ColumnIdUD

deriving anyclass instance Hashable ColumnIdUD

type ColumnIdTC = ColumnId 'TC

deriving stock instance Eq ColumnIdTC

deriving stock instance Show ColumnIdTC

deriving anyclass instance Hashable ColumnIdTC

newtype TableId = TableId {tableName :: String}
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (Hashable)

newtype Alias = Alias {aliasName :: String}
  deriving stock (Eq, Ord, Show, Generic)
  deriving anyclass (Hashable)