packages feed

hasklepias-0.17.0: src/Cohort/Output.hs

{-|
Module      : Hasklepias Cohorts
Description : Defines the options for outputting a cohort
Copyright   : (c) NoviSci, Inc 2020
License     : BSD3
Maintainer  : bsaul@novisci.com
-}
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveAnyClass #-}

module Cohort.Output(
    CohortShape
  , ShapeCohort(..)
  , toJSONCohortShape
) where

import Data.Aeson                           ( ToJSON(..)
                                            , Value
                                            , object
                                            , (.=) )
import Data.Function                        ( (.) )
import Data.Functor                         ( Functor(fmap) )
import Data.List.NonEmpty as NE             ( NonEmpty(..)
                                            , head
                                            , fromList
                                            , zip )
import Data.Tuple                           ( uncurry )
import GHC.Generics                         ( Generic )
import GHC.Types                            ( Type )
import GHC.Show                             ( Show )
import Cohort.Core                          ( AttritionInfo,
                                              Cohort,
                                              ObsUnit,
                                              ID,
                                              CohortData,
                                              getCohortData,
                                              getCohortIDs )
import Cohort.Criteria                      ( CohortStatus )
import Features.Featureset                  ( FeaturesetList(MkFeaturesetList)
                                            , Featureset
                                            , getFeatureset
                                            , getFeaturesetList
                                            , tpose )
import Features.Output                      ( ShapeOutput(dataOnly, nameAttr)
                                            , OutputShape )

instance (ToJSON d) => ToJSON (ObsUnit d) where
instance (ToJSON d) => ToJSON (CohortData d) where
instance (ToJSON d) => ToJSON (Cohort d) where
instance ToJSON CohortStatus where
instance ToJSON AttritionInfo where

-- | A type used to determine the output shape of a Cohort.
data CohortShape d where
  ColumnWise :: (Show a, ToJSON a) => a -> CohortShape ColumnWise
  RowWise :: (Show a, ToJSON a) => a -> CohortShape RowWise

deriving instance Show d => Show (CohortShape d)

-- | Maps CohortShape into an Aeson Value. 
-- TODO: implement Generic and ToJSON instance of CohortShape directly.
toJSONCohortShape :: CohortShape shape -> Value
toJSONCohortShape (ColumnWise x) = toJSON x
toJSONCohortShape (RowWise x)    = toJSON x

-- | Provides methods for reshaping a 'Cohort.Cohort' to a 'CohortShape'.
class ShapeCohort d where
  colWise :: Cohort d -> CohortShape ColumnWise
  rowWise :: Cohort d -> CohortShape RowWise

instance ShapeCohort Featureset where
  colWise x = ColumnWise (shapeColumnWise x)
  rowWise x = RowWise (shapeRowWise x)

data ColumnWise = MkColumnWise {
    colAttributes :: NonEmpty (OutputShape Type)
  , ids     :: [ID]
  , colData :: NonEmpty (NonEmpty (OutputShape Type))
  } deriving ( Show, Generic )

instance ToJSON ColumnWise where
  toJSON x = object [ "attributes" .= colAttributes x
                    , "ids"        .= ids x
                    , "data"       .= colData x ]

newtype IDRow = MkIDRow (ID, NonEmpty (OutputShape Type))
  deriving ( Show, Generic )

instance ToJSON IDRow where
  toJSON (MkIDRow x) = object [ uncurry (.=) x]

data RowWise = MkRowWise {
    attributes :: NonEmpty (OutputShape Type)
  , rowData :: NonEmpty IDRow
  } deriving ( Show, Generic )

instance ToJSON RowWise where
  toJSON x = object [ "attributes" .= attributes x
                    , "data"       .= rowData x ]

shapeColumnWise :: Cohort Featureset -> ColumnWise
shapeColumnWise x = MkColumnWise
        (fmap (nameAttr . NE.head . getFeatureset) z)
        (getCohortIDs x)
        (fmap (fmap dataOnly . getFeatureset)  z)
        -- TODO: don't use fromList; do something more principled
        where z = getFeaturesetList (tpose (MkFeaturesetList (NE.fromList (getCohortData x))))

shapeRowWise :: Cohort Featureset -> RowWise
shapeRowWise x = MkRowWise
        (fmap (nameAttr . NE.head . getFeatureset) z)
        (fmap MkIDRow (zip ids (fmap (fmap dataOnly . getFeatureset) z)))
        -- TODO: don't use fromList; do something more principled
        where z = NE.fromList (getCohortData x)
              ids = fromList (getCohortIDs x)