-- |
-- Module      : Database.Relational.Table
-- Copyright   : 2013-2019 Kei Hibino
-- License     : BSD3
--
-- Maintainer  : ex8k.hibino@gmail.com
-- Stability   : experimental
-- Portability : unknown
--
-- This module defines table type which has table metadatas.
module Database.Relational.Table (
  -- * Phantom typed table type
  Table, untype, name, shortName, width, columns, index, table, toMaybe, recordWidth,

  toSubQuery,

  -- * Table existence inference
  TableDerivable (..)
  ) where

import Data.Array (listArray)

import Database.Record.Persistable
  (PersistableWidth, PersistableRecordWidth, unsafePersistableRecordWidth)

import Database.Relational.Internal.UntypedTable (Untyped (Untyped), name', width', columns', (!))
import Database.Relational.Internal.String (StringSQL, stringSQL, showStringSQL)
import Database.Relational.SqlSyntax (SubQuery)
import qualified Database.Relational.SqlSyntax as Syntax


-- | Phantom typed table type
newtype Table r = Table Untyped

instance Show (Table r) where
  show :: Table r -> String
show Table r
t =
    [String] -> String
unwords
    [String
"Table",  forall a. Show a => a -> String
show forall a b. (a -> b) -> a -> b
$ forall r. Table r -> String
name Table r
t,
     forall a. Show a => a -> String
show forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a -> b) -> [a] -> [b]
map StringSQL -> String
showStringSQL forall a b. (a -> b) -> a -> b
$ forall r. Table r -> [StringSQL]
columns Table r
t]

-- | Untype table.
untype :: Table t -> Untyped
untype :: forall t. Table t -> Untyped
untype (Table Untyped
u) = Untyped
u

-- | Name string of table in SQL
name :: Table r -> String
name :: forall r. Table r -> String
name   = Untyped -> String
name' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Table t -> Untyped
untype

-- | Not qualified name string of table in SQL
shortName :: Table r -> String
shortName :: forall r. Table r -> String
shortName =  forall a. [a] -> [a]
tail forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> [a]
dropWhile (forall a. Eq a => a -> a -> Bool
/= Char
'.') forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r. Table r -> String
name

-- | Width of table
width :: Table r -> Int
width :: forall r. Table r -> Int
width  = Untyped -> Int
width' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Table t -> Untyped
untype

-- | Column name strings in SQL
columns :: Table r -> [StringSQL]
columns :: forall r. Table r -> [StringSQL]
columns =  Untyped -> [StringSQL]
columns' forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Table t -> Untyped
untype

-- | Column name string in SQL specified by index
index :: Table r
      -> Int       -- ^ Column index
      -> StringSQL -- ^ Column name String in SQL
index :: forall r. Table r -> Int -> StringSQL
index =  Untyped -> Int -> StringSQL
(!) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Table t -> Untyped
untype

-- | Cast phantom type into 'Maybe' type.
toMaybe :: Table r -> Table (Maybe r)
toMaybe :: forall r. Table r -> Table (Maybe r)
toMaybe (Table Untyped
t) = forall r. Untyped -> Table r
Table Untyped
t

-- | Unsafely generate phantom typed table type.
table :: String -> [String] -> Table r
table :: forall r. String -> [String] -> Table r
table String
n [String]
f = forall r. Untyped -> Table r
Table forall a b. (a -> b) -> a -> b
$ String -> Int -> Array Int StringSQL -> Untyped
Untyped String
n Int
w Array Int StringSQL
fa  where
  w :: Int
w  = forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
f
  fa :: Array Int StringSQL
fa = forall i e. Ix i => (i, i) -> [e] -> Array i e
listArray (Int
0, Int
w forall a. Num a => a -> a -> a
- Int
1) forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map String -> StringSQL
stringSQL [String]
f

-- | 'SubQuery' from 'Table'.
toSubQuery :: Table r  -- ^ Typed 'Table' metadata
           -> SubQuery -- ^ Result 'SubQuery'
toSubQuery :: forall r. Table r -> SubQuery
toSubQuery = Untyped -> SubQuery
Syntax.Table forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall t. Table t -> Untyped
untype

-- | Inference rule of 'Table' existence.
class PersistableWidth r => TableDerivable r where
  derivedTable :: Table r

-- | PersistableRecordWidth of table
recordWidth :: Table r -> PersistableRecordWidth r
recordWidth :: forall r. Table r -> PersistableRecordWidth r
recordWidth = forall a. Int -> PersistableRecordWidth a
unsafePersistableRecordWidth forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r. Table r -> Int
width