如何在IHP脚本中重用IHP类?

问题描述

使用IHP(haskell Web框架),我创建了一个Web应用程序。现在,我想创建一个IHP脚本,以将一些外部数据加载到数据库中。但是我从Prelude中收到很多导入冲突,但不是我期望的类型。

#!/usr/bin/env run-script
module Application.Script.DataLoader where

import Application.Script.Prelude      hiding (decode,pack,(.:))
import qualified Data.ByteString.Lazy  as     BL
import Data.Csv
import Data.Text                              (pack)
import qualified Data.Vector           as     V
import Control.Monad                          (mzero)

instance FromNamedRecord Product where
    parseNamedRecord r = Product def <$> r .: "title" <*> r .: "price" <*> r .: "category" <*> pure def

run :: Script
run = do
    csvData <- BL.readFile "~/tender/data/Boiler-en-kookkraan_Boiler.csv"
    case decodeByName csvData of
        Left err -> putStrLn $ pack err
        Right (_,v) -> V.forM_ v $ \ p ->
            putStrLn $ (get #title p) ++ "," ++ show (get #price p) ++ " euro"

我的Product模式如下:

CREATE TABLE products (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,title TEXT NOT NULL,price DOUBLE PRECISION NOT NULL,category TEXT NOT NULL
);

有没有一种方法可以将我创建为数据对象的类型用于例如读我的csv到?

[更新后的输出]

Application/Script/DataLoader.hs:12:26: error:
    • Couldn't match type ‘MetaBag -> Product' a1’
                     with ‘Product' (QueryBuilder ProjectProduct)’
      Expected type: Parser Product
        Actual type: Parser (MetaBag -> Product' a1)
    • In the expression:
        Product def <$> r .: "title" <*> r .: "price" <*> r .: "category"
          <*> pure def
      In an equation for ‘parseNamedRecord’:
          parseNamedRecord r
            = Product def <$> r .: "title" <*> r .: "price" <*> r .: "category"
                <*> pure def
      In the instance declaration for ‘FromNamedRecord Product’
   |
12 |     parseNamedRecord r = Product def <$> r .: "title" <*> r .: "price" <*> r .: "category" <*> pure def
   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

[已解决,所有功劳都归于@mpscholten的帮助]

#!/usr/bin/env run-script
module Application.Script.DataLoader where

import Application.Script.Prelude      hiding (decode,(.:))
import qualified Data.ByteString.Lazy  as     BL
import Data.Csv
import Data.Text                              (pack)
import qualified Data.Vector           as     V
import Control.Monad                          (mzero)

parseProduct :: NamedRecord -> Parser Product
parseProduct r = do
  title <- r .: "title"
  price <- r .: "price"
  category <- r .: "category"

  newRecord @Product
    |> set #title title
    |> set #price price
    |> set #category category
    |> pure

run :: Script
run = do
    csvData <- BL.readFile "data/Boiler-en-kookkraan_Boiler.csv"
    case decodeByNameWithP parseProduct defaultDecodeOptions csvData of
        Left err -> putStrLn $ pack err
        Right (_," ++ show (get #price p) ++ " euro"

解决方法

您能否分享您确切遇到的错误?您所需的产品类型应位于Generated.Types加载的实习生中的Application.Script.Prelude中。

我认为您可能有两个都有字段标题的模型。在haskell字段中是函数,它们不能重复使用。

,

FromNamedRecord实例中,您缺少两个字段:idmetaid字段是记录的第一个字段。 meta字段是IHP使用的隐藏字段,用于跟踪验证错误。它始终是记录的最后一个字段。

解决此问题的最简单方法是使用newRecord并以更明确的方式写出代码:

instance FromNamedRecord Product where
    parseNamedRecord r = do
        title <- r .: "title"
        price <- r .: "price"
        category <- r .: "category"

        newRecord @Product
            |> set #title title
            |> set #price price
            |> set #category category
            |> pure

对于错误“歧义出现”标题”,请尝试使用get函数,而不要使用常规的haskell访问器函数:

putStrLn $ (get #title p) ++ "," ++ show (get #price p) ++ " euro"