feat: Drop support for pg 9.6

This commit is contained in:
Wolfgang Walther
2024-06-15 17:23:34 +02:00
committed by Wolfgang Walther
parent ec110720dc
commit daa77d17aa
20 changed files with 401 additions and 656 deletions
+128 -134
View File
@@ -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"]
}