packages feed

composite-cassava 0.0.2.0 → 0.0.3.0

raw patch · 6 files changed

+169/−16 lines, 6 filesdep +bytestringdep +composite-cassavadep +tastyPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: bytestring, composite-cassava, tasty, tasty-hunit, vector

API changes (from Hackage documentation)

- Composite.Csv: instance (GHC.Base.Functor f, GHC.TypeLits.KnownSymbol s, Data.Csv.Conversion.FromField (f x), Data.Csv.Conversion.FromNamedRecord (Data.Vinyl.Core.Rec f xs)) => Data.Csv.Conversion.FromNamedRecord (Data.Vinyl.Core.Rec f ((s Composite.Record.:-> x) : xs))
- Composite.Csv: instance (GHC.Base.Functor f, GHC.TypeLits.KnownSymbol s, Data.Csv.Conversion.ToField (f x), Data.Csv.Conversion.ToNamedRecord (Data.Vinyl.Core.Rec f xs)) => Data.Csv.Conversion.ToNamedRecord (Data.Vinyl.Core.Rec f ((s Composite.Record.:-> x) : xs))
- Composite.Csv: instance Data.Csv.Conversion.FromNamedRecord (Data.Vinyl.Core.Rec f '[])
- Composite.Csv: instance Data.Csv.Conversion.ToNamedRecord (Data.Vinyl.Core.Rec f '[])
+ Composite.Csv: F :: Rec f xs -> F f xs
+ Composite.Csv: TF :: Rec f xs -> TF f xs
+ Composite.Csv: [unF] :: F f xs -> Rec f xs
+ Composite.Csv: [unTF] :: TF f xs -> Rec f xs
+ Composite.Csv: class ToHeader x
+ Composite.Csv: extractRecHeader :: ToHeader x => Proxy x -> Vector Name
+ Composite.Csv: instance (GHC.Base.Functor f, GHC.TypeLits.KnownSymbol s, Data.Csv.Conversion.FromField (f (s Composite.Record.:-> x)), Data.Csv.Conversion.FromNamedRecord (Composite.Csv.TF f xs)) => Data.Csv.Conversion.FromNamedRecord (Composite.Csv.TF f ((s Composite.Record.:-> x) : xs))
+ Composite.Csv: instance (GHC.Base.Functor f, GHC.TypeLits.KnownSymbol s, Data.Csv.Conversion.FromField (f x), Data.Csv.Conversion.FromNamedRecord (Composite.Csv.F f xs)) => Data.Csv.Conversion.FromNamedRecord (Composite.Csv.F f ((s Composite.Record.:-> x) : xs))
+ Composite.Csv: instance (GHC.Base.Functor f, GHC.TypeLits.KnownSymbol s, Data.Csv.Conversion.ToField (f (s Composite.Record.:-> x)), Data.Csv.Conversion.ToNamedRecord (Composite.Csv.TF f xs)) => Data.Csv.Conversion.ToNamedRecord (Composite.Csv.TF f ((s Composite.Record.:-> x) : xs))
+ Composite.Csv: instance (GHC.Base.Functor f, GHC.TypeLits.KnownSymbol s, Data.Csv.Conversion.ToField (f x), Data.Csv.Conversion.ToNamedRecord (Composite.Csv.F f xs)) => Data.Csv.Conversion.ToNamedRecord (Composite.Csv.F f ((s Composite.Record.:-> x) : xs))
+ Composite.Csv: instance (GHC.TypeLits.KnownSymbol s, Composite.Csv.ToHeader (Data.Vinyl.Core.Rec f xs)) => Composite.Csv.ToHeader (Data.Vinyl.Core.Rec f ((s Composite.Record.:-> x) : xs))
+ Composite.Csv: instance Composite.Csv.ToHeader (Data.Vinyl.Core.Rec f '[])
+ Composite.Csv: instance Data.Csv.Conversion.FromNamedRecord (Composite.Csv.F f '[])
+ Composite.Csv: instance Data.Csv.Conversion.FromNamedRecord (Composite.Csv.TF f '[])
+ Composite.Csv: instance Data.Csv.Conversion.ToNamedRecord (Composite.Csv.F f '[])
+ Composite.Csv: instance Data.Csv.Conversion.ToNamedRecord (Composite.Csv.TF f '[])
+ Composite.Csv: newtype F f xs
+ Composite.Csv: newtype TF f xs

Files

ChangeLog.md view
@@ -1,5 +1,10 @@ # Changelog for composite-cassava +## v0.0.3.0++* Add tests.+* Add `ToHeader` class with `generateRecHeader` function.+ ## v0.0.2.0  * Fix `ToNamedRecord` instances.
composite-cassava.cabal view
@@ -5,12 +5,12 @@ -- see: https://github.com/sol/hpack  name:           composite-cassava-version:        0.0.2.0+version:        0.0.3.0 synopsis:       Csv parsing functionality for composite. description:    Csv parsing functionality for composite. category:       Composite, Csv author:         Daniel Firth-maintainer:     dan.firth@homtopic.tech+maintainer:     dan.firth@homotopic.tech copyright:      Daniel Firth license:        MIT license-file:   LICENSE@@ -18,6 +18,8 @@ extra-source-files:     README.md     ChangeLog.md+    test/data/A.csv+    test/data/B.csv  source-repository head   type: git@@ -36,4 +38,26 @@     , composite-base >=0.7.0.0 && <0.8     , text     , unordered-containers+    , vector+  default-language: Haskell2010++test-suite composite-casssava-test+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      Paths_composite_cassava+  hs-source-dirs:+      test+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.7 && <5+    , bytestring+    , cassava >=0.5.0.0 && <0.6+    , composite-base >=0.7.0.0 && <0.8+    , composite-cassava+    , tasty+    , tasty-hunit+    , text+    , unordered-containers+    , vector   default-language: Haskell2010
src/Composite/Csv.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-}@@ -10,25 +11,50 @@ import Composite.Record import Data.Csv import Data.HashMap.Strict as HM+import Data.Proxy import Data.Text.Encoding as T+import Data.Vector import GHC.TypeLits -instance FromNamedRecord (Rec f '[]) where-  parseNamedRecord m = pure RNil+instance FromNamedRecord (F f '[]) where+  parseNamedRecord m = pure $ F RNil -instance ToNamedRecord (Rec f '[]) where+instance ToNamedRecord (F f '[]) where   toNamedRecord m = mempty -instance (Functor f, KnownSymbol s, FromField (f x), FromNamedRecord (Rec f xs)) => FromNamedRecord (Rec f ((s :-> x) ': xs)) where+instance FromNamedRecord (TF f '[]) where+  parseNamedRecord m = pure $ TF RNil++instance ToNamedRecord (TF f '[]) where+  toNamedRecord m = mempty++newtype F f xs = F {unF :: Rec f xs}++instance (Functor f, KnownSymbol s, FromField (f x), FromNamedRecord (F f xs)) => FromNamedRecord (F f ((s :-> x) ': xs)) where   parseNamedRecord m = do-    let nL :: (s :-> x)-        nL = undefined-    x <- m .: T.encodeUtf8 (valName nL)-    f <- parseNamedRecord @(Rec f xs) m-    pure $ x :^: f+    x <- m .: T.encodeUtf8 (valName @s undefined)+    F f <- parseNamedRecord @(F f xs) m+    pure $ F $ x :^: f -instance (Functor f, KnownSymbol s, ToField (f x), ToNamedRecord (Rec f xs)) => ToNamedRecord (Rec f ((s :-> x) ': xs)) where-  toNamedRecord (x :^: xs) =-    let nL :: (s :-> x)-        nL = undefined-     in HM.singleton (T.encodeUtf8 (valName nL)) (toField x) <> toNamedRecord xs+instance (Functor f, KnownSymbol s, ToField (f x), ToNamedRecord (F f xs)) => ToNamedRecord (F f ((s :-> x) ': xs)) where+  toNamedRecord (F (x :^: xs)) = HM.singleton (T.encodeUtf8 (valName @s undefined)) (toField x) <> toNamedRecord (F xs)++newtype TF f xs = TF {unTF :: Rec f xs}++instance (Functor f, KnownSymbol s, FromField (f (s :-> x)), FromNamedRecord (TF f xs)) => FromNamedRecord (TF f ((s :-> x) ': xs)) where+  parseNamedRecord m = do+    x <- m .: T.encodeUtf8 (valName @s undefined)+    TF f <- parseNamedRecord @(TF f xs) m+    pure $ TF $ x :& f++instance (Functor f, KnownSymbol s, ToField (f (s :-> x)), ToNamedRecord (TF f xs)) => ToNamedRecord (TF f ((s :-> x) ': xs)) where+  toNamedRecord (TF (x :& xs)) = HM.singleton (T.encodeUtf8 (valName @s undefined)) (toField x) <> toNamedRecord (TF xs)++class ToHeader x where+  extractRecHeader :: Proxy x -> Vector Name++instance ToHeader (Rec f '[]) where+  extractRecHeader _ = Data.Vector.fromList []++instance (KnownSymbol s, ToHeader (Rec f xs)) => ToHeader (Rec f (s :-> x ': xs)) where+  extractRecHeader Proxy = pure (encodeUtf8 $ valName @s undefined) <> extractRecHeader (Proxy @(Rec f xs))
+ test/Spec.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GeneralisedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE ViewPatterns #-}+{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}++module Main (main) where++import Composite+import Composite.Csv+import Composite.TH+import Data.ByteString.Lazy as LBS+import Data.Csv+import Data.Proxy+import Data.Text+import Data.Text.Encoding+import Data.Vector+import Test.Tasty+import Test.Tasty.HUnit++withLensesAndProxies+  [d|+    type A = "A" :-> Text++    type B = "B" :-> Double++    type C = "C" :-> Text++    type D = "D" :-> Int+    |]++type RecMaybe = Rec Maybe '[A, B, C, D]++deriving newtype instance FromField A++deriving newtype instance FromField B++deriving newtype instance FromField C++deriving newtype instance FromField D++deriving newtype instance ToField A++deriving newtype instance ToField B++deriving newtype instance ToField C++deriving newtype instance ToField D++deriving via (TF Maybe '[A, B, C, D]) instance FromNamedRecord RecMaybe++deriving via (TF Maybe '[A, B, C, D]) instance ToNamedRecord RecMaybe++rec1 :: RecMaybe+rec1 = Just "foo" :^: Just 5e-4 :^: Nothing :^: Just 5 :^: RNil++rec2 :: RecMaybe+rec2 = Just "bar" :^: Just 100e-10 :^: Just "quux" :^: Just 4 :^: RNil++testData :: [RecMaybe]+testData = [rec1, rec2]++tests :: TestTree+tests =+  testGroup+    "Parsing Tests"+    [ testCase "parses Record" $ do+        a <- LBS.readFile "./test/data/A.csv"+        let Right (x, toList -> xs) = decodeByName a+        assertEqual "" testData xs+        b <- LBS.readFile "./test/data/B.csv"+        let Right (y, toList -> ys) = decodeByName b+        assertEqual "" xs ys+        let a' = encodeByName x xs+        let Right (a'', toList -> xs') = decodeByName a'+        assertEqual "" xs xs'+        let b' = encodeByName (extractRecHeader (Proxy @RecMaybe)) ys+        let Right (b'', toList -> ys') = decodeByName b'+        assertEqual "" xs ys'+    ]++main :: IO ()+main = defaultMain tests
+ test/data/A.csv view
@@ -0,0 +1,3 @@+A,B,C,D+"foo",5e-4,,5+"bar",100e-10,"quux",4
+ test/data/B.csv view
@@ -0,0 +1,3 @@+A,D,C,B,E+"foo",5,,5e-4,"lemon"+"bar",4,"quux",100e-10,,