From c47bc5c9c76533422ec3e12d87274004dc5cdad4 Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Mon, 28 Nov 2022 16:55:12 +0000 Subject: [PATCH] test: disable data rep inserts/updates for Pg 9.6. This feature requires Pg 10 or above. --- test/spec/Feature/Query/InsertSpec.hs | 205 +++++++++++++------------ test/spec/Feature/Query/UpdateSpec.hs | 213 +++++++++++++------------- test/spec/Main.hs | 2 +- 3 files changed, 214 insertions(+), 206 deletions(-) diff --git a/test/spec/Feature/Query/InsertSpec.hs b/test/spec/Feature/Query/InsertSpec.hs index 102bd579035..045ca1029f7 100644 --- a/test/spec/Feature/Query/InsertSpec.hs +++ b/test/spec/Feature/Query/InsertSpec.hs @@ -11,8 +11,9 @@ import Test.Hspec.Wai import Test.Hspec.Wai.JSON import Text.Heredoc -import PostgREST.Config.PgVersion (PgVersion, pgVersion110, - pgVersion112, pgVersion130) +import PostgREST.Config.PgVersion (PgVersion, pgVersion100, + pgVersion110, pgVersion112, + pgVersion130) import Protolude hiding (get) import SpecHelper @@ -658,111 +659,113 @@ spec actualPgVersion = do , "Content-Range" <:> "*/*" ] } - 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" <:> "*/*" ] - } + -- Data representations for payload parsing requires Postgrest 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" <:> "*/*" ] + } - 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"} |] - `shouldRespondWith` - [json| [{"id":5,"name": "party", "label_color": "#001100", "due_at":"2018-01-03T11:00:00+00"}] |] - { 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"} |] + `shouldRespondWith` + [json| [{"id":5,"name": "party", "label_color": "#001100", "due_at":"2018-01-03T11:00:00+00"}] |] + { 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:00+00"}] |] - { 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:00+00"}] |] + { 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":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] - { 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":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] + { 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" <:> "*/*" ] - } + 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" <:> "*/*" ] + } - 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:00+00", "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:00+00", "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:00+00"}] |] - { 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:00+00"}] |] + { 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":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] - { 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":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] + { matchStatus = 400 + , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8"] + } diff --git a/test/spec/Feature/Query/UpdateSpec.hs b/test/spec/Feature/Query/UpdateSpec.hs index 0e20067b9ec..ae06d62a370 100644 --- a/test/spec/Feature/Query/UpdateSpec.hs +++ b/test/spec/Feature/Query/UpdateSpec.hs @@ -9,6 +9,9 @@ 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 @@ -18,8 +21,8 @@ tblDataBefore = [aesonQQ|[ , { "id": 3, "name": "item-3" } ]|] -spec :: SpecWith ((), Application) -spec = do +spec :: PgVersion -> SpecWith ((), Application) +spec actualPgVersion = do describe "Patching record" $ do context "to unknown uri" $ it "indicates no table found by returning 404" $ @@ -544,95 +547,12 @@ spec = do , { "id": 3, "name": "item-3" } ]|] - 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:00+00"} |] - `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:00+00"} |] - `shouldRespondWith` - [json| [{"id":2, "label_color": "#221100"}] |] - { matchStatus = 200 - , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", - "Content-Range" <:> "0-0/*"] - } - - 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:20+00"} |] - `shouldRespondWith` - [json| [{"id":2, "name": "Essay", "label_color": "#221100", "due_at":"2019-01-03T11:00:20+00"}] |] - { matchStatus = 200 - , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", - "Content-Range" <:> "0-0/*"] - } - 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:00+00"} |] - `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/*"] - } - - 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:00+00"} |] - `shouldRespondWith` - [json| [ - {"id":1, "name": "Report", "label_color": "#221100", "due_at":"2019-01-03T11:00:00+00"}, - {"id":2, "name": "Essay", "label_color": "#221100", "due_at":"2019-01-03T11:00:00+00"}, - {"id":3, "name": "Algebra", "label_color": "#221100", "due_at":"2019-01-03T11:00:00+00"} - ] |] - { matchStatus = 200 - , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", - "Content-Range" <:> "0-2/*"] - } - 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:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |] - `shouldRespondWith` - [json| [ - {"id":2, "name": "Essay", "label_color": "#000100", "due_at":"2019-01-03T11:00:00+00"} - ] |] - { matchStatus = 200 - , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", - "Content-Range" <:> "0-0/*"] - } - - 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:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |] - `shouldRespondWith` - [json| {"code":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] - { 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:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |] - `shouldRespondWith` 200 - context "on a view" $ do + -- Data representations for payload parsing requires Postgrest 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_computed?id=eq.2" [("Prefer", "return=headers-only")] + request methodPatch "/datarep_todos?id=eq.2" [("Prefer", "return=headers-only")] [json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00+00"} |] `shouldRespondWith` "" @@ -642,7 +562,7 @@ spec = do } 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")] + request methodPatch "/datarep_todos?id=eq.2&select=id,label_color" [("Prefer", "return=representation")] [json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00+00"} |] `shouldRespondWith` [json| [{"id":2, "label_color": "#221100"}] |] @@ -652,23 +572,23 @@ spec = do } it "parses values in payload and formats values in return=representation" $ - request methodPatch "/datarep_todos_computed?id=eq.2" [("Prefer", "return=representation")] + request methodPatch "/datarep_todos?id=eq.2" [("Prefer", "return=representation")] [json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:20+00"} |] `shouldRespondWith` - [json| [{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:20+00"}] |] + [json| [{"id":2, "name": "Essay", "label_color": "#221100", "due_at":"2019-01-03T11:00:20+00"}] |] { matchStatus = 200 , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", "Content-Range" <:> "0-0/*"] } 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")] + 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:00+00"} |] `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"} + {"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", @@ -676,13 +596,13 @@ spec = do } it "parses values in payload and formats values in return=representation" $ - request methodPatch "/datarep_todos_computed?id=lt.4" [("Prefer", "return=representation")] + request methodPatch "/datarep_todos?id=lt.4" [("Prefer", "return=representation")] [json| {"label_color": "#221100", "due_at": "2019-01-03T11:00:00+00"} |] `shouldRespondWith` [json| [ - {"id":1, "name": "Report", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00+00"}, - {"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00+00"}, - {"id":3, "name": "Algebra", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00+00"} + {"id":1, "name": "Report", "label_color": "#221100", "due_at":"2019-01-03T11:00:00+00"}, + {"id":2, "name": "Essay", "label_color": "#221100", "due_at":"2019-01-03T11:00:00+00"}, + {"id":3, "name": "Algebra", "label_color": "#221100", "due_at":"2019-01-03T11:00:00+00"} ] |] { matchStatus = 200 , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", @@ -690,11 +610,11 @@ spec = do } 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")] + request methodPatch "/datarep_todos?id=eq.2&columns=due_at" [("Prefer", "return=representation")] [json| {"due_at": "2019-01-03T11:00:00+00", "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:00+00"} + {"id":2, "name": "Essay", "label_color": "#000100", "due_at":"2019-01-03T11:00:00+00"} ] |] { matchStatus = 200 , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", @@ -702,7 +622,7 @@ spec = do } 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")] + request methodPatch "/datarep_todos?id=eq.2&columns=label_color,helicopters" [("Prefer", "return=representation")] [json| {"due_at": "2019-01-03T11:00:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |] `shouldRespondWith` [json| {"code":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] @@ -711,6 +631,91 @@ spec = do } 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")] + request methodPatch "/datarep_todos?id=eq.2001&columns=label_color" [("Prefer", "return=representation")] [json| {"due_at": "2019-01-03T11:00:00+00", "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:00+00"} |] + `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:00+00"} |] + `shouldRespondWith` + [json| [{"id":2, "label_color": "#221100"}] |] + { matchStatus = 200 + , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", + "Content-Range" <:> "0-0/*"] + } + + 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:20+00"} |] + `shouldRespondWith` + [json| [{"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:20+00"}] |] + { matchStatus = 200 + , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", + "Content-Range" <:> "0-0/*"] + } + 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:00+00"} |] + `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/*"] + } + + 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:00+00"} |] + `shouldRespondWith` + [json| [ + {"id":1, "name": "Report", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00+00"}, + {"id":2, "name": "Essay", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00+00"}, + {"id":3, "name": "Algebra", "label_color": "#221100", "dark_color":"#110880", "due_at":"2019-01-03T11:00:00+00"} + ] |] + { matchStatus = 200 + , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", + "Content-Range" <:> "0-2/*"] + } + 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:00+00", "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:00+00"} + ] |] + { matchStatus = 200 + , matchHeaders = ["Content-Type" <:> "application/json; charset=utf-8", + "Content-Range" <:> "0-0/*"] + } + + 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:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |] + `shouldRespondWith` + [json| {"code":"PGRST118","message":"Could not find 'helicopters' in the target table","details":null,"hint":null} |] + { 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:00+00", "smth": "here", "label_color": "invalid", "fake_id": 13} |] + `shouldRespondWith` 200 diff --git a/test/spec/Main.hs b/test/spec/Main.hs index aa443b821a5..cd53d25b8c9 100644 --- a/test/spec/Main.hs +++ b/test/spec/Main.hs @@ -148,7 +148,7 @@ main = do , ("Feature.Query.RawOutputTypesSpec" , Feature.Query.RawOutputTypesSpec.spec) , ("Feature.Query.RpcSpec" , Feature.Query.RpcSpec.spec actualPgVersion) , ("Feature.Query.SingularSpec" , Feature.Query.SingularSpec.spec) - , ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec) + , ("Feature.Query.UpdateSpec" , Feature.Query.UpdateSpec.spec actualPgVersion) , ("Feature.Query.UpsertSpec" , Feature.Query.UpsertSpec.spec actualPgVersion) , ("Feature.Query.ComputedRelsSpec" , Feature.Query.ComputedRelsSpec.spec) , ("Feature.Query.RelatedQueriesSpec" , Feature.Query.RelatedQueriesSpec.spec)