{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Polytropos.Cassava
(
AllToField (..)
, AllFromField (..)
, FieldNames (..)
) where
import Data.Functor.Identity (Identity (..))
import Data.Proxy (Proxy (..))
import GHC.Exts (Any, toList)
import GHC.TypeLits (KnownSymbol, symbolVal)
import Polytropos (Record)
import Polytropos.Core (Pair (..), Row, RowRep (..), noInlineUnsafeCo,
productRep, repVals)
import qualified Data.ByteString.Char8 as BS8
import qualified Data.Csv as Csv
class FieldNames (r :: Row) where
fieldNames :: Proxy r -> [String]
instance FieldNames '[] where
fieldNames :: Proxy '[] -> [String]
fieldNames Proxy '[]
_ = []
instance (KnownSymbol n, FieldNames r) => FieldNames ((n ':= a) ': r) where
fieldNames :: Proxy ((n ':= a) : r) -> [String]
fieldNames Proxy ((n ':= a) : r)
_ = Proxy n -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @n) String -> [String] -> [String]
forall a. a -> [a] -> [a]
: Proxy r -> [String]
forall (r :: Row). FieldNames r => Proxy r -> [String]
fieldNames (forall (t :: Row). Proxy t
forall {k} (t :: k). Proxy t
Proxy @r)
class AllToField (r :: Row) where
encFields :: Proxy r -> [Identity Any] -> [BS8.ByteString]
instance AllToField '[] where
encFields :: Proxy '[] -> [Identity Any] -> [ByteString]
encFields Proxy '[]
_ [Identity Any]
_ = []
instance (KnownSymbol n, Csv.ToField a, AllToField r)
=> AllToField ((n ':= a) ': r) where
encFields :: Proxy ((n ':= a) : r) -> [Identity Any] -> [ByteString]
encFields Proxy ((n ':= a) : r)
_ (Identity Any
x : [Identity Any]
xs) =
a -> ByteString
forall a. ToField a => a -> ByteString
Csv.toField (Any -> a
forall a b. a -> b
noInlineUnsafeCo Any
x :: a) ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: Proxy r -> [Identity Any] -> [ByteString]
forall (r :: Row).
AllToField r =>
Proxy r -> [Identity Any] -> [ByteString]
encFields (forall (t :: Row). Proxy t
forall {k} (t :: k). Proxy t
Proxy @r) [Identity Any]
xs
encFields Proxy ((n ':= a) : r)
_ [] = String -> [ByteString]
forall a. HasCallStack => String -> a
error String
"polytropos-cassava: payload arity mismatch"
class AllFromField (r :: Row) where
decFields :: Proxy r -> Csv.NamedRecord -> Csv.Parser [Identity Any]
instance AllFromField '[] where
decFields :: Proxy '[] -> NamedRecord -> Parser [Identity Any]
decFields Proxy '[]
_ NamedRecord
_ = [Identity Any] -> Parser [Identity Any]
forall a. a -> Parser a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
instance (KnownSymbol n, Csv.FromField a, AllFromField r)
=> AllFromField ((n ':= a) ': r) where
decFields :: Proxy ((n ':= a) : r) -> NamedRecord -> Parser [Identity Any]
decFields Proxy ((n ':= a) : r)
_ NamedRecord
nr = do
v <- NamedRecord
nr NamedRecord -> ByteString -> Parser a
forall a. FromField a => NamedRecord -> ByteString -> Parser a
Csv..: String -> ByteString
BS8.pack (Proxy n -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal (forall {k} (t :: k). Proxy t
forall (t :: Symbol). Proxy t
Proxy @n)) :: Csv.Parser a
vs <- decFields (Proxy @r) nr
pure (Identity (noInlineUnsafeCo v :: Any) : vs)
instance (FieldNames r, AllToField r) => Csv.ToNamedRecord (Record r) where
toNamedRecord :: Record r -> NamedRecord
toNamedRecord (RowRep Rep Identity ()
rep) = [(ByteString, ByteString)] -> NamedRecord
Csv.namedRecord
([ByteString] -> [ByteString] -> [(ByteString, ByteString)]
forall a b. [a] -> [b] -> [(a, b)]
zip ((String -> ByteString) -> [String] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
map String -> ByteString
BS8.pack (Proxy r -> [String]
forall (r :: Row). FieldNames r => Proxy r -> [String]
fieldNames (forall (t :: Row). Proxy t
forall {k} (t :: k). Proxy t
Proxy @r)))
(Proxy r -> [Identity Any] -> [ByteString]
forall (r :: Row).
AllToField r =>
Proxy r -> [Identity Any] -> [ByteString]
encFields (forall (t :: Row). Proxy t
forall {k} (t :: k). Proxy t
Proxy @r) (SmallArray (Identity Any) -> [Item (SmallArray (Identity Any))]
forall l. IsList l => l -> [Item l]
toList (Rep Identity () -> SmallArray (Identity Any)
forall {k} (f :: * -> *) (a :: k). Rep f a -> SmallArray (f Any)
repVals Rep Identity ()
rep))))
instance AllFromField r => Csv.FromNamedRecord (Record r) where
parseNamedRecord :: NamedRecord -> Parser (Record r)
parseNamedRecord NamedRecord
nr = do
vs <- Proxy r -> NamedRecord -> Parser [Identity Any]
forall (r :: Row).
AllFromField r =>
Proxy r -> NamedRecord -> Parser [Identity Any]
decFields (forall (t :: Row). Proxy t
forall {k} (t :: k). Proxy t
Proxy @r) NamedRecord
nr
pure (RowRep (productRep vs))