2

我是haskell的新手,真的很难过。但这扩展了我的想法,所以我们开始吧。我正在尝试运行一个非常简单的 Web 服务器来查询 Postgres DB 并应将结果作为 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上找到

我希望有人有时间在这里帮助我。感谢您的阅读。

4

2 回答 2

5

该错误基本上说的是您不能将Inttoquery作为第三个参数传递。query期望具有类型类实例但不是一个实例的ToRow东西。Int考虑到您只想将一个值传递query给使用,您可能想做的事情是使用Only. 所以那行变成:

query conn  "select id,data from envelope where id = ?" (Only (eid :: Int))
于 2017-02-23T19:31:27.063 回答
1

基于 sopis 的帮助,我还在 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])

完毕。

于 2017-02-24T08:28:43.160 回答