packages feed

persistent-audit-0.1.0.2: tests/Database/Persist/Audit/QueriesSpec.hs

{-# LANGUAGE BangPatterns               #-}
{-# LANGUAGE EmptyDataDecls             #-}
{-# LANGUAGE FlexibleContexts           #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE OverloadedStrings          #-}
{-# LANGUAGE QuasiQuotes                #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE TypeFamilies               #-}

module Database.Persist.Audit.QueriesSpec (main, spec) where

import           Control.Monad.IO.Class

import           Data.Text                              (Text)
import           Data.Time

import           Database.Persist                hiding (Update)
import           Database.Persist.Sqlite         hiding (Update)
import           Database.Persist.TH

import           Database.Persist.Audit.Class
import           Database.Persist.Audit.Queries
import           Database.Persist.Audit.Types

import           Test.Hspec

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show

BlogPost
    title String
    authorId PersonId
    deriving Show

PersonAudit
    name String
    age Int Maybe
    deriving Show
    originalId PersonId noreference
    auditAction AuditAction
    editedBy Text
    editedOn UTCTime

BlogPostAudit
    title String
    authorId PersonId noreference
    deriving Show
    originalId BlogPostId noreference
    auditAction AuditAction
    editedBy Text
    editedOn UTCTime
|]


instance ToAudit Person where
  type AuditResult Person = PersonAudit
  toAudit v k auditAction editedBy editedOn = PersonAudit (personName v)
                                                          (personAge v)
                                                          k auditAction editedBy editedOn

instance ToAudit BlogPost where
  type AuditResult BlogPost = BlogPostAudit
  toAudit v k auditAction editedBy editedOn = BlogPostAudit (blogPostTitle v)
                                                            (blogPostAuthorId v)
                                                            k auditAction editedBy editedOn

spec :: Spec
spec = do
  describe "Audit Queries" $ do
    it "insertAndAudit should insert the original item and insert an audit version" $ do
      mPair <- liftIO $ runSqlite ":memory:" $ do
        runMigration migrateAll
        johnId <- insertAndAudit (Person "John Doe" $ Just 35) "Admin"

        mPerson <- selectFirst [PersonId ==. johnId] []
        mPersonAudit <- selectFirst [PersonAuditOriginalId ==. johnId, PersonAuditAuditAction ==. Create] []

        return $ (,) <$> mPerson <*> mPersonAudit

      case mPair of
        Nothing -> False `shouldBe` True
        Just (person,personAudit) ->
          ((personName . entityVal $ person) == (personAuditName . entityVal $ personAudit)) `shouldBe` True

    it "deleteAndAudit should delete the original item and an insert audit version" $ do
      pair <- liftIO $ runSqlite ":memory:" $ do
        runMigration migrateAll
        johnId <- insertAndAudit (Person "John Doe" $ Just 35) "Admin"
        deleteAndAudit johnId "Admin"

        mPerson <- selectFirst [PersonId ==. johnId] []
        mPersonAudit <- selectList [PersonAuditOriginalId ==. johnId, PersonAuditAuditAction ==. Delete] []

        return $ (,) mPerson mPersonAudit

      case fst pair of
        Just _ -> False `shouldBe` True
        Nothing -> (length $ snd pair) == 1 `shouldBe` True

    it "updateAndAudit should update the original item and insert an audit version" $ do
      mPersonAudit <- liftIO $ runSqlite ":memory:" $ do
        runMigration migrateAll
        johnId <- insertAndAudit (Person "John Doe" $ Just 35) "Admin"

        updateAndAudit johnId [PersonAge =. (Just 30)] "Admin"
        mPersonAudit <- selectFirst [PersonAuditOriginalId ==. johnId, PersonAuditAuditAction ==. Update] []

        return mPersonAudit

      case mPersonAudit of
        Nothing -> False `shouldBe` True
        Just _ -> True `shouldBe` True

main :: IO ()
main = hspec spec