2017-02-23 6 views
1

私はhaskellを初めて使っていて正直に苦労しています。しかし、それは私の考えを広げるので、ここで私たちは行く。 私は、Postgres DBを照会し、結果をJSONとして返す本当にシンプルなWebサーバーを実行しようとしています。Haskell SpockとPostgres-Simple - クエリテーブルとjsonとしての返信

クエリは絶対に簡単です:「IDを選択し、ID = 1 MYTABLEからデータ」

しかし、Haskellの型システムは、今の私を殺して、自分の行動の最終型が一致しません。 。 私はSpockPostgreSQL-Simpleをコンボとして使用しています。

ほとんどのチュートリアルは、私がやりたいことや難しいことのために簡単なものです。私はどこかにいて、ハスケルの理解が不足しています。以前の多くの問題を単純なコピーと貼り付けで解決し、単純なバージョンの作業を得ました。

しかし、私がルート変数を渡そうとすると、私は失敗しています。 私の働くバージョンです。

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

それから私はそのために、私はまた、PostgreSQLの-シンプルを変更する必要があり、ラムダ関数と封筒IDを渡すために試してみてください。それはget "json"が言うところ私のデータベースの表は、ここでは、「エンベロープ」と呼ばれ、重要な呼び出しがあります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) 

私もちょうど最初の信奉を返すように問題を抱えていますmを照会から削除することができます。

完全なソースは、私は誰かがここで私を助けるために時間を持っている願っていますbitbucket

で見つけることができます。 既にお読みいただきありがとうございます。

答えて

3

基本的には、Intを第3引数としてqueryに渡すことができないということです。 queryは、型クラスToRowIntのインスタンスを持つものは1つではありません。 1つの値をqueryに渡したいと考えている場合は、Onlyを使用することをお勧めします。その行は次のようになります。

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

何ですか?結局のところ、思考の頭痛? ありがとうございます、それは動作します。私は非常に混乱しています。なぜなら2つのパラメータを単純に(parA:Int、parB:Int)することができますが、oneparamでは 'Only'表記をする必要があります。しかし、あなたが私にそれを指摘した後、私はPostgres-Simple Docsのそれについていくつかのコメントを見つけたので、後でそれを理解すると思います。 –

+0

この文脈では、 'Int'を列として、タプルを2つの列と' Only'を1つの列として持つ行と考えることができます。 'query'は行を扱うだけなので、列の中に列を置く必要があります。これは、sqlのinsert文で 'values'を使用するのと少し似ています。あなたは1を渡すことはできません。あなたは 'values(1)'または 'select 1'を必要とします。 – soupi

+0

今より意味があります。ありがとう。 –

1

スープスのヘルプに基づいて、対応する部分もPostgres-Simpleドキュメントにあります。完了のためだけに、ドキュメントにはシングルトンリストを使用した別の構文が記載されています。だからではなく、通常のブラケットを使用してのあなたは、単に角括弧を使用することができますし、それはあまりにも動作します:

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

また、私の例では特に、それがどのそして、その結果から、最初の行だけを返すために、より理にかなっていますhead機能で単純にまっすぐであることが判明しました。

スポックとプレリュードの両方にhead機能が含まれています。競合を避けるために、私はSpockの機能を隠すことを決めました。

は、上部にスクリプトに追加します。

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]) 

関連する問題