{- differential
Gregory W. Schwartz
Finds out whether an entity comes from different distributions (statuses).
-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
module Main where
-- Standard
import Data.List
import Data.Maybe
import Data.Semigroup
import qualified Data.Map as Map
import qualified Data.Set as Set
-- Cabal
import qualified Data.Csv as CSV
import Options.Generic
import TextShow
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
import qualified Data.Vector as V
-- Local
import Types
import Load
import Differential
-- | Command line arguments
data Options = Options { nameCol :: Maybe T.Text
<?> "([name] | COLUMN) The column containing the names of the entities."
, statusCol :: Maybe T.Text
<?> "([status] | COLUMN) The column containing the statuses of the entities."
, valueCol :: Maybe T.Text
<?> "([value] | COLUMN) The column containing the values of the entities."
}
deriving (Generic)
instance ParseRecord Options
main :: IO ()
main = do
opts <- getRecord "differential, Gregory W. Schwartz.\
\ Finds out whether an entity comes from\
\ different distributions (statuses)."
contents <- BL.getContents
let nameCol' = NameCol . fromMaybe "name" . unHelpful . nameCol $ opts
statusCol' =
StatusCol . fromMaybe "status" . unHelpful . statusCol $ opts
valueCol' = ValueCol . fromMaybe "value" . unHelpful . valueCol $ opts
rows = either error snd
$ (CSV.decodeByName contents :: Either String (CSV.Header, V.Vector (Map.Map T.Text T.Text)))
entities = fmap (toEntity nameCol' statusCol' valueCol') rows
nameMap = getNameMap entities
outputMaps = getDifferentials nameMap
comparisons = Set.toList
. Set.fromList
. concatMap (Map.keys . unOutputMap . snd)
$ outputMaps
outputHeader = V.fromList
$ [B.pack . T.unpack . unNameCol $ nameCol']
<> fmap (B.pack . T.unpack) comparisons
outputBody =
fmap ( (\ m -> foldl'
(\acc x -> Map.insertWith (flip const) x "" acc)
m
comparisons
)
. (\ (!n, !m) -> Map.insert (unNameCol nameCol') (unName n)
. unOutputMap
$ m
)
)
$ outputMaps
BL.putStrLn . CSV.encodeByName outputHeader $ outputBody