I started learning Haskell and I try to query data from a SQLite file and dump it again as CSV. I have an issue formating UTCTime
fields, so that cassava
can format it correctly. This is my type:
module History.Types
(Visit)
where
import Data.ByteString as B
import Data.Csv
import Data.Text (Text)
import Data.Time
import Data.Time.Format
import Database.SQLite.Simple.FromRow
data Visit = Visit
{ url :: Text
, title :: Text
, visit_count :: Int
, typed_count :: Int
, last_visit_time :: UTCTime
, visit_time :: UTCTime
, from_visit :: Int
}
deriving (Show)
instance FromRow Visit where
fromRow = Visit <$> field
<*> field
<*> field
<*> field
<*> field
<*> field
<*> field
instance ToField UTCTime where
toField t = formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S" t
instance ToRecord Visit where
toRecord (Visit url
title
visit_count
typed_count
last_visit_time
visit_time
from_visit) = record [ toField visit_time
, toField url
, toField title
, toField visit_count
, toField typed_count
, toField from_visit
, toField last_visit_time
]
And my SQLite code:
{-# LANGUAGE OverloadedStrings #-}
module History.DB
(queryHistory)
where
import History.Types (Visit)
import Data.Text (Text)
import Database.SQLite.Simple (open, query_, close, Query)
q :: Query
q = "\
\SELECT urls.url \
\ , urls.title \
\ , urls.visit_count \
\ , urls.typed_count \
\ , datetime(urls.last_visit_time/1000000-11644473600,'unixepoch','localtime') \
\ , datetime(visits.visit_time/1000000-11644473600,'unixepoch','localtime') \
\ , visits.from_visit \
\FROM urls, visits \
\WHERE urls.id = visits.id \
\ORDER BY visits.visit_time"
queryHistory :: FilePath -> IO [Visit]
queryHistory dbPath =
do conn <- open dbPath
history <- query_ conn q
close conn
return history
Compiling this code leads to the following error:
src/History/Types.hs:34:15:
Couldn't match type ‘[Char]’ with ‘ByteString’
Expected type: Field
Actual type: String
In the expression:
formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S" t
In an equation for ‘toField’:
toField t = formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S" t
So clearly I make a mess with when formatting the date type into a string. I look at the type information of formatTime
and don't really understand why my String
(I assume the error relates to the date formatting string) has to be a ByteString
. So my questions are:
cassava
? Your problem is that toField
has the signature a -> Field
. If you look at the Field
type its definition is type Field = ByteString
. The result of formatTime
is a String
. So the problem is that you provide a String
where a ByteString
is expected.
Since String
is a very common type the first thing you should do is to check if there is already an instance for ToField String
you can use. If you look at the definition there is. This means that you can specialize the toField
function to have the signature String -> Field
and the use it like this:
instance ToField UTCTime where
toField = toField . formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S"
Have you tried {-# LANGUAGE OverloadedStrings #-} in your History.Types file? Not sure if that would work, but maybe worth a try.
ToField has to return a ByteString because it returns a Field, and a Field IS a ByteString:
http://haddock.stackage.org/lts-2.17/cassava-0.4.3.0/Data-Csv.html#t:Field
You are calling formatTime correctly, its just that formatTime returns a String and not a ByteString.
You can directly convert with fromString or pack . So just call formatTime like you are now and convert the result.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.