簡體   English   中英

postgres-simple - 沒有因使用“查詢”而產生的 (ToRow Int) 實例

[英]postgres-simple - No instance for (ToRow Int) arising from a use of ‘query’

我是 Haskell 的新手,老實說,我遇到了困難。 但它擴展了我的想法,所以我們走了。 我正在嘗試運行一個非常簡單的 Web 服務器,它查詢 Postgres 數據庫並應將結果作為 JSON 返回。

查詢非常簡單:“Select id,data from MYTABLE where id = 1”

但是 haskell 的類型系統現在正在殺死我,我的行為的最終類型不匹配。 我使用SpockPostgreSQL-Simple作為組合。

大多數教程對於我想要做的事情來說要么很簡單,要么很困難。 我介於兩者之間,錯過了很多對 Haskell 的理解,我之前的很多問題我已經通過簡單的復制和粘貼解決了,並且得到了一個簡單的版本。

但是一旦我嘗試傳遞路由變量,我就會失敗。 這是我的工作版本。 我的數據庫表在這里稱為“信封”,重要的調用是它說get "json"

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}

module Main where

import Web.Spock
import Web.Spock.Config
import Database.PostgreSQL.Simple
import Data.Pool
import Data.Aeson (ToJSON(toJSON), object, (.=),Value)
import  Database.PostgreSQL.Simple.FromRow

type AppAction a = SpockActionCtx () Connection AppSession AppState a

data AppState = EmptyState
data AppSession = EmptySession

data Envelope = Envelope { envId :: Int, envData :: Value } deriving Show

instance FromRow Envelope where
  fromRow = Envelope <$> field <*> field

instance ToJSON Envelope where
   toJSON (Envelope envA envB) = object [ "id" .= envA, "data" .= envB ]

main :: IO ()
main =
  do pool<-createPool (connect (ConnectInfo "localhost" 5432 "" "" "envelopes") ) close 1 10 10
     spockCfg <- defaultSpockCfg EmptySession (PCPool pool) EmptyState
     runSpock 8080 (spock spockCfg app)

app :: SpockM Connection AppSession AppState ()
app = do 
    get root $
      text "Hello World!"
    get "json" $ do
      xs<-runQuery $ \conn -> 
        query_ conn  "select id,data from envelope where id = 1"
      json (xs::[Envelope])

然后我嘗試使用 lambda 函數傳遞信封 ID,為此我還需要將 PostgreSQL-Simple query_更改為query

    get ( "json" <//> var  ) $ \eid -> do
      xs<-runQuery $ \conn -> 
        query conn  "select id,data from envelope where id = ?" (eid :: Int)
      json (xs::[Envelope])

我得到的錯誤說:

 No instance for (ToRow Int) arising from a use of ‘query’
   In the expression:
      query conn "select id,data from envelope where id = ?" (eid :: Int)
    In the second argument of ‘($)’, namely
      ‘\ conn
         -> query
              conn "select id,data from envelope where id = ?" (eid :: Int)’
    In a stmt of a 'do' block:
      xs <- runQuery
            $ \ conn
                -> query
                     conn "select id,data from envelope where id = ?" (eid :: Int)

即使沒有 lambda 函數,我也無法僅從查詢中返回第一項。

可以在bitbucket上找到完整的源代碼

我希望有人有時間在這里幫助我。 感謝您的閱讀。

錯誤基本上是說您不能將Int作為第三個參數傳遞給query query需要具有類型類ToRow的實例的東西,而Int不是一個。 考慮到您只想將一個值傳遞給query ,您在這種情況下可能想要做的是使用Only 所以該行變為:

query conn  "select id,data from envelope where id = ?" (Only (eid :: Int))

基於soupis help,我還在Postgres-Simple 文檔中找到了相應的部分。 只是為了完成,文檔提到了使用單例列表的替代語法。 因此,您可以簡單地使用方括號而不是使用普通括號,它也可以工作:

query conn "select id,data from envelope where id = ?" [eid :: Int]

此外,特別是在我的示例中,只返回結果中的第一行更有意義,然后結果是直接使用head函數。 對於需要它的任何其他人,您可以這樣做:

Spock 和 Prelude 都包含head功能。 為了避免沖突,我決定隱藏 Spocks 函數,因為我無論如何都沒有使用它。

在頂部添加到您的腳本:

import Web.Spock hiding(head)

然后將get部分更改為:

get ( "json" <//> var  ) $ \eid -> do
      xs<-runQuery $ \conn -> 
        query conn  "select id,data from envelope where id = ?" [eid :: Int]
      json $ head (xs::[Envelope])

完畢。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM