content: {-# LANGUAGE DeriveFunctor, DeriveFoldable, DeriveTraversable #-}
  
  -- |
  -- Module      : Database.Relational.SqlSyntax.Types
  -- Copyright   : 2015-2019 Kei Hibino
  -- License     : BSD3
  --
  -- Maintainer  : ex8k.hibino@gmail.com
  -- Stability   : experimental
  -- Portability : unknown
  --
  -- This module defines sub-query structure used in query products.
  module Database.Relational.SqlSyntax.Types (
    -- * The SubQuery
    SubQuery (..),
  
    -- * Set operations
    Duplication (..), SetOp (..), BinOp (..),
  
    -- * Qualifiers for nested query
    Qualifier (..), Qualified (..), qualifier, unQualify, qualify,
  
    -- * Ordering types
    Order (..), Nulls (..), OrderColumn, OrderingTerm,
  
    -- * Aggregating types
    AggregateColumnRef,
    AggregateBitKey (..), AggregateSet (..), AggregateElem (..),
  
    AggregateKey (..),
  
    -- * Product tree type
    NodeAttr (..), ProductTree (..),
    Node (..), nodeAttr, nodeTree,
    JoinProduct,
  
    -- * Case
    CaseClause (..), WhenClauses(..),
  
    -- * Column and Tuple
    Column (..), Tuple, tupleWidth, Guard,
    )  where
  
  import Prelude hiding (and, product)
  import Data.Foldable (Foldable)
  import Data.Traversable (Traversable)
  
  import Database.Relational.Internal.Config (Config)
  import Database.Relational.Internal.String (StringSQL)
  import Database.Relational.Internal.UntypedTable (UTable)
  
  
  -- | Result record duplication attribute
  data Duplication = All | Distinct  deriving Show
  
  -- | Set operators
  data SetOp = Union | Except | Intersect  deriving Show
  
  -- | Set binary operators
  newtype BinOp = BinOp (SetOp, Duplication) deriving Show
  
  -- | Order direction. Ascendant or Descendant.
  data Order = Asc | Desc  deriving Show
  
  -- | Order of null.
  data Nulls =  NullsFirst | NullsLast deriving Show
  
  -- | Type for order-by column
  type OrderColumn = Column
  
  -- | Type for order-by term
  type OrderingTerm = ((Order, Maybe Nulls), OrderColumn)
  
  -- | Type for group-by term
  type AggregateColumnRef = Column
  
  -- | Type for group key.
  newtype AggregateBitKey = AggregateBitKey [AggregateColumnRef] deriving Show
  
  -- | Type for grouping set
  newtype AggregateSet = AggregateSet [AggregateElem] deriving Show
  
  -- | Type for group-by tree
  data AggregateElem = ColumnRef AggregateColumnRef
                     | Rollup [AggregateBitKey]
                     | Cube   [AggregateBitKey]
                     | GroupingSets [AggregateSet]
                     deriving Show
  
  -- | Typeful aggregate element.
  newtype AggregateKey a = AggregateKey (a, AggregateElem)
  
  -- | Sub-query type
  data SubQuery = Table UTable
                | Flat Config
                  Tuple Duplication JoinProduct [Guard]
                  [OrderingTerm]
                | Aggregated Config
                  Tuple Duplication JoinProduct [Guard]
                  [AggregateElem] [Guard] [OrderingTerm]
                | Bin BinOp SubQuery SubQuery
                deriving Show
  
  -- | Qualifier type.
  newtype Qualifier = Qualifier Int  deriving Show
  
  -- | Qualified query.
  data Qualified a =
    Qualified Qualifier a
    deriving (Show, Functor, Foldable, Traversable)
  
  -- | Get qualifier
  qualifier :: Qualified a -> Qualifier
  qualifier (Qualified q _) = q
  
  -- | Unqualify.
  unQualify :: Qualified a -> a
  unQualify (Qualified _ a) = a
  
  -- | Add qualifier
  qualify :: Qualifier -> a -> Qualified a
  qualify = Qualified
  
  
  -- | node attribute for product.
  data NodeAttr = Just' | Maybe deriving Show
  
  -- | Product tree type. Product tree is constructed by left node and right node.
  data ProductTree rs
    = Leaf (Bool, Qualified SubQuery)
    | Join !(Node rs) !(Node rs) !rs
    deriving (Show, Functor)
  
  -- | Product node. node attribute and product tree.
  data Node rs = Node !NodeAttr !(ProductTree rs)  deriving (Show, Functor)
  
  -- | Get node attribute.
  nodeAttr :: Node rs -> NodeAttr
  nodeAttr (Node a _) = a  where
  
  -- | Get tree from node.
  nodeTree :: Node rs -> ProductTree rs
  nodeTree (Node _ t) = t
  
  -- | Type for join product of query.
  type JoinProduct = Maybe (ProductTree [Guard])
  
  -- | when clauses
  data WhenClauses =
    WhenClauses [(Tuple, Tuple)] Tuple
    deriving Show
  
  -- | case clause
  data CaseClause
    = CaseSearch WhenClauses
    | CaseSimple Tuple WhenClauses
    deriving Show
  
  -- | Projected column structure unit with single column width
  data Column
    = RawColumn StringSQL            -- ^ used in immediate value or unsafe operations
    | SubQueryRef (Qualified Int)    -- ^ normalized sub-query reference T<n> with Int index
    | Scalar SubQuery                -- ^ scalar sub-query
    | Case CaseClause Int            -- ^ <n>th column of case clause
    deriving Show
  
  -- | Un-record-typed projected tuple. Forgot record type.
  type Tuple = [Column]
  
  type Guard = [Column]
  
  -- | Width of 'Tuple'.
  tupleWidth :: Tuple -> Int
  tupleWidth = length
  