{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module DataFrame.Typed.IO.CSV (
readCsv,
readCsvWithError,
readTsv,
readCsvWithOpts,
writeCsv,
writeTsv,
) where
import Control.Applicative ((<|>))
import Control.Exception (SomeException, try)
import qualified Data.Text as T
import DataFrame.IO.CSV (ReadOptions (..), TypeSpec (..), defaultReadOptions)
import qualified DataFrame.IO.CSV as CSV
import DataFrame.Schema (RuntimeSchema (..), elements)
import DataFrame.Typed.Freeze (freezeOrThrow, freezeWithError, thaw)
import DataFrame.Typed.Schema (KnownSchema)
import DataFrame.Typed.Types (TypedDataFrame)
import qualified Data.Map.Strict as M
schemaOptions :: forall cols. (RuntimeSchema cols) => ReadOptions -> ReadOptions
schemaOptions :: forall (cols :: [(Symbol, *)]).
RuntimeSchema cols =>
ReadOptions -> ReadOptions
schemaOptions ReadOptions
opts =
ReadOptions
opts
{ typeSpec = SpecifyTypes (M.toList declared) (typeSpec opts)
, readColumns = readColumns opts <|> Just (M.keys declared)
}
where
declared :: Map Text SchemaType
declared = Schema -> Map Text SchemaType
elements (forall (cols :: [(Symbol, *)]). RuntimeSchema cols => Schema
runtimeSchema @cols)
readCsv ::
forall cols.
(KnownSchema cols, RuntimeSchema cols) =>
FilePath -> IO (TypedDataFrame cols)
readCsv :: forall (cols :: [(Symbol, *)]).
(KnownSchema cols, RuntimeSchema cols) =>
FilePath -> IO (TypedDataFrame cols)
readCsv = forall (cols :: [(Symbol, *)]).
(KnownSchema cols, RuntimeSchema cols) =>
ReadOptions -> FilePath -> IO (TypedDataFrame cols)
readCsvWithOpts @cols ReadOptions
defaultReadOptions
readCsvWithError ::
forall cols.
(KnownSchema cols, RuntimeSchema cols) =>
FilePath -> IO (Either T.Text (TypedDataFrame cols))
readCsvWithError :: forall (cols :: [(Symbol, *)]).
(KnownSchema cols, RuntimeSchema cols) =>
FilePath -> IO (Either Text (TypedDataFrame cols))
readCsvWithError FilePath
path = do
Either SomeException DataFrame
r <- IO DataFrame -> IO (Either SomeException DataFrame)
forall e a. Exception e => IO a -> IO (Either e a)
try (ReadOptions -> FilePath -> IO DataFrame
CSV.readCsvWithOpts (forall (cols :: [(Symbol, *)]).
RuntimeSchema cols =>
ReadOptions -> ReadOptions
schemaOptions @cols ReadOptions
defaultReadOptions) FilePath
path)
Either Text (TypedDataFrame cols)
-> IO (Either Text (TypedDataFrame cols))
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either Text (TypedDataFrame cols)
-> IO (Either Text (TypedDataFrame cols)))
-> Either Text (TypedDataFrame cols)
-> IO (Either Text (TypedDataFrame cols))
forall a b. (a -> b) -> a -> b
$ case Either SomeException DataFrame
r of
Left (SomeException
e :: SomeException) -> Text -> Either Text (TypedDataFrame cols)
forall a b. a -> Either a b
Left (FilePath -> Text
T.pack (SomeException -> FilePath
forall a. Show a => a -> FilePath
show SomeException
e))
Right DataFrame
df -> DataFrame -> Either Text (TypedDataFrame cols)
forall (cols :: [(Symbol, *)]).
KnownSchema cols =>
DataFrame -> Either Text (TypedDataFrame cols)
freezeWithError DataFrame
df
readTsv ::
forall cols.
(KnownSchema cols, RuntimeSchema cols) =>
FilePath -> IO (TypedDataFrame cols)
readTsv :: forall (cols :: [(Symbol, *)]).
(KnownSchema cols, RuntimeSchema cols) =>
FilePath -> IO (TypedDataFrame cols)
readTsv = forall (cols :: [(Symbol, *)]).
(KnownSchema cols, RuntimeSchema cols) =>
ReadOptions -> FilePath -> IO (TypedDataFrame cols)
readCsvWithOpts @cols ReadOptions
defaultReadOptions{columnSeparator = '\t'}
readCsvWithOpts ::
forall cols.
(KnownSchema cols, RuntimeSchema cols) =>
ReadOptions -> FilePath -> IO (TypedDataFrame cols)
readCsvWithOpts :: forall (cols :: [(Symbol, *)]).
(KnownSchema cols, RuntimeSchema cols) =>
ReadOptions -> FilePath -> IO (TypedDataFrame cols)
readCsvWithOpts ReadOptions
opts FilePath
path =
ReadOptions -> FilePath -> IO DataFrame
CSV.readCsvWithOpts (forall (cols :: [(Symbol, *)]).
RuntimeSchema cols =>
ReadOptions -> ReadOptions
schemaOptions @cols ReadOptions
opts) FilePath
path IO DataFrame
-> (DataFrame -> IO (TypedDataFrame cols))
-> IO (TypedDataFrame cols)
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall (cols :: [(Symbol, *)]).
KnownSchema cols =>
DataFrame -> IO (TypedDataFrame cols)
freezeOrThrow @cols
writeCsv :: FilePath -> TypedDataFrame cols -> IO ()
writeCsv :: forall (cols :: [(Symbol, *)]).
FilePath -> TypedDataFrame cols -> IO ()
writeCsv FilePath
path = FilePath -> DataFrame -> IO ()
CSV.writeCsv FilePath
path (DataFrame -> IO ())
-> (TypedDataFrame cols -> DataFrame)
-> TypedDataFrame cols
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypedDataFrame cols -> DataFrame
forall (cols :: [(Symbol, *)]). TypedDataFrame cols -> DataFrame
thaw
writeTsv :: FilePath -> TypedDataFrame cols -> IO ()
writeTsv :: forall (cols :: [(Symbol, *)]).
FilePath -> TypedDataFrame cols -> IO ()
writeTsv FilePath
path = FilePath -> DataFrame -> IO ()
CSV.writeTsv FilePath
path (DataFrame -> IO ())
-> (TypedDataFrame cols -> DataFrame)
-> TypedDataFrame cols
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TypedDataFrame cols -> DataFrame
forall (cols :: [(Symbol, *)]). TypedDataFrame cols -> DataFrame
thaw