{-# LANGUAGE GADTs #-} {-# LANGUAGE ScopedTypeVariables #-} module Database.DSH.CSV (csvImport) where import Database.DSH.Internals import qualified Data.Text as T import Text.CSV csvImport :: (Reify a) => FilePath -> Type [a] -> IO (Exp [a]) csvImport filepath csvType = do let rType = recordType csvType contents <- readFile filepath let csv1 = case parseCSV filepath contents of Left er -> error (show er) Right r -> filter (\l -> not (all null l) || length l > 1) (tail r) return (ListE (fmap (csvRecordToNorm rType) csv1)) where csvError :: String -> a csvError s = error ("Error in '" ++ filepath ++ "': " ++ s) recordType :: Type [a] -> Type a recordType (ListT rType) = rType csvRecordToNorm :: Type a -> [String] -> Exp a csvRecordToNorm UnitT [] = UnitE csvRecordToNorm t [] = csvError ("When converting record '" ++ "[]" ++ "' to a value of type '" ++ show t ++ "'") csvRecordToNorm t1 [bs] = csvFieldToNorm t1 bs csvRecordToNorm (PairT (t1 :: Type b) (t2 :: Type c)) (bs : bss) = PairE (csvFieldToNorm t1 bs :: Exp b) (csvRecordToNorm t2 bss) csvRecordToNorm t rs = csvError ("When converting record '" ++ show rs ++ "' to a value of type '" ++ show t ++ "'") csvFieldToNorm :: Type a -> String -> Exp a csvFieldToNorm t s = case t of UnitT -> UnitE BoolT -> BoolE (read s) CharT -> CharE (head s) IntegerT -> IntegerE (read s) DoubleT -> DoubleE (read s) TextT -> TextE (T.pack s) _ -> er where er = csvError ("When converting CSV field'" ++ s ++ "' to a value of type '" ++ show t ++ "'")