feat: Drop support for pg 9.6
This commit is contained in:
committed by
Wolfgang Walther
parent
ec110720dc
commit
daa77d17aa
@@ -11,10 +11,9 @@ import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion110, pgVersion112,
|
||||
pgVersion120, pgVersion130,
|
||||
pgVersion140)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion110,
|
||||
pgVersion112, pgVersion120,
|
||||
pgVersion130, pgVersion140)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
@@ -494,24 +493,22 @@ spec actualPgVersion = do
|
||||
{"id": 205, "body": "zzz"}]|] `shouldRespondWith` 400
|
||||
|
||||
context "apply defaults on missing values" $ do
|
||||
-- inserting the array fails on pg 9.6, but the feature should work normally
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "inserts table default values(field-with_sep) when json keys are undefined" $
|
||||
request methodPost "/complex_items?columns=id,name,field-with_sep,arr_data" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
[json|[
|
||||
{"id": 4, "name": "Vier"},
|
||||
{"id": 5, "name": "Funf", "arr_data": null},
|
||||
{"id": 6, "name": "Sechs", "field-with_sep": 6, "arr_data": "{1,2,3}"}
|
||||
]|]
|
||||
`shouldRespondWith`
|
||||
[json|[
|
||||
{"id": 4, "name": "Vier", "field-with_sep": 1, "settings":null,"arr_data":null},
|
||||
{"id": 5, "name": "Funf", "field-with_sep": 1, "settings":null,"arr_data":null},
|
||||
{"id": 6, "name": "Sechs", "field-with_sep": 6, "settings":null,"arr_data":[1,2,3]}
|
||||
]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Preference-Applied" <:> "missing=default, return=representation"]
|
||||
}
|
||||
it "inserts table default values(field-with_sep) when json keys are undefined" $
|
||||
request methodPost "/complex_items?columns=id,name,field-with_sep,arr_data" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
[json|[
|
||||
{"id": 4, "name": "Vier"},
|
||||
{"id": 5, "name": "Funf", "arr_data": null},
|
||||
{"id": 6, "name": "Sechs", "field-with_sep": 6, "arr_data": "{1,2,3}"}
|
||||
]|]
|
||||
`shouldRespondWith`
|
||||
[json|[
|
||||
{"id": 4, "name": "Vier", "field-with_sep": 1, "settings":null,"arr_data":null},
|
||||
{"id": 5, "name": "Funf", "field-with_sep": 1, "settings":null,"arr_data":null},
|
||||
{"id": 6, "name": "Sechs", "field-with_sep": 6, "settings":null,"arr_data":[1,2,3]}
|
||||
]|]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Preference-Applied" <:> "missing=default, return=representation"]
|
||||
}
|
||||
|
||||
it "inserts view default values(field-with_sep) when json keys are undefined" $
|
||||
request methodPost "/complex_items_view?columns=id,name" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
@@ -537,15 +534,14 @@ spec actualPgVersion = do
|
||||
, matchHeaders = ["Preference-Applied" <:> "missing=default, return=representation"]
|
||||
}
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "inserts a default on a generated by default as identity column" $
|
||||
request methodPost "/channels?columns=id,data,slug&select=data,slug" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
[json| { "slug": "foo" } |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"data":{"foo": "bar"},"slug":"foo"}] |] -- id 1 was inserted here, we don't get it for idempotence in the tests
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Preference-Applied" <:> "missing=default, return=representation"]
|
||||
}
|
||||
it "inserts a default on a generated by default as identity column" $
|
||||
request methodPost "/channels?columns=id,data,slug&select=data,slug" [("Prefer", "return=representation"), ("Prefer", "missing=default")]
|
||||
[json| { "slug": "foo" } |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"data":{"foo": "bar"},"slug":"foo"}] |] -- id 1 was inserted here, we don't get it for idempotence in the tests
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Preference-Applied" <:> "missing=default, return=representation"]
|
||||
}
|
||||
|
||||
when (actualPgVersion >= pgVersion120) $
|
||||
it "fails with a good error message on generated always columns" $
|
||||
@@ -798,115 +794,113 @@ spec actualPgVersion = do
|
||||
}
|
||||
|
||||
|
||||
-- Data representations for payload parsing requires Postgres 10 or above.
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
describe "Data representations" $ do
|
||||
context "on regular table" $ do
|
||||
it "parses values in POST body" $
|
||||
-- we don't check that the parsing is correct here, just that it's happening. If it doesn't happen we'll get a
|
||||
-- an "invalid input syntax for type integer:" error.
|
||||
request methodPost "/datarep_todos" [("Prefer", "return=headers-only")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Location" <:> "/datarep_todos?id=eq.5"
|
||||
, "Content-Range" <:> "*/*"
|
||||
, "Preference-Applied" <:> "return=headers-only"]
|
||||
}
|
||||
describe "Data representations" $ do
|
||||
context "on regular table" $ do
|
||||
it "parses values in POST body" $
|
||||
-- we don't check that the parsing is correct here, just that it's happening. If it doesn't happen we'll get a
|
||||
-- an "invalid input syntax for type integer:" error.
|
||||
request methodPost "/datarep_todos" [("Prefer", "return=headers-only")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Location" <:> "/datarep_todos?id=eq.5"
|
||||
, "Content-Range" <:> "*/*"
|
||||
, "Preference-Applied" <:> "return=headers-only"]
|
||||
}
|
||||
|
||||
it "parses values in POST body and formats individually selected values in return=representation" $
|
||||
request methodPost "/datarep_todos?select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "label_color": "#001100"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
it "parses values in POST body and formats individually selected values in return=representation" $
|
||||
request methodPost "/datarep_todos?select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "label_color": "#001100"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
|
||||
it "parses values in POST body and formats values in return=representation" $
|
||||
request methodPost "/datarep_todos" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00", "icon_image": "3q2+7w", "created_at":-15, "budget": "-100000000000000.13"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5,"name": "party", "label_color": "#001100", "due_at":"2018-01-03T11:00:00Z", "icon_image": "3q2+7w==", "created_at":-15, "budget": "-100000000000000.13"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
it "parses values in POST body and formats values in return=representation" $
|
||||
request methodPost "/datarep_todos" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00", "icon_image": "3q2+7w", "created_at":-15, "budget": "-100000000000000.13"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5,"name": "party", "label_color": "#001100", "due_at":"2018-01-03T11:00:00Z", "icon_image": "3q2+7w==", "created_at":-15, "budget": "-100000000000000.13"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
|
||||
context "with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPost "/datarep_todos?columns=id,label_color&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "invalid but should be ignored"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "name":null, "label_color": "#001100", "due_at": "2018-01-01T00:00:00Z"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
context "with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPost "/datarep_todos?columns=id,label_color&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "invalid but should be ignored"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "name":null, "label_color": "#001100", "due_at": "2018-01-01T00:00:00Z"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
|
||||
it "fails without parsing anything if at least one specified column doesn't exist" $
|
||||
request methodPost "/datarep_todos?columns=id,label_color,helicopters&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
it "fails without parsing anything if at least one specified column doesn't exist" $
|
||||
request methodPost "/datarep_todos?columns=id,label_color,helicopters&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
|
||||
context "on updatable view" $ do
|
||||
it "parses values in POST body" $
|
||||
-- we don't check that the parsing is correct here, just that it's happening. If it doesn't happen we'll get a
|
||||
-- an "invalid input syntax for type integer:" error.
|
||||
request methodPost "/datarep_todos_computed" [("Prefer", "return=headers-only")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Location" <:> "/datarep_todos_computed?id=eq.5"
|
||||
, "Content-Range" <:> "*/*"
|
||||
, "Preference-Applied" <:> "return=headers-only"]
|
||||
}
|
||||
context "on updatable view" $ do
|
||||
it "parses values in POST body" $
|
||||
-- we don't check that the parsing is correct here, just that it's happening. If it doesn't happen we'll get a
|
||||
-- an "invalid input syntax for type integer:" error.
|
||||
request methodPost "/datarep_todos_computed" [("Prefer", "return=headers-only")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Location" <:> "/datarep_todos_computed?id=eq.5"
|
||||
, "Content-Range" <:> "*/*"
|
||||
, "Preference-Applied" <:> "return=headers-only"]
|
||||
}
|
||||
|
||||
it "parses values in POST body and formats individually selected values in return=representation" $
|
||||
request methodPost "/datarep_todos_computed?select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "label_color": "#001100"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
it "parses values in POST body and formats individually selected values in return=representation" $
|
||||
request methodPost "/datarep_todos_computed?select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "label_color": "#001100"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
|
||||
it "parses values in POST body and formats values in return=representation" $
|
||||
request methodPost "/datarep_todos_computed" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5,"name": "party", "label_color": "#001100", "due_at":"2018-01-03T11:00:00Z", "dark_color":"#000880"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
it "parses values in POST body and formats values in return=representation" $
|
||||
request methodPost "/datarep_todos_computed" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "2018-01-03T11:00:00+00"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5,"name": "party", "label_color": "#001100", "due_at":"2018-01-03T11:00:00Z", "dark_color":"#000880"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
|
||||
context "on updatable views with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPost "/datarep_todos_computed?columns=id,label_color&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "invalid but should be ignored"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "name":null, "label_color": "#001100", "due_at": "2018-01-01T00:00:00Z"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
context "on updatable views with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPost "/datarep_todos_computed?columns=id,label_color&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"id":5, "name": "party", "label_color": "#001100", "due_at": "invalid but should be ignored"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":5, "name":null, "label_color": "#001100", "due_at": "2018-01-01T00:00:00Z"}] |]
|
||||
{ matchStatus = 201
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8",
|
||||
"Content-Range" <:> "*/*"]
|
||||
}
|
||||
|
||||
it "fails without parsing anything if at least one specified column doesn't exist" $
|
||||
request methodPost "/datarep_todos_computed?columns=id,label_color,helicopters&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos_computed' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
it "fails without parsing anything if at least one specified column doesn't exist" $
|
||||
request methodPost "/datarep_todos_computed?columns=id,label_color,helicopters&select=id,name,label_color,due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos_computed' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
|
||||
@@ -7,13 +7,11 @@ import Test.Hspec
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
|
||||
spec :: PgVersion -> SpecWith ((), Application)
|
||||
spec actualPgVersion = describe "PostGIS features" $
|
||||
spec :: SpecWith ((), Application)
|
||||
spec = describe "PostGIS features" $
|
||||
context "GeoJSON output" $ do
|
||||
it "works for a table that has a geometry column" $
|
||||
request methodGet "/shops"
|
||||
@@ -56,59 +54,32 @@ spec actualPgVersion = describe "PostGIS features" $
|
||||
it "works with resource embedding" $
|
||||
request methodGet "/shops?select=*,shop_bles(*)&id=eq.1"
|
||||
[("Accept", "application/geo+json")] "" `shouldRespondWith`
|
||||
(if actualPgVersion >= pgVersion100
|
||||
then [json| {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"properties": {
|
||||
"address": "1369 Cambridge St", "id": 1,
|
||||
"shop_bles": [
|
||||
{ "id": 1, "name": "Beacon-1", "shop_id": 1 ,
|
||||
"coords": { "coordinates": [ -71.10044, 42.373695 ], "crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Point" },
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10045254230499, 42.37387083326593 ], [ -71.10048070549963, 42.37377126199953 ], [ -71.10039688646793, 42.37375838212269 ], [ -71.10037006437777, 42.37385844878863 ], [ -71.10045254230499, 42.37387083326593 ] ] ],
|
||||
"crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Polygon" }
|
||||
},
|
||||
{ "coords": { "coordinates": [ -71.10044, 42.373695 ], "crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Point" },
|
||||
"id": 2, "name": "Beacon-2", "shop_id": 1,
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10034391283989, 42.37385299961788 ], [ -71.10036939382553, 42.373756895982865 ], [ -71.1002916097641, 42.373745997623224 ], [ -71.1002641171217, 42.37384408279195 ], [ -71.10034391283989, 42.37385299961788 ] ] ],
|
||||
"crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Polygon" }
|
||||
}
|
||||
]
|
||||
}
|
||||
[json| {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"properties": {
|
||||
"address": "1369 Cambridge St", "id": 1,
|
||||
"shop_bles": [
|
||||
{ "id": 1, "name": "Beacon-1", "shop_id": 1 ,
|
||||
"coords": { "coordinates": [ -71.10044, 42.373695 ], "crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Point" },
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10045254230499, 42.37387083326593 ], [ -71.10048070549963, 42.37377126199953 ], [ -71.10039688646793, 42.37375838212269 ], [ -71.10037006437777, 42.37385844878863 ], [ -71.10045254230499, 42.37387083326593 ] ] ],
|
||||
"crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Polygon" }
|
||||
},
|
||||
{ "coords": { "coordinates": [ -71.10044, 42.373695 ], "crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Point" },
|
||||
"id": 2, "name": "Beacon-2", "shop_id": 1,
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10034391283989, 42.37385299961788 ], [ -71.10036939382553, 42.373756895982865 ], [ -71.1002916097641, 42.373745997623224 ], [ -71.1002641171217, 42.37384408279195 ], [ -71.10034391283989, 42.37385299961788 ] ] ],
|
||||
"crs": { "properties": { "name": "EPSG:4326" }, "type": "name" }, "type": "Polygon" }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}|]
|
||||
else [json| {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"properties": {
|
||||
"address": "1369 Cambridge St", "id": 1,
|
||||
"shop_bles": [
|
||||
{ "id": 1, "name": "Beacon-1", "shop_id": 1 ,
|
||||
"coords": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10045254230499, 42.37387083326593 ], [ -71.10048070549963, 42.37377126199953 ], [ -71.10039688646793, 42.37375838212269 ], [ -71.10037006437777, 42.37385844878863 ], [ -71.10045254230499, 42.37387083326593 ] ] ],
|
||||
"type": "Polygon" }
|
||||
},
|
||||
{ "coords": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" },
|
||||
"id": 2, "name": "Beacon-2", "shop_id": 1,
|
||||
"range_area": {
|
||||
"coordinates": [ [ [ -71.10034391283989, 42.37385299961788 ], [ -71.10036939382553, 42.373756895982865 ], [ -71.1002916097641, 42.373745997623224 ], [ -71.1002641171217, 42.37384408279195 ], [ -71.10034391283989, 42.37385299961788 ] ] ],
|
||||
"type": "Polygon" }
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}|])
|
||||
}
|
||||
]
|
||||
}|]
|
||||
{ matchHeaders = ["Content-Type" <:> "application/geo+json; charset=utf-8"] }
|
||||
|
||||
it "works with RPC" $
|
||||
@@ -219,14 +190,8 @@ spec actualPgVersion = describe "PostGIS features" $
|
||||
|
||||
it "gets the geojson geometry object with the regular application/json output" $
|
||||
request methodGet "/shops?id=eq.1" [] "" `shouldRespondWith`
|
||||
(if actualPgVersion >= pgVersion100
|
||||
then [json|[{
|
||||
"id":1,"address":"1369 Cambridge St",
|
||||
"shop_geom":{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-71.10044,42.373695]}
|
||||
}]|]
|
||||
else [json|[{
|
||||
"address": "1369 Cambridge St",
|
||||
"id": 1,
|
||||
"shop_geom": { "coordinates": [ -71.10044, 42.373695 ], "type": "Point" }
|
||||
}]|])
|
||||
[json|[{
|
||||
"id":1,"address":"1369 Cambridge St",
|
||||
"shop_geom":{"type":"Point","crs":{"type":"name","properties":{"name":"EPSG:4326"}},"coordinates":[-71.10044,42.373695]}
|
||||
}]|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
@@ -11,9 +11,9 @@ import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
import Text.Heredoc
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion109, pgVersion110,
|
||||
pgVersion112, pgVersion114)
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion109,
|
||||
pgVersion110, pgVersion112,
|
||||
pgVersion114)
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
@@ -530,66 +530,34 @@ spec actualPgVersion =
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
context "proc argument types" $ do
|
||||
-- different syntax for array needed for pg<10
|
||||
when (actualPgVersion < pgVersion100) $
|
||||
it "accepts a variety of arguments (Postgres < 10)" $
|
||||
post "/rpc/varied_arguments"
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "20190101",
|
||||
"money": 0,
|
||||
"enum": "foo",
|
||||
"arr": "{a,b,c}",
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
`shouldRespondWith`
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "2019-01-01",
|
||||
"money": "$0.00",
|
||||
"enum": "foo",
|
||||
"arr": ["a", "b", "c"],
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "accepts a variety of arguments (Postgres >= 10)" $
|
||||
post "/rpc/varied_arguments"
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "20190101",
|
||||
"money": 0,
|
||||
"enum": "foo",
|
||||
"arr": ["a", "b", "c"],
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
`shouldRespondWith`
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "2019-01-01",
|
||||
"money": "$0.00",
|
||||
"enum": "foo",
|
||||
"arr": ["a", "b", "c"],
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
it "accepts a variety of arguments (Postgres >= 10)" $
|
||||
post "/rpc/varied_arguments"
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "20190101",
|
||||
"money": 0,
|
||||
"enum": "foo",
|
||||
"arr": ["a", "b", "c"],
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
`shouldRespondWith`
|
||||
[json| {
|
||||
"double": 3.1,
|
||||
"varchar": "hello",
|
||||
"boolean": true,
|
||||
"date": "2019-01-01",
|
||||
"money": "$0.00",
|
||||
"enum": "foo",
|
||||
"arr": ["a", "b", "c"],
|
||||
"integer": 43,
|
||||
"json": {"some key": "some value"},
|
||||
"jsonb": {"another key": [1, 2, "3"]}
|
||||
} |]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
it "accepts a variety of arguments with GET" $
|
||||
-- without JSON / JSONB here, because passing those via query string is useless - they just become a "json string" all the time
|
||||
@@ -635,14 +603,6 @@ spec actualPgVersion =
|
||||
[json|"object"|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when (actualPgVersion < pgVersion100) $
|
||||
it "parses quoted JSON arguments as JSON (Postgres < 10)" $
|
||||
post "/rpc/json_argument"
|
||||
[json| { "arg": "{ \"key\": 3 }" } |]
|
||||
`shouldRespondWith`
|
||||
[json|"object"|]
|
||||
{ matchHeaders = [matchContentTypeJson] }
|
||||
|
||||
when ((actualPgVersion >= pgVersion109 && actualPgVersion < pgVersion110)
|
||||
|| actualPgVersion >= pgVersion114) $
|
||||
it "parses quoted JSON arguments as JSON string (from Postgres 10.9, 11.4)" $
|
||||
@@ -765,68 +725,59 @@ spec actualPgVersion =
|
||||
[json|[{"a": "A", "b": "B"}]|]
|
||||
|
||||
context "procs with VARIADIC params" $ do
|
||||
when (actualPgVersion < pgVersion100) $
|
||||
it "works with POST (Postgres < 10)" $
|
||||
post "/rpc/variadic_param"
|
||||
[json| { "v": "{hi,hello,there}" } |]
|
||||
it "works with POST (Postgres >= 10)" $
|
||||
post "/rpc/variadic_param"
|
||||
[json| { "v": ["hi", "hello", "there"] } |]
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "hello", "there"]|]
|
||||
|
||||
context "works with GET and repeated params" $ do
|
||||
it "n=0 (through DEFAULT)" $
|
||||
get "/rpc/variadic_param"
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "hello", "there"]|]
|
||||
[json|[]|]
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
it "works with POST (Postgres >= 10)" $
|
||||
post "/rpc/variadic_param"
|
||||
[json| { "v": ["hi", "hello", "there"] } |]
|
||||
it "n=1" $
|
||||
get "/rpc/variadic_param?v=hi"
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "hello", "there"]|]
|
||||
[json|["hi"]|]
|
||||
|
||||
context "works with GET and repeated params" $ do
|
||||
it "n=0 (through DEFAULT)" $
|
||||
get "/rpc/variadic_param"
|
||||
`shouldRespondWith`
|
||||
[json|[]|]
|
||||
it "n>1" $
|
||||
get "/rpc/variadic_param?v=hi&v=there"
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "there"]|]
|
||||
|
||||
it "n=1" $
|
||||
get "/rpc/variadic_param?v=hi"
|
||||
`shouldRespondWith`
|
||||
[json|["hi"]|]
|
||||
context "works with POST and repeated params from html form" $ do
|
||||
it "n=0 (through DEFAULT)" $
|
||||
request methodPost "/rpc/variadic_param"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|[]|]
|
||||
|
||||
it "n>1" $
|
||||
get "/rpc/variadic_param?v=hi&v=there"
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "there"]|]
|
||||
it "n=1" $
|
||||
request methodPost "/rpc/variadic_param"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
"v=hi"
|
||||
`shouldRespondWith`
|
||||
[json|["hi"]|]
|
||||
|
||||
context "works with POST and repeated params from html form" $ do
|
||||
it "n=0 (through DEFAULT)" $
|
||||
request methodPost "/rpc/variadic_param"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
""
|
||||
`shouldRespondWith`
|
||||
[json|[]|]
|
||||
|
||||
it "n=1" $
|
||||
request methodPost "/rpc/variadic_param"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
"v=hi"
|
||||
`shouldRespondWith`
|
||||
[json|["hi"]|]
|
||||
|
||||
it "n>1" $
|
||||
request methodPost "/rpc/variadic_param"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
"v=hi&v=there"
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "there"]|]
|
||||
it "n>1" $
|
||||
request methodPost "/rpc/variadic_param"
|
||||
[("Content-Type", "application/x-www-form-urlencoded")]
|
||||
"v=hi&v=there"
|
||||
`shouldRespondWith`
|
||||
[json|["hi", "there"]|]
|
||||
|
||||
it "returns last value for repeated params without VARIADIC" $
|
||||
get "/rpc/sayhello?name=ignored&name=world"
|
||||
`shouldRespondWith`
|
||||
[json|"Hello, world"|]
|
||||
|
||||
when (actualPgVersion >= pgVersion100) $
|
||||
it "returns last value for repeated non-variadic params in function with other VARIADIC arguments" $
|
||||
get "/rpc/sayhello_variadic?name=ignored&name=world&v=unused"
|
||||
`shouldRespondWith`
|
||||
[json|"Hello, world"|]
|
||||
it "returns last value for repeated non-variadic params in function with other VARIADIC arguments" $
|
||||
get "/rpc/sayhello_variadic?name=ignored&name=world&v=unused"
|
||||
`shouldRespondWith`
|
||||
[json|"Hello, world"|]
|
||||
|
||||
it "can handle procs with args that have a DEFAULT value" $ do
|
||||
get "/rpc/many_inout_params?num=1&str=two"
|
||||
|
||||
@@ -7,14 +7,11 @@ import Network.HTTP.Types
|
||||
import Test.Hspec.Wai
|
||||
import Test.Hspec.Wai.JSON
|
||||
|
||||
import PostgREST.Config.PgVersion (PgVersion, pgVersion100)
|
||||
|
||||
|
||||
import Protolude hiding (get)
|
||||
import SpecHelper
|
||||
|
||||
spec :: PgVersion -> SpecWith ((), Application)
|
||||
spec actualPgVersion = do
|
||||
spec :: SpecWith ((), Application)
|
||||
spec = do
|
||||
describe "Patching record" $ do
|
||||
context "to unknown uri" $
|
||||
it "indicates no table found by returning 404" $
|
||||
@@ -623,196 +620,93 @@ spec actualPgVersion = do
|
||||
}
|
||||
|
||||
-- Data representations for payload parsing requires Postgres 10 or above.
|
||||
when (actualPgVersion >= pgVersion100) $ do
|
||||
describe "Data representations" $ do
|
||||
context "for a single row" $ do
|
||||
it "parses values in payload" $
|
||||
request methodPatch "/datarep_todos?id=eq.2" [("Prefer", "return=headers-only")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 204
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Content-Range" <:> "0-0/*"]
|
||||
}
|
||||
describe "Data representations" $ do
|
||||
context "for a single row" $ do
|
||||
it "parses values in payload" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2" [("Prefer", "return=headers-only")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 204
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Content-Range" <:> "0-0/*" ]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2, "label_color": "#221100"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2&select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2, "label_color": "#221100"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=eq.2" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:20Z", "icon_image": "3q2+7w"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2,"name":"Essay","label_color":"#221100","due_at":"2019-01-03T11:00:20Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"100000000000000.13"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:20Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:20Z"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "for multiple rows" $ do
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=lt.4&select=id,name,label_color,dark_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1, "name": "Report", "label_color": "#221100", "dark_color":"#110880"},
|
||||
{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880"},
|
||||
{"id":3, "name": "Algebra", "label_color": "#221100", "dark_color":"#110880"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats star mixed selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&select=due_at,*" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z", "created_at": 0} |]
|
||||
`shouldRespondWith`
|
||||
-- end up with due_at twice here but that's unrelated to data reps
|
||||
[json| [{"due_at":"2019-01-03T11:00:00Z","id":2,"name":"Essay","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":null,"created_at":0,"budget":"100000000000000.13"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "for multiple rows" $ do
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=lt.4&select=id,name,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1, "name": "Report", "label_color": "#221100"},
|
||||
{"id":2, "name": "Essay", "label_color": "#221100"},
|
||||
{"id":3, "name": "Algebra", "label_color": "#221100"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=lt.4" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1, "name": "Report", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00Z"},
|
||||
{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00Z"},
|
||||
{"id":3, "name": "Algebra", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00Z"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2&columns=due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":2, "name": "Essay", "label_color": "#000100", "dark_color": "#000080", "due_at":"2019-01-03T11:00:00Z"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos?id=lt.4" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z", "icon_image": "3q2+7w="} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1,"name":"Report","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"12.50"},
|
||||
{"id":2,"name":"Essay","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"100000000000000.13"},
|
||||
{"id":3,"name":"Algebra","label_color":"#221100","due_at":"2019-01-03T11:00:00Z","icon_image":"3q2+7w==","created_at":1513213350,"budget":"0.00"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&columns=due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":2,"name":"Essay","label_color":"#000100","due_at":"2019-01-03T11:00:00Z","icon_image":null,"created_at":1513213350,"budget":"100000000000000.13"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
it "fails if at least one specified column doesn't exist" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2&columns=label_color,helicopters" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos_computed' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
|
||||
it "fails if at least one specified column doesn't exist" $
|
||||
request methodPatch "/datarep_todos?id=eq.2&columns=label_color,helicopters" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
|
||||
it "ignores json keys and gives 200 if no record updated" $
|
||||
request methodPatch "/datarep_todos?id=eq.2001&columns=label_color" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith` 200
|
||||
context "on a view" $ do
|
||||
context "for a single row" $ do
|
||||
it "parses values in payload" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2" [("Prefer", "return=headers-only")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
""
|
||||
{ matchStatus = 204
|
||||
, matchHeaders = [ matchHeaderAbsent hContentType
|
||||
, "Content-Range" <:> "0-0/*" ]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2&select=id,label_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2, "label_color": "#221100"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:20Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:20Z"}] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "for multiple rows" $ do
|
||||
it "parses values in payload and formats individually selected values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=lt.4&select=id,name,label_color,dark_color" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1, "name": "Report", "label_color": "#221100", "dark_color":"#110880"},
|
||||
{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880"},
|
||||
{"id":3, "name": "Algebra", "label_color": "#221100", "dark_color":"#110880"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "parses values in payload and formats values in return=representation" $
|
||||
request methodPatch "/datarep_todos_computed?id=lt.4" [("Prefer", "return=representation")]
|
||||
[json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00Z"} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":1, "name": "Report", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00Z"},
|
||||
{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00Z"},
|
||||
{"id":3, "name": "Algebra", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00Z"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-2/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
context "with ?columns parameter" $ do
|
||||
it "ignores json keys not included in ?columns; parses only the ones specified" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2&columns=due_at" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| [
|
||||
{"id":2, "name": "Essay", "label_color": "#000100", "dark_color": "#000080", "due_at":"2019-01-03T11:00:00Z"}
|
||||
] |]
|
||||
{ matchStatus = 200
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"
|
||||
, "Content-Range" <:> "0-0/*"
|
||||
, "Preference-Applied" <:> "return=representation"]
|
||||
}
|
||||
|
||||
it "fails if at least one specified column doesn't exist" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2&columns=label_color,helicopters" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith`
|
||||
[json| {"code":"PGRST204","details":null,"hint":null,"message":"Could not find the 'helicopters' column of 'datarep_todos_computed' in the schema cache"} |]
|
||||
{ matchStatus = 400
|
||||
, matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"]
|
||||
}
|
||||
|
||||
it "ignores json keys and gives 200 if no record updated" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2001&columns=label_color" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith` 200
|
||||
it "ignores json keys and gives 200 if no record updated" $
|
||||
request methodPatch "/datarep_todos_computed?id=eq.2001&columns=label_color" [("Prefer", "return=representation")]
|
||||
[json| {"due_at": "2019-01-03T11:00:00Z", "smth": "here", "label_color": "invalid", "fake_id": 13} |]
|
||||
`shouldRespondWith` 200
|
||||
|
||||
Reference in New Issue
Block a user