我试图创建一个简单的Haskell应用程序,该应用程序从API获取数据,然后将其插入数据库(sqlite3)。我已经成功地从我的API中获取了数据并创建了数据库。但是,我目前面临的问题是如何从JSON中提取这些数据并将其插入数据库。我不能分享所有细节,这就是为什么我修改类型(数据)结构的原因。示例API响应:
[{"name":"John","surname":"Terry","workPlace":"Bank","accountBalance":124344.08,"age":44}]
人员数据类型及其实例(用于提取):
data Person = Person
{
name :: Text,
surname :: Text,
workPlace :: Text,
accountBalance :: Rational,
age :: Integer
}
deriving (Eq, Show, Read, Generic, ToJSON )
instance FromJSON Person where
parseJSON (Object v) = p <$> n <*> s <*> w <*> acc <*> a
where p = Person
n = v .: "name"
s = v .: "surname"
w = v .: "workPlace"
acc = v .: "accountBalance"
a = v .: "age"
-- A non-Object value is of the wrong type, so fail.
parseJSON _ = mzero
先谢谢了。
答案 0 :(得分:0)
我目前面临的问题是如何从JSON中提取这些数据并将其插入数据库。
那是两个独立的问题。
您有一个用于类型的<input type="text" id="txt">
<button id="add">Add</button>
<ul id="list">
<li>Select me and click Remove</li>
<li>I'm another to-do item</li>
</ul>
<script src="//code.jquery.com/jquery-3.1.1.min.js"></script>
实例,因此您所要做的就是FromJSON
或decode
来将JSON解析为eitherDecode
类型:< / p>
Person
您尚未选择sqlite库。选择一个并阅读使用方法。我选择了sqlite-simple,它可以这样使用:
case eitherDecode person_json of
Left err -> error err
Right person -> insertPersonIntoDB person
稍后,您在评论中说:
我需要将json中的值分配给变量
这就是解码的作用,它将JSON解析为Person值,并且通过在Person上进行模式匹配,我们可以获得每个JSON字段的变量。例如:
do
conn <- open "test.db"
execute_ conn "CREATE TABLE IF NOT EXISTS people\
\ (name TEXT, surname TEXT, workPlace TEXT,\
\ accountBalance INTEGER, age INTEGER)"
execute conn "INSERT INTO people \
\(name,surname,workPlace,accountBalance,age)\
\ VALUES (?,?,?,?,?)"
(name,surname,workPlace,accountBalance,age)
close conn
所以我可以将存储在这些变量中的值插入数据库中
是的,一旦有了变量名,或者只有一个printPersonTuple (Person nm sur wk acct years) =
print (nm,sur,wk,acct,years)
实例(请阅读sqlite-simple文档),就可以将值插入数据库。
我的问题是,每当我尝试将json转换为对象时,我都会使用IO()格式
那是一个与您的问题完全不同的问题。如果您感到困惑,请将其发布为另一个问题。
结论
您似乎遇到了一些问题,例如了解IO,将问题分解为子组件,在解析后使用值,选择和添加数据库库。请参见下面的完整示例,但鉴于要学习的东西列表,它可能不会完全阐明-请不要跟进此问题,而应将其作为与该答案分开的新问题而不是对此答案的评论。
ToRow
结果如下:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
import GHC.Generics -- So you can derive 'Generic'
import Data.Aeson -- JSON
import Database.SQLite.Simple -- Databse ops
import Data.Text (Text,unpack)
import qualified Data.ByteString.Lazy.Char8 as BC -- Just for prettier debugging
-- The type you are receiving from JSON
data Person = Person
{ name :: Text
, surname :: Text
, workPlace :: Text
, accountBalance :: Integer
, age :: Integer
}
deriving (Eq, Show, Read, Generic, FromJSON, ToJSON )
-- To/FromJSON are autogenerated JSON encode/decode instances
-- Auto-convert database rows into Person types for queries
instance FromRow Person where
fromRow = Person <$> field <*> field <*> field <*> field <*> field
-- An expensive "insert" operation
-- Open a DB connection, create a table (maybe), insert the value, close the
-- connection
insertPersonIntoDB :: Person -> IO ()
insertPersonIntoDB (Person {..}) =
do conn <- open "test.db"
execute_ conn "CREATE TABLE IF NOT EXISTS people (name TEXT, surname TEXT, workPlace TEXT, accountBalance INTEGER, age INTEGER)"
execute conn "INSERT INTO people (name,surname,workPlace,accountBalance,age) VALUES (?,?,?,?,?)" (name,surname,workPlace,accountBalance,age)
close conn
-- A simple test to print out the whole table
printDB :: IO ()
printDB =
do conn <- open "test.db"
res <- query_ conn "SELECT * FROM people" :: IO [Person]
putStrLn (unlines (map show res))
close conn
-- Glue it all together by
-- 1. Make the json 2. parse the json 3. insert to DB 4. print entire DB
main :: IO ()
main =
do let person_json = encode (Person "Tom" "MD" "Galois" (floor 1e9) 4)
putStrLn $ "JSON: " ++ BC.unpack person_json
case eitherDecode person_json of
Left err -> error err
Right person -> insertPersonIntoDB person
putStrLn "----- Database -----"
printDB