{-# LANGUAGE GADTs #-}
# LANGUAGE ScopedTypeVariables #
# LANGUAGE TemplateHaskell #
# LANGUAGE TypeFamilies #

module Data.TableSpec where

import Control.Applicative
import Control.Lens
import Data.Table
import Test.Hspec


data Foo = Foo { _k :: String, _v :: String }
  deriving (Eq, Ord, Show, Read)

makeLenses ''Foo

instance Tabular Foo where
  type PKT Foo = String
  data Key k Foo a where
    FooK :: Key Primary Foo String
    FooV :: Key Supplemental Foo String
  data Tab Foo i = FooTab (i Primary String)
                          (i Supplemental String)

  fetch FooK = _k
  fetch FooV = _v

  primary = FooK
  primarily FooK r = r

  mkTab f               = FooTab <$> f FooK   <*> f FooV
  forTab (FooTab a b) f = FooTab <$> f FooK a <*> f FooV b
  ixTab (FooTab a _) FooK = a
  ixTab (FooTab _ b) FooV = b


tableA, tableB, tableC, tableD, tableE, tableF, tableG, tableH, tableI, tableJ,
 tableA', tableB', tableC', tableD', tableE', tableF', tableG', tableH', tableI', tableJ',
 tableB_at, tableD_at, tableJ_at :: Table Foo

tableA = fromList [Foo "a" "A", Foo "b" "hello"]
tableA' = fromList [Foo {_k = "a", _v = "A"}, Foo {_k = "b", _v = "hello"}]

tableB = insert (Foo "a" "Y") tableA
tableB_at = tableA & at "a" .~ Just (Foo "a" "Y")
tableB' = fromList [Foo {_k = "a", _v = "Y"}, Foo {_k = "b", _v = "hello"}]

tableC = tableB ^. with FooV (/=) ""
tableC' = fromList [Foo {_k = "a", _v = "Y"}, Foo {_k = "b", _v = "hello"}]

tableD = (tableA & ix "a" . v .~ "OH! NO!") ^. with FooV (/=) ""
tableD_at = (tableA & at "a" . _Just . v .~ "OH! NO!") ^. with FooV (/=) ""
tableD' = fromList [Foo {_k = "a", _v = "OH! NO!"}, Foo {_k = "b", _v = "hello"}]

tableE = tableC ^. with FooV (/=) ""
tableE' = fromList [Foo {_k = "a", _v = "Y"}, Foo {_k = "b", _v = "hello"}]

tableF = tableC ^. with _v (==) "A"
tableF' = fromList []

tableG = tableC ^. with _v (==) "Y"
tableG' = fromList [Foo {_k = "a", _v = "Y"}]

tableH = tableC ^. with FooV (==) "Y"
tableH' = fromList [Foo {_k = "a", _v = "Y"}]

tableI = tableC ^. with _v (==) "Y"
tableI' = fromList [Foo {_k = "a", _v = "Y"}]

tableJ = delete (Foo "a" "A") tableA
tableJ_at = tableA & at "a" .~ Nothing
tableJ' = fromList [Foo {_k = "b", _v = "hello"}]

tests :: IO ()
tests = hspec spec

spec :: Spec
spec = describe "Data.Table" . it "unit tests" $ do
  mapM_ (\ (i :: String, t, t') -> (i, t) `shouldBe` (i, t'))
    [ ("A", tableA, tableA')
    , ("B", tableB, tableB')
    , ("B at", tableB_at, tableB')
    , ("C", tableC, tableC')
    , ("E", tableE, tableE')
    , ("F", tableF, tableF')
    , ("G", tableG, tableG')
    , ("H", tableH, tableH')
    , ("I", tableI, tableI')
    , ("D", tableD, tableD')
    , ("D at", tableD_at, tableD')
    , ("J", tableJ, tableJ')
    , ("J at", tableJ_at, tableJ')
    ]

# LANGUAGE GADTs #
# LANGUAGE ScopedTypeVariables #
# LANGUAGE TemplateHaskell #
# LANGUAGE TypeFamilies #

module Data.TableSpec where

import Control.Applicative
import Control.Lens
import Data.Table
import Test.Hspec


data Foo = Foo { _k :: String, _v :: String }
  deriving (Eq, Ord, Show, Read)

makeLenses ''Foo

instance Tabular Foo where
  type PKT Foo = String
  data Key k Foo a where
    FooK :: Key Primary Foo String
    FooV :: Key Supplemental Foo String
  data Tab Foo i = FooTab (i Primary String)
                          (i Supplemental String)

  fetch FooK = _k
  fetch FooV = _v

  primary = FooK
  primarily FooK r = r

  mkTab f               = FooTab <$> f FooK   <*> f FooV
  forTab (FooTab a b) f = FooTab <$> f FooK a <*> f FooV b
  ixTab (FooTab a _) FooK = a
  ixTab (FooTab _ b) FooV = b


tableA, tableB, tableC, tableD, tableE, tableF, tableG, tableH, tableI, tableJ,
 tableA', tableB', tableC', tableD', tableE', tableF', tableG', tableH', tableI', tableJ',
 tableB_at, tableD_at, tableJ_at :: Table Foo

tableA = fromList [Foo "a" "A", Foo "b" "hello"]
tableA' = fromList [Foo {_k = "a", _v = "A"}, Foo {_k = "b", _v = "hello"}]

tableB = insert (Foo "a" "Y") tableA
tableB_at = tableA & at "a" .~ Just (Foo "a" "Y")
tableB' = fromList [Foo {_k = "a", _v = "Y"}, Foo {_k = "b", _v = "hello"}]

tableC = tableB ^. with FooV (/=) ""
tableC' = fromList [Foo {_k = "a", _v = "Y"}, Foo {_k = "b", _v = "hello"}]

tableD = (tableA & ix "a" . v .~ "OH! NO!") ^. with FooV (/=) ""
tableD_at = (tableA & at "a" . _Just . v .~ "OH! NO!") ^. with FooV (/=) ""
tableD' = fromList [Foo {_k = "a", _v = "OH! NO!"}, Foo {_k = "b", _v = "hello"}]

tableE = tableC ^. with FooV (/=) ""
tableE' = fromList [Foo {_k = "a", _v = "Y"}, Foo {_k = "b", _v = "hello"}]

tableF = tableC ^. with _v (==) "A"
tableF' = fromList []

tableG = tableC ^. with _v (==) "Y"
tableG' = fromList [Foo {_k = "a", _v = "Y"}]

tableH = tableC ^. with FooV (==) "Y"
tableH' = fromList [Foo {_k = "a", _v = "Y"}]

tableI = tableC ^. with _v (==) "Y"
tableI' = fromList [Foo {_k = "a", _v = "Y"}]

tableJ = delete (Foo "a" "A") tableA
tableJ_at = tableA & at "a" .~ Nothing
tableJ' = fromList [Foo {_k = "b", _v = "hello"}]

tests :: IO ()
tests = hspec spec

spec :: Spec
spec = describe "Data.Table" . it "unit tests" $ do
  mapM_ (\ (i :: String, t, t') -> (i, t) `shouldBe` (i, t'))
    [ ("A", tableA, tableA')
    , ("B", tableB, tableB')
    , ("B at", tableB_at, tableB')
    , ("C", tableC, tableC')
    , ("E", tableE, tableE')
    , ("F", tableF, tableF')
    , ("G", tableG, tableG')
    , ("H", tableH, tableH')
    , ("I", tableI, tableI')
    , ("D", tableD, tableD')
    , ("D at", tableD_at, tableD')
    , ("J", tableJ, tableJ')
    , ("J at", tableJ_at, tableJ')
    ]
