我开始学习Haskell,我尝试从SQLite文件中查询数据并将其作为CSV再次转储。我在编制UTCTime
字段时遇到问题,因此cassava
可以正确格式化。这是我的类型:
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
]
我的SQLite代码:
{-# 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
编译此代码会导致以下错误:
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
在将日期类型格式化为字符串时,我很清楚。我查看了formatTime
的类型信息,并且不太明白为什么我的String
(我假设错误与日期格式化字符串有关)必须是ByteString
。所以我的问题是:
cassava
格式化要写入CSV文件的日期类型的正确方法吗? 答案 0 :(得分:2)
您的问题是toField
有签名a -> Field
。如果您查看Field
类型,其定义为type Field = ByteString
。 formatTime
的结果是String
。所以问题是你提供String
,其中ByteString
是预期的。
由于String
是一种非常常见的类型,因此您应该首先检查是否已有可用的ToField String
实例。如果你看一下the definition。这意味着您可以将toField
函数专门化为签名String -> Field
并使用它:
instance ToField UTCTime where
toField = toField . formatTime defaultTimeLocale "%d-%m-%Y %H:%M:%S"
答案 1 :(得分:0)
您是否在History.Types文件中尝试过{ - #LANGUAGE OverloadedStrings# - }?不确定这是否有用,但也许值得一试。
ToField必须返回ByteString,因为它返回一个Field,而Field是一个ByteString:
http://haddock.stackage.org/lts-2.17/cassava-0.4.3.0/Data-Csv.html#t:Field
您正在正确调用formatTime,它只是formatTime返回一个String而不是ByteString。
您可以使用fromString or pack直接转换。所以只需像现在一样调用formatTime并转换结果。