packages feed

hasklepias-0.12.0: src/Hasklepias/MakeApp.hs

{-# LANGUAGE BlockArguments #-}
{-|
Module      : Hasklepias.MakeApp
Description : Functions for creating a cohort application
Copyright   : (c) NoviSci, Inc 2020
License     : BSD3
Maintainer  : bsaul@novisci.com
-}
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Hasklepias.MakeApp (
   makeCohortApp
) where

import Control.Monad                        ( Monad(return), Functor(fmap) )
import Control.Applicative                  ( Applicative )
import Data.Aeson                           ( encode, FromJSON, ToJSON(..) )
import Data.Bifunctor                       ( Bifunctor(second) )
import qualified Data.ByteString.Lazy as B
import Data.ByteString.Lazy.Char8 as C      ( putStrLn )
import Data.Function                        ( ($), (.) )
import Data.List                            ( (++) )
import Data.Monoid                          ( Monoid(mconcat) )
import Data.String                          ( String )
import Data.Text                            ( pack, Text )
import Data.Tuple                           ( fst, snd )
import GHC.Show                             ( Show(show) )
import GHC.IO                               ( IO )

import EventData                            ( Events )
import Hasklepias.Aeson                     ( parsePopulationLines, ParseError )
import Hasklepias.Cohort                    ( evalCohort, Cohort, CohortSpec )
import IntervalAlgebra                      ( IntervalSizeable )

import Control.Monad.IO.Class               (MonadIO, liftIO)
import Control.Monad.Reader                 (MonadReader (..), ReaderT (..))
import Colog                                ( Message
                                            , HasLog(..)
                                            , WithLog
                                            , LogAction(..)
                                            , richMessageAction
                                            , logInfo
                                            , logError
                                            , logStringStdout
                                            , logStringStderr
                                            , logText
                                            , withLog
                                            , logPrint
                                            , logPrintStderr 
                                            , (<&)
                                            , (>$)
                                            , log )
import System.Console.CmdArgs               ( Data, Typeable
                                            , cmdArgs, summary, help, (&=) )
import System.Environment                   (getArgs)

-- a stub to add more arguments to later
data MakeCohort = MakeCohort deriving (Show, Data, Typeable)

makeAppArgs ::
     String  -- ^ name of the application
  -> String  -- ^ version of the application 
  -> MakeCohort
makeAppArgs name version = MakeCohort
    {
    } &= help "Pass event data via stdin."
      &= summary (name ++ " " ++ version)

makeCohortBuilder :: (FromJSON a, Show a, IntervalSizeable a b, ToJSON d0, Monad m) =>
     [CohortSpec (Events a) d0]
  -> m (B.ByteString -> m ([ParseError], [Cohort d0]))
makeCohortBuilder specs =
  return (return . second (\pop -> fmap (`evalCohort` pop) specs) . parsePopulationLines)

-- logging based on example here:
-- https://github.com/kowainik/co-log/blob/main/co-log/tutorials/Main.hs
parseErrorL :: LogAction IO ParseError
parseErrorL = logPrintStderr

logParseErrors :: [ParseError] -> IO ()
logParseErrors x = mconcat $ fmap (parseErrorL <&) x

-- | Make a command line cohort building application.
makeCohortApp :: (FromJSON a, Show a, IntervalSizeable a b, ToJSON d0) =>
       String  -- ^ cohort name
    -> String  -- ^ app version
    -> [CohortSpec (Events a) d0]  -- ^ a list of cohort specifications
    -> IO ()
makeCohortApp name version spec =
    do
      args <- cmdArgs ( makeAppArgs name version )
      let logger = logStringStdout

      logger <& "Creating cohort builder..."
      app <- makeCohortBuilder spec

      logger <& "Reading data from stdin..."
      dat  <- B.getContents

      logger <& "Bulding cohort..."
      res <- app dat

      logParseErrors (fst res)

      logger <& "Encoding cohort(s) output and writing to stdout..."
      C.putStrLn (encode ( toJSON (snd res) ))

      logger <& "Cohort build complete!"