{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
module Foundation.Format.CSV.Builder
(
csvStringBuilder
, rowStringBuilder
, fieldStringBuilder
, csvBlockBuilder
, rowBlockBuilder
, fieldBlockBuilder
, rowC
) where
import Basement.Imports
import Basement.String (replace)
import Foundation.Collection.Sequential (Sequential(intersperse))
import Foundation.Conduit.Internal
import qualified Foundation.String.Builder as String
import Basement.Block (Block)
import qualified Basement.Block.Builder as Block
import GHC.ST (runST)
import Foundation.Format.CSV.Types
csvStringBuilder :: CSV -> String.Builder
csvStringBuilder :: CSV -> Builder
csvStringBuilder = Builder -> Builder
String.unsafeStringBuilder forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. CSV -> Builder
csvBlockBuilder
rowStringBuilder :: Row -> String.Builder
rowStringBuilder :: Row -> Builder
rowStringBuilder = Builder -> Builder
String.unsafeStringBuilder forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Row -> Builder
rowBlockBuilder
fieldStringBuilder :: Field -> String.Builder
fieldStringBuilder :: Field -> Builder
fieldStringBuilder = Builder -> Builder
String.unsafeStringBuilder forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Field -> Builder
fieldBlockBuilder
csvBlockBuilder :: CSV -> Block.Builder
csvBlockBuilder :: CSV -> Builder
csvBlockBuilder = forall a. Monoid a => [a] -> a
mconcat forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall c. Sequential c => Element c -> c -> c
intersperse (String -> Builder
Block.emitString String
"\r\n") forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Row -> Builder
rowBlockBuilder forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall l. IsList l => l -> [Item l]
toList forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. CSV -> Array Row
unCSV
rowBlockBuilder :: Row -> Block.Builder
rowBlockBuilder :: Row -> Builder
rowBlockBuilder = forall a. Monoid a => [a] -> a
mconcat forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall c. Sequential c => Element c -> c -> c
intersperse (Char -> Builder
Block.emitUTF8Char Char
',') forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Field -> Builder
fieldBlockBuilder forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall l. IsList l => l -> [Item l]
toList forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. Row -> Array Field
unRow
fieldBlockBuilder :: Field -> Block.Builder
fieldBlockBuilder :: Field -> Builder
fieldBlockBuilder (FieldInteger Integer
i) = String -> Builder
Block.emitString forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show Integer
i
fieldBlockBuilder (FieldDouble Double
d) = String -> Builder
Block.emitString forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show Double
d
fieldBlockBuilder (FieldString String
s Escaping
e) = case Escaping
e of
Escaping
NoEscape -> String -> Builder
Block.emitString String
s
Escaping
Escape -> Char -> Builder
Block.emitUTF8Char Char
'"' forall a. Semigroup a => a -> a -> a
<> String -> Builder
Block.emitString String
s forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Block.emitUTF8Char Char
'"'
Escaping
DoubleEscape -> Char -> Builder
Block.emitUTF8Char Char
'"' forall a. Semigroup a => a -> a -> a
<> String -> Builder
Block.emitString (String -> String -> String -> String
replace String
"\"" String
"\"\"" String
s) forall a. Semigroup a => a -> a -> a
<> Char -> Builder
Block.emitUTF8Char Char
'"'
rowC :: (Record row, Monad m) => Conduit row (Block Word8) m ()
rowC :: forall row (m :: * -> *).
(Record row, Monad m) =>
Conduit row (Block Word8) m ()
rowC = forall i o (m :: * -> *). Conduit i o m (Maybe i)
await forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall {m :: * -> *} {i}.
(Monad m, Record i) =>
Maybe i -> Conduit i (Block Word8) m ()
go
where
go :: Maybe i -> Conduit i (Block Word8) m ()
go Maybe i
Nothing = forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
go (Just i
r) =
let bytes :: Block Word8
bytes = forall a. (forall s. ST s a) -> a
runST (forall (prim :: * -> *).
PrimMonad prim =>
Builder -> prim (Block Word8)
Block.run forall a b. (a -> b) -> a -> b
$ Row -> Builder
rowBlockBuilder (forall a. Record a => a -> Row
toRow i
r) forall a. Semigroup a => a -> a -> a
<> String -> Builder
Block.emitString String
"\r\n")
in forall (m :: * -> *) o i. Monad m => o -> Conduit i o m ()
yield Block Word8
bytes forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall i o (m :: * -> *). Conduit i o m (Maybe i)
await forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe i -> Conduit i (Block Word8) m ()
go