module Jerimum.Tests.Integration.PostgreSQL.UpdateTests where

import           Control.Monad
import qualified Data.Map                           as M
import           Data.Monoid
import qualified Database.PostgreSQL.Simple         as PQ
import           Jerimum.PostgreSQL
import           Jerimum.PostgreSQL.Types
import           Jerimum.PostgreSQL.Types.Numeric
import           Jerimum.PostgreSQL.Types.Text
import           Jerimum.Tests.Integration.Helper
import           Jerimum.Tests.Integration.Resource
import           Test.Tasty
import           Test.Tasty.HUnit

beforeAllTests :: PQ.Connection -> IO ()
beforeAllTests conn =
  void $
  PQ.execute_
    conn
    "create table if not exists update_tests (id integer primary key, name text default null)"

afterAllTests :: PQ.Connection -> IO ()
afterAllTests conn = void $ PQ.execute_ conn "drop table if exists update_tests"

updateChangePkTest :: IO Handle -> IO PQ.Connection -> TestTree
updateChangePkTest getHandle getDBConn =
  testCase "update changing pk" $ do
    dbconn <- getDBConn
    handle <- getHandle
    Just _ <-
      executeAndRead
        handle
        dbconn
        "insert into update_tests values (0, DEFAULT)"
    executeAndTest
      handle
      dbconn
      "update update_tests set name = 'foobar', id = 1 where id = 0"
      [ Update
          "public"
          "update_tests"
          (Just $ M.singleton "id" (fromInt32 $ Just 0))
          (M.fromList
             [("id", fromInt32 $ Just 1), ("name", fromText $ Just "foobar")])
      ]

updateSamePkTest :: IO Handle -> IO PQ.Connection -> TestTree
updateSamePkTest getHandle getDBConn =
  testCase "update same pk" $ do
    dbconn <- getDBConn
    handle <- getHandle
    Just _ <-
      executeAndRead
        handle
        dbconn
        "insert into update_tests values (0, DEFAULT)"
    executeAndTest
      handle
      dbconn
      "update update_tests set name = 'foobar' where id = 0"
      [ Update
          "public"
          "update_tests"
          (Just $ M.singleton "id" (fromInt32 $ Just 0))
          (M.fromList
             [("id", fromInt32 $ Just 0), ("name", fromText $ Just "foobar")])
      ]

upsertTest :: IO Handle -> IO PQ.Connection -> TestTree
upsertTest getHandle getDBConn =
  testCase "upsert" $ do
    handle <- getHandle
    dbconn <- getDBConn
    Just _ <-
      executeAndRead
        handle
        dbconn
        "insert into update_tests values (0, DEFAULT)"
    executeAndTest
      handle
      dbconn
      ("INSERT INTO update_tests (id, name) VALUES (0, DEFAULT) " <>
       "ON CONFLICT (id) DO UPDATE SET name = 'foobar'")
      [ Update
          "public"
          "update_tests"
          (Just $ M.singleton "id" (fromInt32 $ Just 0))
          (M.fromList
             [("id", fromInt32 $ Just 0), ("name", fromText $ Just "foobar")])
      ]

tests :: TestTree
tests =
  testGroup
    "UPDATE"
    [ buildTest
        (ReplIntegrationTest beforeAllTests afterAllTests updateSamePkTest)
    , buildTest (ReplIntegrationTest beforeAllTests afterAllTests upsertTest)
    , buildTest
        (ReplIntegrationTest beforeAllTests afterAllTests updateChangePkTest)
    ]
