Skip to content

Instantly share code, notes, and snippets.

@begriffs
Created January 23, 2016 22:08
Show Gist options
  • Select an option

  • Save begriffs/c0e728ae297fffe8638e to your computer and use it in GitHub Desktop.

Select an option

Save begriffs/c0e728ae297fffe8638e to your computer and use it in GitHub Desktop.
A stash I have laying around that tries to use a db pool for tests
diff --git a/test/Feature/AuthSpec.hs b/test/Feature/AuthSpec.hs
index f678ae2..6f7d8bb 100644
--- a/test/Feature/AuthSpec.hs
+++ b/test/Feature/AuthSpec.hs
@@ -6,13 +6,14 @@ import Test.Hspec.Wai
import Test.Hspec.Wai.JSON
import Network.HTTP.Types
import qualified Hasql.Connection as H
+import Data.Pool
import SpecHelper
import PostgREST.Types (DbStructure(..))
-- }}}
-spec :: DbStructure -> H.Connection -> Spec
-spec struct c = around (withApp cfgDefault struct c)
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
+spec struct pool = around (withApp cfgDefault struct pool)
$ describe "authorization" $ do
it "hides tables that anonymous does not own" $
diff --git a/test/Feature/CorsSpec.hs b/test/Feature/CorsSpec.hs
index 811af71..eea9993 100644
--- a/test/Feature/CorsSpec.hs
+++ b/test/Feature/CorsSpec.hs
@@ -6,6 +6,7 @@ import Test.Hspec.Wai
import Network.Wai.Test (SResponse(simpleHeaders, simpleBody))
import qualified Data.ByteString.Lazy as BL
import qualified Hasql.Connection as H
+import Data.Pool
import SpecHelper
import PostgREST.Types (DbStructure(..))
@@ -13,7 +14,7 @@ import PostgREST.Types (DbStructure(..))
import Network.HTTP.Types
-- }}}
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c = around (withApp cfgDefault struct c) $ describe "CORS" $ do
let preflightHeaders = [
("Accept", "*/*"),
diff --git a/test/Feature/DeleteSpec.hs b/test/Feature/DeleteSpec.hs
index ba9c60e..e2d4a62 100644
--- a/test/Feature/DeleteSpec.hs
+++ b/test/Feature/DeleteSpec.hs
@@ -7,10 +7,11 @@ import Text.Heredoc
import SpecHelper
import PostgREST.Types (DbStructure(..))
import qualified Hasql.Connection as H
+import Data.Pool
import Network.HTTP.Types
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c = beforeAll resetDb
. around (withApp cfgDefault struct c) $
describe "Deleting" $ do
diff --git a/test/Feature/InsertSpec.hs b/test/Feature/InsertSpec.hs
index cba8d44..71a92b0 100644
--- a/test/Feature/InsertSpec.hs
+++ b/test/Feature/InsertSpec.hs
@@ -10,6 +10,7 @@ import PostgREST.Types (DbStructure(..))
import qualified Data.Aeson as JSON
import Data.Maybe (fromJust)
+import Data.Pool
import Text.Heredoc
import Network.HTTP.Types.Header
import Network.HTTP.Types
@@ -18,7 +19,7 @@ import qualified Hasql.Connection as H
import TestTypes(IncPK(..), CompoundPK(..))
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c = beforeAll_ resetDb $ around (withApp cfgDefault struct c) $ do
describe "Posting new record" $ do
context "disparate csv types" $ do
diff --git a/test/Feature/QueryLimitedSpec.hs b/test/Feature/QueryLimitedSpec.hs
index 71e6aa7..5ba81e6 100644
--- a/test/Feature/QueryLimitedSpec.hs
+++ b/test/Feature/QueryLimitedSpec.hs
@@ -6,11 +6,12 @@ import Test.Hspec.Wai.JSON
import Network.HTTP.Types
import Network.Wai.Test (SResponse(simpleHeaders, simpleStatus))
import qualified Hasql.Connection as H
+import Data.Pool
import SpecHelper
import PostgREST.Types (DbStructure(..))
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c =
beforeAll resetDb
. around (withApp (cfgLimitRows 3) struct c) $
diff --git a/test/Feature/QuerySpec.hs b/test/Feature/QuerySpec.hs
index 4de2b60..913879e 100644
--- a/test/Feature/QuerySpec.hs
+++ b/test/Feature/QuerySpec.hs
@@ -6,21 +6,22 @@ import Test.Hspec.Wai.JSON
import Network.HTTP.Types
import Network.Wai.Test (SResponse(simpleHeaders))
import qualified Hasql.Connection as H
+import Data.Pool
import SpecHelper
import PostgREST.Types (DbStructure(..))
import Text.Heredoc
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c = around (withApp cfgDefault struct c) $ do
- describe "Querying a table with a column called count" $
- it "should not confuse count column with pg_catalog.count aggregate" $
- get "/has_count_column" `shouldRespondWith` 200
+ -- describe "Querying a table with a column called count" $
+ -- it "should not confuse count column with pg_catalog.count aggregate" $
+ -- get "/has_count_column" `shouldRespondWith` 200
- describe "Querying a nonexistent table" $
- it "causes a 404" $
- get "/faketable" `shouldRespondWith` 404
+ -- describe "Querying a nonexistent table" $
+ -- it "causes a 404" $
+ -- get "/faketable" `shouldRespondWith` 404
describe "Filtering response" $ do
it "matches with equality" $
@@ -39,364 +40,364 @@ spec struct c = around (withApp cfgDefault struct c) $ do
, matchHeaders = ["Content-Range" <:> "0-13/14"]
}
- it "matches with more than one condition using not operator" $
- get "/simple_pk?k=like.*yx&extra=not.eq.u" `shouldRespondWith` "[]"
-
- it "matches with inequality using not operator" $ do
- get "/items?id=not.lt.14&order=id.asc"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":14},{"id":15}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-1/2"]
- }
- get "/items?id=not.gt.2&order=id.asc"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":1},{"id":2}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-1/2"]
- }
-
- it "matches items IN" $
- get "/items?id=in.1,3,5"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":1},{"id":3},{"id":5}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-2/3"]
- }
-
- it "matches items NOT IN" $
- get "/items?id=notin.2,4,6,7,8,9,10,11,12,13,14,15"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":1},{"id":3},{"id":5}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-2/3"]
- }
-
- it "matches items NOT IN using not operator" $
- get "/items?id=not.in.2,4,6,7,8,9,10,11,12,13,14,15"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":1},{"id":3},{"id":5}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-2/3"]
- }
-
- it "matches nulls using not operator" $
- get "/no_pk?a=not.is.null" `shouldRespondWith`
- [json| [{"a":"1","b":"0"},{"a":"2","b":"0"}] |]
-
- it "matches nulls in varchar and numeric fields alike" $ do
- get "/no_pk?a=is.null" `shouldRespondWith`
- [json| [{"a": null, "b": null}] |]
-
- get "/nullable_integer?a=is.null" `shouldRespondWith` [str|[{"a":null}]|]
-
- it "matches with like" $ do
- get "/simple_pk?k=like.*yx" `shouldRespondWith`
- [str|[{"k":"xyyx","extra":"u"}]|]
- get "/simple_pk?k=like.xy*" `shouldRespondWith`
- [str|[{"k":"xyyx","extra":"u"}]|]
- get "/simple_pk?k=like.*YY*" `shouldRespondWith`
- [str|[{"k":"xYYx","extra":"v"}]|]
-
- it "matches with like using not operator" $
- get "/simple_pk?k=not.like.*yx" `shouldRespondWith`
- [str|[{"k":"xYYx","extra":"v"}]|]
-
- it "matches with ilike" $ do
- get "/simple_pk?k=ilike.xy*&order=extra.asc" `shouldRespondWith`
- [str|[{"k":"xyyx","extra":"u"},{"k":"xYYx","extra":"v"}]|]
- get "/simple_pk?k=ilike.*YY*&order=extra.asc" `shouldRespondWith`
- [str|[{"k":"xyyx","extra":"u"},{"k":"xYYx","extra":"v"}]|]
-
- it "matches with ilike using not operator" $
- get "/simple_pk?k=not.ilike.xy*&order=extra.asc" `shouldRespondWith` "[]"
-
- it "matches with tsearch @@" $
- get "/tsearch?text_search_vector=@@.foo" `shouldRespondWith`
- [json| [{"text_search_vector":"'bar':2 'foo':1"}] |]
-
- it "matches with tsearch @@ using not operator" $
- get "/tsearch?text_search_vector=not.@@.foo" `shouldRespondWith`
- [json| [{"text_search_vector":"'baz':1 'qux':2"}] |]
-
- it "matches with computed column" $
- get "/items?always_true=eq.true&order=id.asc" `shouldRespondWith`
- [json| [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}] |]
-
- it "order by computed column" $
- get "/items?order=anti_id.desc" `shouldRespondWith`
- [json| [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}] |]
-
- it "matches filtering nested items" $
- get "/clients?select=id,projects{id,tasks{id,name}}&projects.tasks.name=like.Design*" `shouldRespondWith`
- [str|[{"id":1,"projects":[{"id":1,"tasks":[{"id":1,"name":"Design w7"}]},{"id":2,"tasks":[{"id":3,"name":"Design w10"}]}]},{"id":2,"projects":[{"id":3,"tasks":[{"id":5,"name":"Design IOS"}]},{"id":4,"tasks":[{"id":7,"name":"Design OSX"}]}]}]|]
-
- it "matches with @> operator" $
- get "/complex_items?select=id&arr_data=@>.{2}" `shouldRespondWith`
- [str|[{"id":2},{"id":3}]|]
-
- it "matches with <@ operator" $
- get "/complex_items?select=id&arr_data=<@.{1,2,4}" `shouldRespondWith`
- [str|[{"id":1},{"id":2}]|]
-
-
- describe "Shaping response with select parameter" $ do
-
- it "selectStar works in absense of parameter" $
- get "/complex_items?id=eq.3" `shouldRespondWith`
- [str|[{"id":3,"name":"Three","settings":{"foo":{"int":1,"bar":"baz"}},"arr_data":[1,2,3]}]|]
-
- it "one simple column" $
- get "/complex_items?select=id" `shouldRespondWith`
- [json| [{"id":1},{"id":2},{"id":3}] |]
-
- it "one simple column with casting (text)" $
- get "/complex_items?select=id::text" `shouldRespondWith`
- [json| [{"id":"1"},{"id":"2"},{"id":"3"}] |]
-
- it "json column" $
- get "/complex_items?id=eq.1&select=settings" `shouldRespondWith`
- [json| [{"settings":{"foo":{"int":1,"bar":"baz"}}}] |]
-
- it "json subfield one level with casting (json)" $
- get "/complex_items?id=eq.1&select=settings->>foo::json" `shouldRespondWith`
- [json| [{"foo":{"int":1,"bar":"baz"}}] |] -- the value of foo here is of type "text"
-
- it "fails on bad casting (data of the wrong format)" $
- get "/complex_items?select=settings->foo->>bar::integer"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| {"hint":null,"details":null,"code":"22P02","message":"invalid input syntax for integer: \"baz\""} |]
- , matchStatus = 400
- , matchHeaders = []
- }
-
- it "fails on bad casting (wrong cast type)" $
- get "/complex_items?select=id::fakecolumntype"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| {"hint":null,"details":null,"code":"42704","message":"type \"fakecolumntype\" does not exist"} |]
- , matchStatus = 400
- , matchHeaders = []
- }
-
-
- it "json subfield two levels (string)" $
- get "/complex_items?id=eq.1&select=settings->foo->>bar" `shouldRespondWith`
- [json| [{"bar":"baz"}] |]
-
-
- it "json subfield two levels with casting (int)" $
- get "/complex_items?id=eq.1&select=settings->foo->>int::integer" `shouldRespondWith`
- [json| [{"int":1}] |] -- the value in the db is an int, but here we expect a string for now
-
- it "requesting parents and children" $
- get "/projects?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith`
- [str|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}]|]
-
- it "requesting parents and filtering parent columns" $
- get "/projects?id=eq.1&select=id, name, clients{id}" `shouldRespondWith`
- [str|[{"id":1,"name":"Windows 7","clients":{"id":1}}]|]
-
- it "rows with missing parents are included" $
- get "/projects?id=in.1,5&select=id,clients{id}" `shouldRespondWith`
- [str|[{"id":1,"clients":{"id":1}},{"id":5,"clients":null}]|]
-
- it "rows with no children return [] instead of null" $
- get "/projects?id=in.5&select=id,tasks{id}" `shouldRespondWith`
- [str|[{"id":5,"tasks":[]}]|]
-
- it "requesting children 2 levels" $
- get "/clients?id=eq.1&select=id,projects{id,tasks{id}}" `shouldRespondWith`
- [str|[{"id":1,"projects":[{"id":1,"tasks":[{"id":1},{"id":2}]},{"id":2,"tasks":[{"id":3},{"id":4}]}]}]|]
-
- it "requesting many<->many relation" $
- get "/tasks?select=id,users{id}" `shouldRespondWith`
- [str|[{"id":1,"users":[{"id":1},{"id":3}]},{"id":2,"users":[{"id":1}]},{"id":3,"users":[{"id":1}]},{"id":4,"users":[{"id":1}]},{"id":5,"users":[{"id":2},{"id":3}]},{"id":6,"users":[{"id":2}]},{"id":7,"users":[{"id":2}]},{"id":8,"users":[]}]|]
-
-
- it "requesting many<->many relation reverse" $
- get "/users?select=id,tasks{id}" `shouldRespondWith`
- [str|[{"id":1,"tasks":[{"id":1},{"id":2},{"id":3},{"id":4}]},{"id":2,"tasks":[{"id":5},{"id":6},{"id":7}]},{"id":3,"tasks":[{"id":1},{"id":5}]}]|]
-
- it "requesting parents and children on views" $
- get "/projects_view?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith`
- [str|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}]|]
-
- it "requesting children with composite key" $
- get "/users_tasks?user_id=eq.2&task_id=eq.6&select=*, comments{content}" `shouldRespondWith`
- [str|[{"user_id":2,"task_id":6,"comments":[{"content":"Needs to be delivered ASAP"}]}]|]
-
- it "detect relations in views from exposed schema that are based on tables in private schema and have columns renames" $
- get "/articles?id=eq.1&select=id,articleStars{users{*}}" `shouldRespondWith`
- [str|[{"id":1,"articleStars":[{"users":{"id":1,"name":"Angela Martin"}},{"users":{"id":2,"name":"Michael Scott"}},{"users":{"id":3,"name":"Dwight Schrute"}}]}]|]
-
- it "can select by column name" $
- get "/projects?id=in.1,3&select=id,name,client_id,client_id{id,name}" `shouldRespondWith`
- [str|[{"id":1,"name":"Windows 7","client_id":1,"client_id":{"id":1,"name":"Microsoft"}},{"id":3,"name":"IOS","client_id":2,"client_id":{"id":2,"name":"Apple"}}]|]
-
- it "can select by column name sans id" $
- get "/projects?id=in.1,3&select=id,name,client_id,client{id,name}" `shouldRespondWith`
- [str|[{"id":1,"name":"Windows 7","client_id":1,"client":{"id":1,"name":"Microsoft"}},{"id":3,"name":"IOS","client_id":2,"client":{"id":2,"name":"Apple"}}]|]
-
-
- describe "Plurality singular" $ do
- it "will select an existing object" $
- request methodGet "/items?id=eq.5" [("Prefer","plurality=singular")] ""
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| {"id":5} |]
- , matchStatus = 200
- , matchHeaders = []
- }
-
- it "works in the presence of a range header" $
- let headers = ("Prefer","plurality=singular") :
- rangeHdrs (ByteRangeFromTo 0 9) in
- request methodGet "/items" headers ""
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| {"id":1} |]
- , matchStatus = 200
- , matchHeaders = []
- }
-
- it "will respond with 404 when not found" $
- request methodGet "/items?id=eq.9999" [("Prefer","plurality=singular")] ""
- `shouldRespondWith` 404
-
- it "can shape plurality singular object routes" $
- request methodGet "/projects_view?id=eq.1&select=id,name,clients{*},tasks{id,name}" [("Prefer","plurality=singular")] ""
- `shouldRespondWith`
- [str|{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}|]
-
-
- describe "ordering response" $ do
- it "by a column asc" $
- get "/items?id=lte.2&order=id.asc"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":1},{"id":2}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-1/2"]
- }
- it "by a column desc" $
- get "/items?id=lte.2&order=id.desc"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"id":2},{"id":1}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-1/2"]
- }
-
- it "by a column asc with nulls last" $
- get "/no_pk?order=a.asc.nullslast"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"a":"1","b":"0"},
- {"a":"2","b":"0"},
- {"a":null,"b":null}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-2/3"]
- }
-
- it "by a column desc with nulls first" $
- get "/no_pk?order=a.desc.nullsfirst"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"a":null,"b":null},
- {"a":"2","b":"0"},
- {"a":"1","b":"0"}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-2/3"]
- }
-
- it "by a column desc with nulls last" $
- get "/no_pk?order=a.desc.nullslast"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just [json| [{"a":"2","b":"0"},
- {"a":"1","b":"0"},
- {"a":null,"b":null}] |]
- , matchStatus = 200
- , matchHeaders = ["Content-Range" <:> "0-2/3"]
- }
-
- it "without other constraints" $
- get "/items?order=id.asc" `shouldRespondWith` 200
-
- describe "Accept headers" $ do
- it "should respond an unknown accept type with 415" $
- request methodGet "/simple_pk"
- (acceptHdrs "text/unknowntype") ""
- `shouldRespondWith` 415
-
- it "should respond correctly to */* in accept header" $
- request methodGet "/simple_pk"
- (acceptHdrs "*/*") ""
- `shouldRespondWith` 200
-
- it "should respond correctly to multiple types in accept header" $
- request methodGet "/simple_pk"
- (acceptHdrs "text/unknowntype, text/csv") ""
- `shouldRespondWith` 200
-
- it "should respond with CSV to 'text/csv' request" $
- request methodGet "/simple_pk"
- (acceptHdrs "text/csv; version=1") ""
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just "k,extra\nxyyx,u\nxYYx,v"
- , matchStatus = 200
- , matchHeaders = ["Content-Type" <:> "text/csv"]
- }
-
- describe "Canonical location" $ do
- it "Sets Content-Location with alphabetized params" $
- get "/no_pk?b=eq.1&a=eq.1"
- `shouldRespondWith` ResponseMatcher {
- matchBody = Just "[]"
- , matchStatus = 200
- , matchHeaders = ["Content-Location" <:> "/no_pk?a=eq.1&b=eq.1"]
- }
-
- it "Omits question mark when there are no params" $ do
- r <- get "/simple_pk"
- liftIO $ do
- let respHeaders = simpleHeaders r
- respHeaders `shouldSatisfy` matchHeader
- "Content-Location" "/simple_pk"
-
- describe "jsonb" $ do
- it "can filter by properties inside json column" $ do
- get "/json?data->foo->>bar=eq.baz" `shouldRespondWith`
- [json| [{"data": {"id": 1, "foo": {"bar": "baz"}}}] |]
- get "/json?data->foo->>bar=eq.fake" `shouldRespondWith`
- [json| [] |]
- it "can filter by properties inside json column using not" $
- get "/json?data->foo->>bar=not.eq.baz" `shouldRespondWith`
- [json| [] |]
- it "can filter by properties inside json column using ->>" $
- get "/json?data->>id=eq.1" `shouldRespondWith`
- [json| [{"data": {"id": 1, "foo": {"bar": "baz"}}}] |]
-
- describe "remote procedure call" $ do
- context "a proc that returns a set" $
- it "returns proper json" $
- post "/rpc/getitemrange" [json| { "min": 2, "max": 4 } |] `shouldRespondWith`
- [json| [ {"id": 3}, {"id":4} ] |]
-
- context "a proc that returns an empty rowset" $
- it "returns empty json array" $
- post "/rpc/test_empty_rowset" [json| {} |] `shouldRespondWith`
- [json| [] |]
-
- context "a proc that returns plain text" $
- it "returns proper json" $
- post "/rpc/sayhello" [json| { "name": "world" } |] `shouldRespondWith`
- [json| [{"sayhello":"Hello, world"}] |]
-
- describe "weird requests" $ do
- it "can query as normal" $ do
- get "/Escap3e;" `shouldRespondWith`
- [json| [{"so6meIdColumn":1},{"so6meIdColumn":2},{"so6meIdColumn":3},{"so6meIdColumn":4},{"so6meIdColumn":5}] |]
- get "/ghostBusters" `shouldRespondWith`
- [json| [{"escapeId":1},{"escapeId":3},{"escapeId":5}] |]
-
- it "will embed a collection" $
- get "/Escap3e;?select=ghostBusters{*}" `shouldRespondWith`
- [json| [{"ghostBusters":[{"escapeId":1}]},{"ghostBusters":[]},{"ghostBusters":[{"escapeId":3}]},{"ghostBusters":[]},{"ghostBusters":[{"escapeId":5}]}] |]
-
- it "will embed using a column" $
- get "/ghostBusters?select=escapeId{*}" `shouldRespondWith`
- [json| [{"escapeId":{"so6meIdColumn":1}},{"escapeId":{"so6meIdColumn":3}},{"escapeId":{"so6meIdColumn":5}}] |]
+ -- it "matches with more than one condition using not operator" $
+ -- get "/simple_pk?k=like.*yx&extra=not.eq.u" `shouldRespondWith` "[]"
+
+ -- it "matches with inequality using not operator" $ do
+ -- get "/items?id=not.lt.14&order=id.asc"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":14},{"id":15}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-1/2"]
+ -- }
+ -- get "/items?id=not.gt.2&order=id.asc"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":1},{"id":2}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-1/2"]
+ -- }
+
+ -- it "matches items IN" $
+ -- get "/items?id=in.1,3,5"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":1},{"id":3},{"id":5}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-2/3"]
+ -- }
+
+ -- it "matches items NOT IN" $
+ -- get "/items?id=notin.2,4,6,7,8,9,10,11,12,13,14,15"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":1},{"id":3},{"id":5}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-2/3"]
+ -- }
+
+ -- it "matches items NOT IN using not operator" $
+ -- get "/items?id=not.in.2,4,6,7,8,9,10,11,12,13,14,15"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":1},{"id":3},{"id":5}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-2/3"]
+ -- }
+
+ -- it "matches nulls using not operator" $
+ -- get "/no_pk?a=not.is.null" `shouldRespondWith`
+ -- [json| [{"a":"1","b":"0"},{"a":"2","b":"0"}] |]
+
+ -- it "matches nulls in varchar and numeric fields alike" $ do
+ -- get "/no_pk?a=is.null" `shouldRespondWith`
+ -- [json| [{"a": null, "b": null}] |]
+
+ -- get "/nullable_integer?a=is.null" `shouldRespondWith` [str|[{"a":null}]|]
+
+ -- it "matches with like" $ do
+ -- get "/simple_pk?k=like.*yx" `shouldRespondWith`
+ -- [str|[{"k":"xyyx","extra":"u"}]|]
+ -- get "/simple_pk?k=like.xy*" `shouldRespondWith`
+ -- [str|[{"k":"xyyx","extra":"u"}]|]
+ -- get "/simple_pk?k=like.*YY*" `shouldRespondWith`
+ -- [str|[{"k":"xYYx","extra":"v"}]|]
+
+ -- it "matches with like using not operator" $
+ -- get "/simple_pk?k=not.like.*yx" `shouldRespondWith`
+ -- [str|[{"k":"xYYx","extra":"v"}]|]
+
+ -- it "matches with ilike" $ do
+ -- get "/simple_pk?k=ilike.xy*&order=extra.asc" `shouldRespondWith`
+ -- [str|[{"k":"xyyx","extra":"u"},{"k":"xYYx","extra":"v"}]|]
+ -- get "/simple_pk?k=ilike.*YY*&order=extra.asc" `shouldRespondWith`
+ -- [str|[{"k":"xyyx","extra":"u"},{"k":"xYYx","extra":"v"}]|]
+
+ -- it "matches with ilike using not operator" $
+ -- get "/simple_pk?k=not.ilike.xy*&order=extra.asc" `shouldRespondWith` "[]"
+
+ -- it "matches with tsearch @@" $
+ -- get "/tsearch?text_search_vector=@@.foo" `shouldRespondWith`
+ -- [json| [{"text_search_vector":"'bar':2 'foo':1"}] |]
+
+ -- it "matches with tsearch @@ using not operator" $
+ -- get "/tsearch?text_search_vector=not.@@.foo" `shouldRespondWith`
+ -- [json| [{"text_search_vector":"'baz':1 'qux':2"}] |]
+
+ -- it "matches with computed column" $
+ -- get "/items?always_true=eq.true&order=id.asc" `shouldRespondWith`
+ -- [json| [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}] |]
+
+ -- it "order by computed column" $
+ -- get "/items?order=anti_id.desc" `shouldRespondWith`
+ -- [json| [{"id":1},{"id":2},{"id":3},{"id":4},{"id":5},{"id":6},{"id":7},{"id":8},{"id":9},{"id":10},{"id":11},{"id":12},{"id":13},{"id":14},{"id":15}] |]
+
+ -- it "matches filtering nested items" $
+ -- get "/clients?select=id,projects{id,tasks{id,name}}&projects.tasks.name=like.Design*" `shouldRespondWith`
+ -- [str|[{"id":1,"projects":[{"id":1,"tasks":[{"id":1,"name":"Design w7"}]},{"id":2,"tasks":[{"id":3,"name":"Design w10"}]}]},{"id":2,"projects":[{"id":3,"tasks":[{"id":5,"name":"Design IOS"}]},{"id":4,"tasks":[{"id":7,"name":"Design OSX"}]}]}]|]
+
+ -- it "matches with @> operator" $
+ -- get "/complex_items?select=id&arr_data=@>.{2}" `shouldRespondWith`
+ -- [str|[{"id":2},{"id":3}]|]
+
+ -- it "matches with <@ operator" $
+ -- get "/complex_items?select=id&arr_data=<@.{1,2,4}" `shouldRespondWith`
+ -- [str|[{"id":1},{"id":2}]|]
+
+
+ -- describe "Shaping response with select parameter" $ do
+
+ -- it "selectStar works in absense of parameter" $
+ -- get "/complex_items?id=eq.3" `shouldRespondWith`
+ -- [str|[{"id":3,"name":"Three","settings":{"foo":{"int":1,"bar":"baz"}},"arr_data":[1,2,3]}]|]
+
+ -- it "one simple column" $
+ -- get "/complex_items?select=id" `shouldRespondWith`
+ -- [json| [{"id":1},{"id":2},{"id":3}] |]
+
+ -- it "one simple column with casting (text)" $
+ -- get "/complex_items?select=id::text" `shouldRespondWith`
+ -- [json| [{"id":"1"},{"id":"2"},{"id":"3"}] |]
+
+ -- it "json column" $
+ -- get "/complex_items?id=eq.1&select=settings" `shouldRespondWith`
+ -- [json| [{"settings":{"foo":{"int":1,"bar":"baz"}}}] |]
+
+ -- it "json subfield one level with casting (json)" $
+ -- get "/complex_items?id=eq.1&select=settings->>foo::json" `shouldRespondWith`
+ -- [json| [{"foo":{"int":1,"bar":"baz"}}] |] -- the value of foo here is of type "text"
+
+ -- it "fails on bad casting (data of the wrong format)" $
+ -- get "/complex_items?select=settings->foo->>bar::integer"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| {"hint":null,"details":null,"code":"22P02","message":"invalid input syntax for integer: \"baz\""} |]
+ -- , matchStatus = 400
+ -- , matchHeaders = []
+ -- }
+
+ -- it "fails on bad casting (wrong cast type)" $
+ -- get "/complex_items?select=id::fakecolumntype"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| {"hint":null,"details":null,"code":"42704","message":"type \"fakecolumntype\" does not exist"} |]
+ -- , matchStatus = 400
+ -- , matchHeaders = []
+ -- }
+
+
+ -- it "json subfield two levels (string)" $
+ -- get "/complex_items?id=eq.1&select=settings->foo->>bar" `shouldRespondWith`
+ -- [json| [{"bar":"baz"}] |]
+
+
+ -- it "json subfield two levels with casting (int)" $
+ -- get "/complex_items?id=eq.1&select=settings->foo->>int::integer" `shouldRespondWith`
+ -- [json| [{"int":1}] |] -- the value in the db is an int, but here we expect a string for now
+
+ -- it "requesting parents and children" $
+ -- get "/projects?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith`
+ -- [str|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}]|]
+
+ -- it "requesting parents and filtering parent columns" $
+ -- get "/projects?id=eq.1&select=id, name, clients{id}" `shouldRespondWith`
+ -- [str|[{"id":1,"name":"Windows 7","clients":{"id":1}}]|]
+
+ -- it "rows with missing parents are included" $
+ -- get "/projects?id=in.1,5&select=id,clients{id}" `shouldRespondWith`
+ -- [str|[{"id":1,"clients":{"id":1}},{"id":5,"clients":null}]|]
+
+ -- it "rows with no children return [] instead of null" $
+ -- get "/projects?id=in.5&select=id,tasks{id}" `shouldRespondWith`
+ -- [str|[{"id":5,"tasks":[]}]|]
+
+ -- it "requesting children 2 levels" $
+ -- get "/clients?id=eq.1&select=id,projects{id,tasks{id}}" `shouldRespondWith`
+ -- [str|[{"id":1,"projects":[{"id":1,"tasks":[{"id":1},{"id":2}]},{"id":2,"tasks":[{"id":3},{"id":4}]}]}]|]
+
+ -- it "requesting many<->many relation" $
+ -- get "/tasks?select=id,users{id}" `shouldRespondWith`
+ -- [str|[{"id":1,"users":[{"id":1},{"id":3}]},{"id":2,"users":[{"id":1}]},{"id":3,"users":[{"id":1}]},{"id":4,"users":[{"id":1}]},{"id":5,"users":[{"id":2},{"id":3}]},{"id":6,"users":[{"id":2}]},{"id":7,"users":[{"id":2}]},{"id":8,"users":[]}]|]
+
+
+ -- it "requesting many<->many relation reverse" $
+ -- get "/users?select=id,tasks{id}" `shouldRespondWith`
+ -- [str|[{"id":1,"tasks":[{"id":1},{"id":2},{"id":3},{"id":4}]},{"id":2,"tasks":[{"id":5},{"id":6},{"id":7}]},{"id":3,"tasks":[{"id":1},{"id":5}]}]|]
+
+ -- it "requesting parents and children on views" $
+ -- get "/projects_view?id=eq.1&select=id, name, clients{*}, tasks{id, name}" `shouldRespondWith`
+ -- [str|[{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}]|]
+
+ -- it "requesting children with composite key" $
+ -- get "/users_tasks?user_id=eq.2&task_id=eq.6&select=*, comments{content}" `shouldRespondWith`
+ -- [str|[{"user_id":2,"task_id":6,"comments":[{"content":"Needs to be delivered ASAP"}]}]|]
+
+ -- it "detect relations in views from exposed schema that are based on tables in private schema and have columns renames" $
+ -- get "/articles?id=eq.1&select=id,articleStars{users{*}}" `shouldRespondWith`
+ -- [str|[{"id":1,"articleStars":[{"users":{"id":1,"name":"Angela Martin"}},{"users":{"id":2,"name":"Michael Scott"}},{"users":{"id":3,"name":"Dwight Schrute"}}]}]|]
+
+ -- it "can select by column name" $
+ -- get "/projects?id=in.1,3&select=id,name,client_id,client_id{id,name}" `shouldRespondWith`
+ -- [str|[{"id":1,"name":"Windows 7","client_id":1,"client_id":{"id":1,"name":"Microsoft"}},{"id":3,"name":"IOS","client_id":2,"client_id":{"id":2,"name":"Apple"}}]|]
+
+ -- it "can select by column name sans id" $
+ -- get "/projects?id=in.1,3&select=id,name,client_id,client{id,name}" `shouldRespondWith`
+ -- [str|[{"id":1,"name":"Windows 7","client_id":1,"client":{"id":1,"name":"Microsoft"}},{"id":3,"name":"IOS","client_id":2,"client":{"id":2,"name":"Apple"}}]|]
+
+
+ -- describe "Plurality singular" $ do
+ -- it "will select an existing object" $
+ -- request methodGet "/items?id=eq.5" [("Prefer","plurality=singular")] ""
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| {"id":5} |]
+ -- , matchStatus = 200
+ -- , matchHeaders = []
+ -- }
+
+ -- it "works in the presence of a range header" $
+ -- let headers = ("Prefer","plurality=singular") :
+ -- rangeHdrs (ByteRangeFromTo 0 9) in
+ -- request methodGet "/items" headers ""
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| {"id":1} |]
+ -- , matchStatus = 200
+ -- , matchHeaders = []
+ -- }
+
+ -- it "will respond with 404 when not found" $
+ -- request methodGet "/items?id=eq.9999" [("Prefer","plurality=singular")] ""
+ -- `shouldRespondWith` 404
+
+ -- it "can shape plurality singular object routes" $
+ -- request methodGet "/projects_view?id=eq.1&select=id,name,clients{*},tasks{id,name}" [("Prefer","plurality=singular")] ""
+ -- `shouldRespondWith`
+ -- [str|{"id":1,"name":"Windows 7","clients":{"id":1,"name":"Microsoft"},"tasks":[{"id":1,"name":"Design w7"},{"id":2,"name":"Code w7"}]}|]
+
+
+ -- describe "ordering response" $ do
+ -- it "by a column asc" $
+ -- get "/items?id=lte.2&order=id.asc"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":1},{"id":2}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-1/2"]
+ -- }
+ -- it "by a column desc" $
+ -- get "/items?id=lte.2&order=id.desc"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"id":2},{"id":1}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-1/2"]
+ -- }
+
+ -- it "by a column asc with nulls last" $
+ -- get "/no_pk?order=a.asc.nullslast"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"a":"1","b":"0"},
+ -- {"a":"2","b":"0"},
+ -- {"a":null,"b":null}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-2/3"]
+ -- }
+
+ -- it "by a column desc with nulls first" $
+ -- get "/no_pk?order=a.desc.nullsfirst"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"a":null,"b":null},
+ -- {"a":"2","b":"0"},
+ -- {"a":"1","b":"0"}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-2/3"]
+ -- }
+
+ -- it "by a column desc with nulls last" $
+ -- get "/no_pk?order=a.desc.nullslast"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just [json| [{"a":"2","b":"0"},
+ -- {"a":"1","b":"0"},
+ -- {"a":null,"b":null}] |]
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Range" <:> "0-2/3"]
+ -- }
+
+ -- it "without other constraints" $
+ -- get "/items?order=id.asc" `shouldRespondWith` 200
+
+ -- describe "Accept headers" $ do
+ -- it "should respond an unknown accept type with 415" $
+ -- request methodGet "/simple_pk"
+ -- (acceptHdrs "text/unknowntype") ""
+ -- `shouldRespondWith` 415
+
+ -- it "should respond correctly to */* in accept header" $
+ -- request methodGet "/simple_pk"
+ -- (acceptHdrs "*/*") ""
+ -- `shouldRespondWith` 200
+
+ -- it "should respond correctly to multiple types in accept header" $
+ -- request methodGet "/simple_pk"
+ -- (acceptHdrs "text/unknowntype, text/csv") ""
+ -- `shouldRespondWith` 200
+
+ -- it "should respond with CSV to 'text/csv' request" $
+ -- request methodGet "/simple_pk"
+ -- (acceptHdrs "text/csv; version=1") ""
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just "k,extra\nxyyx,u\nxYYx,v"
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Type" <:> "text/csv"]
+ -- }
+
+ -- describe "Canonical location" $ do
+ -- it "Sets Content-Location with alphabetized params" $
+ -- get "/no_pk?b=eq.1&a=eq.1"
+ -- `shouldRespondWith` ResponseMatcher {
+ -- matchBody = Just "[]"
+ -- , matchStatus = 200
+ -- , matchHeaders = ["Content-Location" <:> "/no_pk?a=eq.1&b=eq.1"]
+ -- }
+
+ -- it "Omits question mark when there are no params" $ do
+ -- r <- get "/simple_pk"
+ -- liftIO $ do
+ -- let respHeaders = simpleHeaders r
+ -- respHeaders `shouldSatisfy` matchHeader
+ -- "Content-Location" "/simple_pk"
+
+ -- describe "jsonb" $ do
+ -- it "can filter by properties inside json column" $ do
+ -- get "/json?data->foo->>bar=eq.baz" `shouldRespondWith`
+ -- [json| [{"data": {"id": 1, "foo": {"bar": "baz"}}}] |]
+ -- get "/json?data->foo->>bar=eq.fake" `shouldRespondWith`
+ -- [json| [] |]
+ -- it "can filter by properties inside json column using not" $
+ -- get "/json?data->foo->>bar=not.eq.baz" `shouldRespondWith`
+ -- [json| [] |]
+ -- it "can filter by properties inside json column using ->>" $
+ -- get "/json?data->>id=eq.1" `shouldRespondWith`
+ -- [json| [{"data": {"id": 1, "foo": {"bar": "baz"}}}] |]
+
+ -- describe "remote procedure call" $ do
+ -- context "a proc that returns a set" $
+ -- it "returns proper json" $
+ -- post "/rpc/getitemrange" [json| { "min": 2, "max": 4 } |] `shouldRespondWith`
+ -- [json| [ {"id": 3}, {"id":4} ] |]
+
+ -- context "a proc that returns an empty rowset" $
+ -- it "returns empty json array" $
+ -- post "/rpc/test_empty_rowset" [json| {} |] `shouldRespondWith`
+ -- [json| [] |]
+
+ -- context "a proc that returns plain text" $
+ -- it "returns proper json" $
+ -- post "/rpc/sayhello" [json| { "name": "world" } |] `shouldRespondWith`
+ -- [json| [{"sayhello":"Hello, world"}] |]
+
+ -- describe "weird requests" $ do
+ -- it "can query as normal" $ do
+ -- get "/Escap3e;" `shouldRespondWith`
+ -- [json| [{"so6meIdColumn":1},{"so6meIdColumn":2},{"so6meIdColumn":3},{"so6meIdColumn":4},{"so6meIdColumn":5}] |]
+ -- get "/ghostBusters" `shouldRespondWith`
+ -- [json| [{"escapeId":1},{"escapeId":3},{"escapeId":5}] |]
+
+ -- it "will embed a collection" $
+ -- get "/Escap3e;?select=ghostBusters{*}" `shouldRespondWith`
+ -- [json| [{"ghostBusters":[{"escapeId":1}]},{"ghostBusters":[]},{"ghostBusters":[{"escapeId":3}]},{"ghostBusters":[]},{"ghostBusters":[{"escapeId":5}]}] |]
+
+ -- it "will embed using a column" $
+ -- get "/ghostBusters?select=escapeId{*}" `shouldRespondWith`
+ -- [json| [{"escapeId":{"so6meIdColumn":1}},{"escapeId":{"so6meIdColumn":3}},{"escapeId":{"so6meIdColumn":5}}] |]
diff --git a/test/Feature/RangeSpec.hs b/test/Feature/RangeSpec.hs
index 0ab9987..2c941ba 100644
--- a/test/Feature/RangeSpec.hs
+++ b/test/Feature/RangeSpec.hs
@@ -6,11 +6,12 @@ import Test.Hspec.Wai.JSON
import Network.HTTP.Types
import Network.Wai.Test (SResponse(simpleHeaders,simpleStatus))
import qualified Hasql.Connection as H
+import Data.Pool
import SpecHelper
import PostgREST.Types (DbStructure(..))
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c = beforeAll resetDb
. around (withApp cfgDefault struct c) $
describe "GET /items" $ do
diff --git a/test/Feature/StructureSpec.hs b/test/Feature/StructureSpec.hs
index 9d8834f..7c75cb8 100644
--- a/test/Feature/StructureSpec.hs
+++ b/test/Feature/StructureSpec.hs
@@ -7,10 +7,11 @@ import qualified Hasql.Connection as H
import SpecHelper
import PostgREST.Types (DbStructure(..))
+import Data.Pool
import Network.HTTP.Types
-spec :: DbStructure -> H.Connection -> Spec
+spec :: DbStructure -> Pool (Either H.ConnectionError H.Connection) -> Spec
spec struct c = around (withApp cfgDefault struct c) $ do
describe "GET /" $ do
it "lists views in schema" $
diff --git a/test/Main.hs b/test/Main.hs
index 6256f5d..6a42c2b 100644
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -7,7 +7,9 @@ import qualified Hasql.Session as H
import qualified Hasql.Connection as H
import PostgREST.DbStructure (getDbStructure)
+import PostgREST.Types (DbStructure(..))
import Data.String.Conversions (cs)
+import Data.Pool
import qualified Feature.AuthSpec
import qualified Feature.CorsSpec
@@ -20,24 +22,28 @@ import qualified Feature.StructureSpec
main :: IO ()
main = do
- setupDb
+ --setupDb
- H.acquire (cs dbString) >>= \case
- Left err -> error $ show err
- Right c -> do
- dbOrErr <- H.run (getDbStructure "test") c
- -- Not using hspec-discover because we want to precompute
- -- the db structure and pass it to specs for speed
- either (error.show) (hspec . specs c) dbOrErr
- H.release c
+ pool <- createPool (H.acquire . cs $ dbString)
+ (either (const $ return ()) H.release) 1 1 2
+ hspec $ specs pool (DbStructure [] [] [] [])
+
+ -- H.acquire (cs dbString) >>= \case
+ -- Left err -> error $ show err
+ -- Right c -> do
+ -- dbOrErr <- H.run (getDbStructure "test") c
+ -- -- Not using hspec-discover because we want to precompute
+ -- -- the db structure and pass it to specs for speed
+ -- either (error.show) (hspec . specs c) dbOrErr
+ -- H.release c
where
- specs conn dbStructure = do
- describe "Feature.AuthSpec" $ Feature.AuthSpec.spec dbStructure conn
- describe "Feature.CorsSpec" $ Feature.CorsSpec.spec dbStructure conn
- describe "Feature.DeleteSpec" $ Feature.DeleteSpec.spec dbStructure conn
- describe "Feature.InsertSpec" $ Feature.InsertSpec.spec dbStructure conn
- describe "Feature.QueryLimitedSpec" $ Feature.QueryLimitedSpec.spec dbStructure conn
- describe "Feature.QuerySpec" $ Feature.QuerySpec.spec dbStructure conn
- describe "Feature.RangeSpec" $ Feature.RangeSpec.spec dbStructure conn
- describe "Feature.StructureSpec" $ Feature.StructureSpec.spec dbStructure conn
+ specs pool dbStructure = do
+ -- describe "Feature.AuthSpec" $ Feature.AuthSpec.spec dbStructure conn
+ -- describe "Feature.CorsSpec" $ Feature.CorsSpec.spec dbStructure conn
+ -- describe "Feature.DeleteSpec" $ Feature.DeleteSpec.spec dbStructure conn
+ -- describe "Feature.InsertSpec" $ Feature.InsertSpec.spec dbStructure conn
+ -- describe "Feature.QueryLimitedSpec" $ Feature.QueryLimitedSpec.spec dbStructure conn
+ describe "Feature.QuerySpec" $ Feature.QuerySpec.spec dbStructure pool
+ -- describe "Feature.RangeSpec" $ Feature.RangeSpec.spec dbStructure conn
+ -- describe "Feature.StructureSpec" $ Feature.StructureSpec.spec dbStructure conn
diff --git a/test/SpecHelper.hs b/test/SpecHelper.hs
index 4d53839..d885aaf 100644
--- a/test/SpecHelper.hs
+++ b/test/SpecHelper.hs
@@ -38,16 +38,20 @@ cfgDefault = cfg dbString Nothing
cfgLimitRows :: Integer -> AppConfig
cfgLimitRows = cfg dbString . Just
-withApp :: AppConfig -> DbStructure -> H.Connection
+withApp :: AppConfig -> DbStructure
+ -> Pool (Either H.ConnectionError H.Connection)
-> ActionWith Application -> IO ()
-withApp config dbStructure c perform = do
+withApp config dbStructure pool perform = do
perform $ defaultMiddle $ \req resp -> do
time <- getPOSIXTime
body <- strictRequestBody req
let handleReq = H.run (runWithClaims config time (app dbStructure config body) req)
- resOrError <- handleReq c
- either (resp . pgErrResponse) resp resOrError
+ withResource pool $ \case
+ Left err -> error $ show err
+ Right c -> do
+ resOrError <- handleReq c
+ either (resp . pgErrResponse) resp resOrError
setupDb :: IO ()
setupDb = do
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment