import Control.Concurrent (forkIO, threadDelay) import Control.Monad (liftM) import Control.Monad.Trans.Class (lift) import Data.Aeson (ToJSON, encode) import Data.CQRS import Data.CQRS.GUID (hexEncode) import Data.CQRS.EventStore.Backend.Sqlite3 import qualified Data.Map as M import qualified Data.Text as T import qualified Data.Text.Encoding as TE import Data.Time (fromGregorian) import Database.SQLite3 (Database) import Aggregates import Events import Instances () import Query import Happstack.Lite sqliteFile :: String sqliteFile = "example.db" eventSourcingThread :: Database -> EventStore Event -> IO () eventSourcingThread queryDb eventStore = do loop where loop = do putStrLn "Sourcing events..." updateQueryStateRef queryDb eventStore -- Wait 1 second threadDelay 1000000 -- Go again. loop -- Serve JSON ok response. okJson :: ToJSON a => a -> ServerPart Response okJson a = ok $ toResponseBS "text/json" $ encode a -- Serve JSON project list. projectsJson :: Database -> ServerPart Response projectsJson queryDb = do p <- liftM (map f) $ lift $ qProjectList queryDb okJson $ p where f (g,pn,psd) = M.fromList [ (T.pack "id" , TE.decodeUtf8 $ hexEncode g) , (T.pack "name" , pn) , (T.pack "short_desc", psd) ] -- Serve JSON task list. tasksJson :: Database -> ServerPart Response tasksJson queryDb = do p <- liftM (map f) $ lift $ qTaskList queryDb okJson $ p where f (g,tsd) = M.fromList [ (T.pack "id" , TE.decodeUtf8 $ hexEncode g) , (T.pack "short_description", tsd) ] -- Serve JSON data. jsonPart :: Database -> ServerPart Response jsonPart queryDb = msum [ dir "projects" $ projectsJson queryDb , dir "tasks" $ tasksJson queryDb , dir "time-sheet" $ okJson ([ ] :: [String]) ] -- Serve. myApp :: Database -> ServerPart Response myApp queryDb = msum [ dir "js" $ serveDirectory EnableBrowsing [ ] "static/js" , dir "css" $ serveDirectory EnableBrowsing [ ] "static/css" , dir "json" $ jsonPart queryDb , serveDirectory EnableBrowsing [ "index.html" ] "static" ] -- test1 :: IO () test1 = do let queryDbFile = "query.db" -- Start sourcing events. _ <- forkIO $ do queryDb <- initializeQueryDatabase queryDbFile withEventStore (openSqliteEventStore sqliteFile) $ eventSourcingThread queryDb -- Web serving thread. _ <- forkIO $ do queryDb <- initializeQueryDatabase queryDbFile serve Nothing $ myApp queryDb -- Do a few things withEventStore (openSqliteEventStore sqliteFile) $ \eventStore -> do runTransactionT eventStore $ do -- Create new project. projectId <- lift $ newGUID (projectRef, _ :: Project) <- getAggregateRoot projectId publishEvent projectRef $ ProjectCreated "my project" "short desc of my project" -- Add a couple of tasks taskId1 <- lift $ newGUID (taskRef1, _ :: Task) <- getAggregateRoot taskId1 publishEvent taskRef1 $ TaskAdded projectId "tweak knob" taskId2 <- lift $ newGUID (taskRef2, _ :: Task) <- getAggregateRoot taskId2 publishEvent taskRef2 $ TaskAdded projectId "pull lever" -- Rename project. publishEvent projectRef $ ProjectRenamed "old project" -- Create user. userId1 <- lift $ newGUID (userRef1, _ :: User) <- getAggregateRoot userId1 publishEvent userRef1 $ UserCreated "bardur" "Bardur" "Arantsson" -- Record time for task #2. workUnitId1 <- lift $ newGUID publishEvent taskRef2 $ RecordedWorkUnit workUnitId1 (fromGregorian 2011 12 01) 3 "found the lever to pull" userId1 main :: IO () main = do putStrLn "Running test1..." test1 putStrLn "Press to quit" _ <- getLine return ()