packages feed

eventful-postgresql-0.2.0: tests/Eventful/Store/PostgresqlSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Eventful.Store.PostgresqlSpec (spec) where

import Control.Monad.Reader (ask)
import Data.Monoid ((<>))
import Data.Text (Text, intercalate)
import Database.Persist.Postgresql
import Test.Hspec

import Eventful.Store.Postgresql
import Eventful.TestHelpers

spec :: Spec
spec = do
  describe "Postgres event store" $ do
    eventStoreSpec postgresStoreRunner
    globalStreamEventStoreSpec postgresStoreGlobalRunner

makeStore :: (MonadIO m) => m (EventStoreWriter (SqlPersistT m) CounterEvent, VersionedEventStoreReader (SqlPersistT m) CounterEvent, ConnectionPool)
makeStore = do
  -- TODO: Obviously this is hard-coded, make this use environment variables or
  -- something in the future.
  let
    connString = "host=localhost port=5432 user=postgres dbname=eventful_test password=password"
    writer = serializedEventStoreWriter jsonStringSerializer $ postgresqlEventStoreWriter defaultSqlEventStoreConfig
    reader = serializedVersionedEventStoreReader jsonStringSerializer $ sqlEventStoreReader defaultSqlEventStoreConfig
  pool <- liftIO $ runNoLoggingT (createPostgresqlPool connString 1)
  initializePostgresqlEventStore pool
  liftIO $ runSqlPool truncateTables pool
  return (writer, reader, pool)

getTables :: MonadIO m => SqlPersistT m [Text]
getTables = do
    tables <-
      rawSql
      "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE';"
      []
    return $ map unSingle tables

truncateTables :: MonadIO m => SqlPersistT m ()
truncateTables = do
    tables <- getTables
    sqlBackend <- ask
    let
      escapedTables = map (connEscapeName sqlBackend . DBName) tables
      query = "TRUNCATE TABLE " <> intercalate ", " escapedTables <> " RESTART IDENTITY CASCADE"
    rawExecute query []

postgresStoreRunner :: EventStoreRunner (SqlPersistT IO)
postgresStoreRunner = EventStoreRunner $ \action -> do
  (writer, reader, pool) <- makeStore
  runSqlPool (action writer reader) pool

postgresStoreGlobalRunner :: GlobalStreamEventStoreRunner (SqlPersistT IO)
postgresStoreGlobalRunner = GlobalStreamEventStoreRunner $ \action -> do
  (writer, _, pool) <- makeStore
  let
    globalReader = serializedGlobalEventStoreReader jsonStringSerializer (sqlGlobalEventStoreReader defaultSqlEventStoreConfig)
  runSqlPool (action writer globalReader) pool