Haskell sqlite3 json - PullRequest
       2

Haskell sqlite3 json

0 голосов
/ 15 декабря 2018

Я пытаюсь создать простое приложение на Haskell, которое получает данные из API и затем вставляет их в базу данных (sqlite3).Мне удалось успешно получить данные из моего API и создать базу данных.Однако проблема, с которой я сейчас сталкиваюсь, заключается в том, как извлечь эти данные из JSON и вставить их в базу данных.Я не могу поделиться всеми деталями, поэтому я изменил структуру типов (данных).Пример ответа API:

[{"name":"John","surname":"Terry","workPlace":"Bank","accountBalance":124344.08,"age":44}]

Тип данных Person и его экземпляр (для извлечения):

    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 голосов
/ 17 декабря 2018

Проблема, с которой я сейчас сталкиваюсь, заключается в том, как извлечь эти данные из JSON и вставить их в базу данных.

Это две отдельные проблемы.

  1. У вас есть FromJSON экземпляр для вашего типа, поэтому все, что вам нужно сделать, это decode или eitherDecode, чтобы проанализировать ваш JSON в тип Person:

     case eitherDecode person_json of
        Left err     -> error err
        Right person -> insertPersonIntoDB person
    
  2. Вы не выбрали библиотеку sqlite.Выберите один и прочитайте, как его использовать.Я выбрал sqlite-simple, который можно использовать следующим образом:

     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
    

Позже в комментарии вы сказали:

Мне нужно назначитьзначения от json до переменных

Это то, что делает декодирование, он анализирует JSON в значение Person, и путем сопоставления с шаблоном Person мы можем получить переменные для каждого поля JSON.Например:

printPersonTuple (Person nm sur wk acct years) =
    print (nm,sur,wk,acct,years)

, чтобы я мог вставить значения, хранящиеся в этих переменных, в базу данных

Да, если у вас есть имена переменных или просто ToRow instance (прочитайте sqlite-simple docs), затем вы можете вставить значение в базу данных.

И моя проблема в том, что всякий раз, когда я пытаюсь преобразовать json в объект, я получаю IO () format

Ну, это очень отдельная проблема из всего, что у вас в вопросе.Опубликуйте это как еще один вопрос, если вы в тупике.

Заключение

Похоже, у вас есть несколько проблем, таких как понимание ввода-вывода, разложение проблемы на подкомпоненты, использование значения послеРазбор, выбор и создание базы данных библиотеки.Пожалуйста, см. Ниже полный пример, но он, вероятно, не будет полностью освещен, учитывая этот список вещей для изучения - пожалуйста, задавайте последующие вопросы не как комментарии к этому ответу, а как свежие вопросы отдельно от этого.

{-# 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

И результат выглядит так:

% ghc so.hs
% ./so
JSON: {"accountBalance":1000000000,"age":4,"name":"Tom","workPlace":"Galois","surname":"MD"}
----- Database -----
Person {name = "Tom", surname = "MD", workPlace = "Galois", accountBalance = 1000000000, age = 4}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...