From 3a2b7ff4f05e545ab015b974096c0cb57043bfcd Mon Sep 17 00:00:00 2001
From: Alice BRENON <alice.brenon@ens-lyon.fr>
Date: Wed, 17 Jan 2024 09:32:11 +0100
Subject: [PATCH] Trim TSV.Header from HasDefaultHeader, already covered by
 DefaultOrdered from cassava

---
 geode.cabal                              |  2 +-
 lib/GEODE/Metadata.hs                    |  1 -
 lib/GEODE/Metadata/ArticleRecord.hs      |  7 ++----
 lib/GEODE/Metadata/Contrastive.hs        |  8 +++---
 lib/GEODE/Metadata/Entry.hs              |  8 ++----
 lib/GEODE/Metadata/TSV/Header.hs         | 31 ++++++++----------------
 lib/GEODE/Metadata/Types.hs              |  7 ++++--
 test/GEODE/Metadata/TestArticleRecord.hs |  2 +-
 test/GEODE/Metadata/TestEntry.hs         |  3 +--
 9 files changed, 25 insertions(+), 44 deletions(-)

diff --git a/geode.cabal b/geode.cabal
index 03309af..ba9c94f 100644
--- a/geode.cabal
+++ b/geode.cabal
@@ -24,7 +24,6 @@ library
     exposed-modules:  GEODE.Metadata
                     , GEODE.Metadata.Entry
                     , GEODE.Metadata.SplitContext
-                    , GEODE.Metadata.TSV.Header
                     , GEODE.Options
 
     -- Modules included in this library but not exported.
@@ -32,6 +31,7 @@ library
                     , GEODE.Metadata.ArticleRecord
                     , GEODE.Metadata.Record
                     , GEODE.Metadata.TSV
+                    , GEODE.Metadata.TSV.Header
                     , GEODE.Metadata.Types
                     , GEODE.Metadata.Work
 
diff --git a/lib/GEODE/Metadata.hs b/lib/GEODE/Metadata.hs
index 4376658..2d0dc5d 100644
--- a/lib/GEODE/Metadata.hs
+++ b/lib/GEODE/Metadata.hs
@@ -24,7 +24,6 @@ import GEODE.Metadata.Record as Record
 import GEODE.Metadata.SplitContext as SplitContext hiding (get, page, rank)
 import GEODE.Metadata.TSV as TSV
 import GEODE.Metadata.TSV.Header as TSV_Header
-  ( DefaultFields(..), HasDefaultHeader(..), WithDefaultHeader(..), glue )
 import GEODE.Metadata.Types as Types
 import GEODE.Metadata.Work as Work
 
diff --git a/lib/GEODE/Metadata/ArticleRecord.hs b/lib/GEODE/Metadata/ArticleRecord.hs
index b78b70a..1337b74 100644
--- a/lib/GEODE/Metadata/ArticleRecord.hs
+++ b/lib/GEODE/Metadata/ArticleRecord.hs
@@ -7,10 +7,9 @@ module GEODE.Metadata.ArticleRecord
 
 import Data.Aeson ((.=), FromJSON(..), ToJSON(..))
 import Data.Aeson.KeyMap as KeyMap (fromList)
-import Data.Csv (FromNamedRecord(..), ToNamedRecord(..))
+import Data.Csv (DefaultOrdered(..), FromNamedRecord(..), ToNamedRecord(..))
 import GEODE.Metadata.Record (Record(..))
 import GEODE.Metadata.Types (ToJSONObject(..))
-import GEODE.Metadata.TSV.Header (DefaultFields(..), HasDefaultHeader(..))
 import GEODE.Metadata.Work (Work(..))
 import GHC.Generics (Generic)
 import System.FilePath ((</>), (<.>))
@@ -23,6 +22,7 @@ data ArticleRecord = ArticleRecord
 
 instance FromNamedRecord ArticleRecord
 instance ToNamedRecord ArticleRecord
+instance DefaultOrdered ArticleRecord
 
 instance ToJSONObject ArticleRecord where
   toJSONObject (ArticleRecord {work, volume, article}) = KeyMap.fromList
@@ -42,6 +42,3 @@ instance Record ArticleRecord where
 
   relativePath (ArticleRecord {work, volume, article}) extension =
     (show work) </> ("T" <> show volume) </> (show article) <.> extension
-
-instance HasDefaultHeader ArticleRecord where
-  defaultFields = DefaultFields [ "work", "volume", "article" ]
diff --git a/lib/GEODE/Metadata/Contrastive.hs b/lib/GEODE/Metadata/Contrastive.hs
index 69d9c48..b044e0c 100644
--- a/lib/GEODE/Metadata/Contrastive.hs
+++ b/lib/GEODE/Metadata/Contrastive.hs
@@ -5,9 +5,9 @@ module GEODE.Metadata.Contrastive
   , formatList ) where
 
 import Data.Csv
-  ( FromField(..), FromNamedRecord(..), ToNamedRecord(..), ToField(..) )
+  ( DefaultOrdered(..), FromField(..), FromNamedRecord(..), ToNamedRecord(..)
+  , ToField(..) )
 import Data.Text (Text, intercalate, splitOn, uncons, unsnoc)
-import GEODE.Metadata.TSV.Header (DefaultFields(..), HasDefaultHeader(..))
 import GHC.Generics (Generic)
 
 newtype MultiText = MultiText
@@ -39,8 +39,6 @@ data Contrastive = Contrastive
   , domains :: MultiText
   , subCorpus :: MultiText } deriving (Generic, Show)
 
+instance DefaultOrdered Contrastive
 instance FromNamedRecord Contrastive
 instance ToNamedRecord Contrastive
-
-instance HasDefaultHeader Contrastive where
-  defaultFields = DefaultFields [ "authors", "domains", "subCorpus" ]
diff --git a/lib/GEODE/Metadata/Entry.hs b/lib/GEODE/Metadata/Entry.hs
index 3a3ae44..f9e568b 100644
--- a/lib/GEODE/Metadata/Entry.hs
+++ b/lib/GEODE/Metadata/Entry.hs
@@ -5,11 +5,9 @@ module GEODE.Metadata.Entry
   , normalize ) where
 
 import Data.Char (isAlphaNum, isSpace, isUpper, toLower)
-import Data.Csv (FromNamedRecord(..), ToNamedRecord(..))
+import Data.Csv (DefaultOrdered(..), FromNamedRecord(..), ToNamedRecord(..))
 import Data.Text as Text (Text, concat, foldl', pack, snoc)
 import GEODE.Metadata.SplitContext (Field(..), SplitContext(..), next)
-import GEODE.Metadata.TSV.Header
-  (DefaultFields(..), HasDefaultHeader(..), HasDefaultHeader(..))
 import GHC.Generics (Generic)
 
 data Entry = Entry
@@ -17,12 +15,10 @@ data Entry = Entry
   , name :: Text 
   , page :: Int } deriving (Generic, Show)
 
+instance DefaultOrdered Entry
 instance FromNamedRecord Entry
 instance ToNamedRecord Entry
 
-instance HasDefaultHeader Entry where
-  defaultFields = DefaultFields [ "headword", "name", "page" ]
-
 normalize :: Text -> Text
 normalize = Text.foldl' appendIf mempty
   where
diff --git a/lib/GEODE/Metadata/TSV/Header.hs b/lib/GEODE/Metadata/TSV/Header.hs
index 6e084e6..7d9157d 100644
--- a/lib/GEODE/Metadata/TSV/Header.hs
+++ b/lib/GEODE/Metadata/TSV/Header.hs
@@ -1,38 +1,27 @@
 {-# LANGUAGE ExplicitNamespaces, ScopedTypeVariables, TypeOperators #-}
 module GEODE.Metadata.TSV.Header
-  ( DefaultFields(..)
-  , HasDefaultHeader(..)
-  , WithDefaultHeader(..)
+  ( WithDefaultHeader(..)
   , for
   , getHeader
   , glue ) where
 
-import Data.ByteString.Char8 as StrictByteString (pack)
-import Data.Csv (Header, ToNamedRecord(..), ToRecord(..))
+import Data.Csv (DefaultOrdered(..), Header, ToNamedRecord(..), ToRecord(..))
 import Data.HashMap.Strict ((!))
-import Data.Vector (fromList)
 import GEODE.Metadata.Types (type (@)(..))
 
 newtype WithDefaultHeader a = WithDefaultHeader a
-newtype DefaultFields a = DefaultFields [String]
-class HasDefaultHeader a where
-  defaultFields :: DefaultFields a
 
-instance (HasDefaultHeader a, HasDefaultHeader b) => HasDefaultHeader (a @ b) where
-  defaultFields = DefaultFields (a ++ b)
-    where
-      DefaultFields a = (defaultFields :: DefaultFields a)
-      DefaultFields b = (defaultFields :: DefaultFields b)
+-- | An alias to shorten and make more intuitive the magic of
+-- the DefaultOrdered class type
+getHeader :: DefaultOrdered a => a -> Header
+getHeader = headerOrder
 
-getHeader :: forall a. HasDefaultHeader a => a -> Header
-getHeader _ = StrictByteString.pack <$> fromList fields
-    where
-      DefaultFields fields = (defaultFields :: DefaultFields a)
-
-for :: HasDefaultHeader a => a
+-- | This is just `undefined`, but nicer to read and making more sense with the
+-- type notation `(for :: SomeTypeOfYours)`
+for :: DefaultOrdered a => a
 for = undefined
 
-instance (HasDefaultHeader a, ToNamedRecord a) => ToRecord (WithDefaultHeader a) where
+instance (DefaultOrdered a, ToNamedRecord a) => ToRecord (WithDefaultHeader a) where
   toRecord (WithDefaultHeader a) = (toNamedRecord a !) <$> getHeader a
 
 glue :: a -> b -> WithDefaultHeader (a @ b)
diff --git a/lib/GEODE/Metadata/Types.hs b/lib/GEODE/Metadata/Types.hs
index 881168a..e8ff47a 100644
--- a/lib/GEODE/Metadata/Types.hs
+++ b/lib/GEODE/Metadata/Types.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE ExplicitNamespaces, FlexibleInstances, MultiParamTypeClasses, TypeOperators, UndecidableInstances #-}
+{-# LANGUAGE ExplicitNamespaces, FlexibleInstances, MultiParamTypeClasses, ScopedTypeVariables, TypeOperators, UndecidableInstances #-}
 module GEODE.Metadata.Types
   ( Has(..)
   , ToJSONObject(..)
@@ -6,7 +6,7 @@ module GEODE.Metadata.Types
 
 import Data.Aeson (FromJSON(..), Object, Series, ToJSON(..), Value(..), pairs)
 import Data.Aeson.KeyMap as Object (union)
-import Data.Csv (FromNamedRecord(..), ToNamedRecord(..))
+import Data.Csv (DefaultOrdered(..), FromNamedRecord(..), ToNamedRecord(..))
 import Data.HashMap.Strict as Hash (union)
 
 infixl 9 @
@@ -25,6 +25,9 @@ instance Has a b => Has a (b @ c) where
 instance {-# OVERLAPS #-} Has b (a @ b) where
   get (_ :@: b) = b
 
+instance (DefaultOrdered a, DefaultOrdered b) => DefaultOrdered (a @ b) where
+  headerOrder _ = headerOrder (undefined :: a) <> headerOrder (undefined :: b)
+
 instance (ToNamedRecord a, ToNamedRecord b) => ToNamedRecord (a @ b) where
   toNamedRecord (a :@: b) = Hash.union (toNamedRecord a) (toNamedRecord b)
 
diff --git a/test/GEODE/Metadata/TestArticleRecord.hs b/test/GEODE/Metadata/TestArticleRecord.hs
index 87ade55..139e4d5 100644
--- a/test/GEODE/Metadata/TestArticleRecord.hs
+++ b/test/GEODE/Metadata/TestArticleRecord.hs
@@ -5,7 +5,7 @@ import Data.Csv (ToNamedRecord(..))
 import Data.Foldable (toList)
 import Data.HashMap.Strict ((!?))
 import GEODE.Metadata (Work(..), ArticleRecord(..))
-import GEODE.Metadata.TSV.Header (getHeader, for)
+import GEODE.Metadata (getHeader, for)
 import Test.HUnit (Test(..), (~?=))
 import Test.HUnit.Extra (isJust)
 
diff --git a/test/GEODE/Metadata/TestEntry.hs b/test/GEODE/Metadata/TestEntry.hs
index bf31fc7..3b4f92b 100644
--- a/test/GEODE/Metadata/TestEntry.hs
+++ b/test/GEODE/Metadata/TestEntry.hs
@@ -5,9 +5,8 @@ import Data.Csv (ToNamedRecord(..))
 import Data.Foldable (toList)
 import Data.HashMap.Strict ((!?))
 import Data.Text (dropEnd)
-import GEODE.Metadata (evalSplit, newEntry, normalize)
+import GEODE.Metadata (evalSplit, for, getHeader, newEntry, normalize)
 import GEODE.Metadata.Entry (Entry(..))
-import GEODE.Metadata.TSV.Header (getHeader, for)
 import Test.HUnit (Test(..), (~?=))
 import Test.HUnit.Extra (isJust)
 
-- 
GitLab