Haskell sqlite3 json

时间:2018-12-14 21:22:02

标签: json sqlite haskell

我试图创建一个简单的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

先谢谢了。

1 个答案:

答案 0 :(得分:0)

  

我目前面临的问题是如何从JSON中提取这些数据并将其插入数据库。

那是两个独立的问题。

  1. 您有一个用于类型的<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>实例,因此您所要做的就是FromJSONdecode来将JSON解析为eitherDecode类型:< / p>

    Person
  2. 您尚未选择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