{-# LANGUAGE TypeFamilies #-}
-- | User-friendly, type safe, runtime efficient tooling for working
-- with tabular data deserialized from comma-separated values (CSV)
-- files. The type of each row of data is inferred from data, which
-- can then be streamed from disk, or worked with in memory.
module Frames
  ( module Data.Vinyl
  , module Data.Vinyl.CoRec
  , module Data.Vinyl.Lens
  , module Data.Vinyl.TypeLevel
  , module Frames.Col
  , module Frames.ColumnUniverse
  , module Frames.CSV
  , module Frames.Exploration
  , module Frames.Frame
  , inCoreAoS, inCoreAoS', inCore, inCoreSoA
  , I.toAoS, I.toFrame, I.filterFrame
  , module Frames.Melt
  , module Frames.Rec
  , module Frames.RecF
  , module Frames.RecLens
  , module Frames.TypeLevel
  , module Pipes.Safe, runSafeEffect
  , Text
  ) where
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Primitive
import Data.Text (Text)
import Data.Vinyl ((<+>), Rec)
import Data.Vinyl.CoRec (Field, onField, onCoRec)
import Data.Vinyl.Lens hiding (rlens, rget, rput)
import Data.Vinyl.TypeLevel (AllConstrained, AllSatisfied, AllAllSat)
import Frames.Col ((:->)(..))
import Frames.ColumnUniverse
import Frames.CSV (readTable, readTableMaybe, declareColumn,
                   pipeTable, pipeTableMaybe,
                   tableType, tableTypes, tableType', tableTypes')
import Frames.Exploration
import Frames.Frame
import qualified Frames.InCore as I
import Frames.Melt (melt, meltRow)
import Frames.Rec (Record, RecordColumns, (&:), recUncons, recMaybe, showFields)
import Frames.RecF
import Frames.RecLens
import Frames.TypeLevel
import qualified Pipes as P
import Pipes.Safe (MonadSafe, runSafeT, runSafeP, SafeT)
import qualified Pipes.Safe as PS

-- * SafeT helpers

-- | Run a self-contained ’Pipes.Effect’ and execute the finalizers
-- associated with the ’SafeT’ transformer.
runSafeEffect :: (MonadIO m, PS.MonadMask m)
              => P.Effect (SafeT m) r -> m r
runSafeEffect = runSafeT . P.runEffect

-- | Stream a finite sequence of rows into an efficient in-memory
-- representation for further manipulation. Each column of the input
-- table will be stored optimally based on its type, making use of the
-- resulting generators a matter of indexing into a densely packed
-- representation. Returns a 'Frame' that provides a function to index
-- into the table.
inCoreAoS :: (PrimMonad m, MonadIO m, PS.MonadMask m, I.RecVec rs)
          => P.Producer (Record rs) (PS.SafeT m) () -> m (FrameRec rs)
inCoreAoS = runSafeT . I.inCoreAoS

-- | Like 'inCoreAoS', but applies the provided function to the record
-- of columns before building the 'Frame'.
inCoreAoS' :: (PrimMonad m, MonadIO m, PS.MonadMask m, I.RecVec rs)
           => (Rec ((->) Int) rs -> Rec ((->) Int) ss)
           -> P.Producer (Record rs) (SafeT m) () -> m (FrameRec ss)
inCoreAoS' f = runSafeT . I.inCoreAoS' f

-- | Stream a finite sequence of rows into an efficient in-memory
-- representation for further manipulation. Each column of the input
-- table will be stored optimally based on its type, making use of the
-- resulting generator a matter of indexing into a densely packed
-- representation.
inCore :: (PrimMonad m, MonadIO m, PS.MonadMask m, I.RecVec rs, Monad n)
       => P.Producer (Record rs) (SafeT m) () -> m (P.Producer (Record rs) n ())
inCore = runSafeT . I.inCore

-- | Stream a finite sequence of rows into an efficient in-memory
-- representation for further manipulation. Each column of the input
-- table will be stored optimally based on its type, making use of the
-- resulting generators a matter of indexing into a densely packed
-- representation. Returns the number of rows and a record of column
-- indexing functions. See 'toAoS' to convert the result to a 'Frame'
-- which provides an easier-to-use function that indexes into the
-- table in a row-major fashion.
inCoreSoA :: (PrimMonad m, MonadIO m, PS.MonadMask m, I.RecVec rs)
          => P.Producer (Record rs) (SafeT m) () -> m (Int, Rec ((->) Int) rs)
inCoreSoA = runSafeT . I.inCoreSoA