Reorganize error groups

* Grouped Hasql errors into one error and renamed it to InternalError
* Move all the General errors to ApiRequest errors
This commit is contained in:
Laurence Isla
2022-05-02 21:16:31 -05:00
committed by GitHub
parent 980f27a6d1
commit a2349d90c0
6 changed files with 76 additions and 104 deletions
+43 -71
View File
@@ -98,11 +98,6 @@ instance JSON.ToJSON ApiRequestError where
"message" .= message, "message" .= message,
"details" .= details, "details" .= details,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON PutRangeNotAllowedError = JSON.object [
"code" .= GeneralErrorCode03,
"message" .= ("Range header and limit/offset querystring parameters are not allowed for PUT" :: Text),
"details" .= JSON.Null,
"hint" .= JSON.Null]
toJSON InvalidFilters = JSON.object [ toJSON InvalidFilters = JSON.object [
"code" .= ApiRequestErrorCode05, "code" .= ApiRequestErrorCode05,
"message" .= ("Filters must include all and only primary key columns with 'eq' operators" :: Text), "message" .= ("Filters must include all and only primary key columns with 'eq' operators" :: Text),
@@ -130,6 +125,12 @@ instance JSON.ToJSON ApiRequestError where
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= ("Apply an 'order' using unique column(s)" :: Text)] "hint" .= ("Apply an 'order' using unique column(s)" :: Text)]
toJSON PutRangeNotAllowedError = JSON.object [
"code" .= ApiRequestErrorCode14,
"message" .= ("Range header and limit/offset querystring parameters are not allowed for PUT" :: Text),
"details" .= JSON.Null,
"hint" .= JSON.Null]
toJSON (NoRelBetween parent child schema) = JSON.object [ toJSON (NoRelBetween parent child schema) = JSON.object [
"code" .= SchemaCacheErrorCode00, "code" .= SchemaCacheErrorCode00,
"message" .= ("Could not find a relationship between '" <> parent <> "' and '" <> child <> "' in the schema cache" :: Text), "message" .= ("Could not find a relationship between '" <> parent <> "' and '" <> child <> "' in the schema cache" :: Text),
@@ -217,36 +218,17 @@ instance JSON.ToJSON SQL.QueryError where
instance JSON.ToJSON SQL.CommandError where instance JSON.ToJSON SQL.CommandError where
toJSON (SQL.ResultError (SQL.ServerError c m d h)) = JSON.object [ toJSON (SQL.ResultError (SQL.ServerError c m d h)) = JSON.object [
"code" .= (T.decodeUtf8 c :: Text), "code" .= (T.decodeUtf8 c :: Text),
"message" .= (T.decodeUtf8 m :: Text), "message" .= (T.decodeUtf8 m :: Text),
"details" .= (fmap T.decodeUtf8 d :: Maybe Text), "details" .= (fmap T.decodeUtf8 d :: Maybe Text),
"hint" .= (fmap T.decodeUtf8 h :: Maybe Text)] "hint" .= (fmap T.decodeUtf8 h :: Maybe Text)]
toJSON (SQL.ResultError (SQL.UnexpectedResult m)) = JSON.object [ toJSON (SQL.ResultError resultError) = JSON.object [
"code" .= HasqlErrorCode00, "code" .= InternalErrorCode00,
"message" .= (m :: Text), "message" .= (show resultError :: Text),
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON (SQL.ResultError (SQL.RowError i SQL.EndOfInput)) = JSON.object [
"code" .= HasqlErrorCode01,
"message" .= ("Row error: end of input" :: Text),
"details" .= ("Attempt to parse more columns than there are in the result" :: Text),
"hint" .= (("Row number " <> show i) :: Text)]
toJSON (SQL.ResultError (SQL.RowError i SQL.UnexpectedNull)) = JSON.object [
"code" .= HasqlErrorCode02,
"message" .= ("Row error: unexpected null" :: Text),
"details" .= ("Attempt to parse a NULL as some value." :: Text),
"hint" .= (("Row number " <> show i) :: Text)]
toJSON (SQL.ResultError (SQL.RowError i (SQL.ValueError d))) = JSON.object [
"code" .= HasqlErrorCode03,
"message" .= ("Row error: Wrong value parser used" :: Text),
"details" .= d,
"hint" .= (("Row number " <> show i) :: Text)]
toJSON (SQL.ResultError (SQL.UnexpectedAmountOfRows i)) = JSON.object [
"code" .= HasqlErrorCode04,
"message" .= ("Unexpected amount of rows" :: Text),
"details" .= i,
"hint" .= JSON.Null]
toJSON (SQL.ClientError d) = JSON.object [ toJSON (SQL.ClientError d) = JSON.object [
"code" .= ConnectionErrorCode01, "code" .= ConnectionErrorCode01,
"message" .= ("Database client error. Retrying the connection." :: Text), "message" .= ("Database client error. Retrying the connection." :: Text),
@@ -381,46 +363,46 @@ instance JSON.ToJSON Error where
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON (OffLimitsChangesError n maxs) = JSON.object [
"code" .= ApiRequestErrorCode10,
"message" .= ("The maximum number of rows allowed to change was surpassed" :: Text),
"details" .= T.unwords ["Results contain", show n, "rows changed but the maximum number allowed is", show maxs],
"hint" .= JSON.Null]
toJSON GucHeadersError = JSON.object [ toJSON GucHeadersError = JSON.object [
"code" .= GeneralErrorCode00, "code" .= ApiRequestErrorCode11,
"message" .= ("response.headers guc must be a JSON array composed of objects with a single key and a string value" :: Text), "message" .= ("response.headers guc must be a JSON array composed of objects with a single key and a string value" :: Text),
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON GucStatusError = JSON.object [ toJSON GucStatusError = JSON.object [
"code" .= GeneralErrorCode01, "code" .= ApiRequestErrorCode12,
"message" .= ("response.status guc must be a valid status code" :: Text), "message" .= ("response.status guc must be a valid status code" :: Text),
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON (BinaryFieldError ct) = JSON.object [ toJSON (BinaryFieldError ct) = JSON.object [
"code" .= GeneralErrorCode02, "code" .= ApiRequestErrorCode13,
"message" .= ((T.decodeUtf8 (ContentType.toMime ct) <> " requested but more than one column was selected") :: Text), "message" .= ((T.decodeUtf8 (ContentType.toMime ct) <> " requested but more than one column was selected") :: Text),
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON PutMatchingPkError = JSON.object [ toJSON PutMatchingPkError = JSON.object [
"code" .= GeneralErrorCode04, "code" .= ApiRequestErrorCode15,
"message" .= ("Payload values do not match URL in primary key column(s)" :: Text), "message" .= ("Payload values do not match URL in primary key column(s)" :: Text),
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON (SingularityError n) = JSON.object [ toJSON (SingularityError n) = JSON.object [
"code" .= GeneralErrorCode05, "code" .= ApiRequestErrorCode16,
"message" .= ("JSON object requested, multiple (or no) rows returned" :: Text), "message" .= ("JSON object requested, multiple (or no) rows returned" :: Text),
"details" .= T.unwords ["Results contain", show n, "rows,", T.decodeUtf8 (ContentType.toMime CTSingularJSON), "requires 1 row"], "details" .= T.unwords ["Results contain", show n, "rows,", T.decodeUtf8 (ContentType.toMime CTSingularJSON), "requires 1 row"],
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON (UnsupportedVerb verb) = JSON.object [ toJSON (UnsupportedVerb verb) = JSON.object [
"code" .= GeneralErrorCode06, "code" .= ApiRequestErrorCode17,
"message" .= ("Unsupported HTTP verb: " <> verb), "message" .= ("Unsupported HTTP verb: " <> verb),
"details" .= JSON.Null, "details" .= JSON.Null,
"hint" .= JSON.Null] "hint" .= JSON.Null]
toJSON (OffLimitsChangesError n maxs) = JSON.object [
"code" .= ApiRequestErrorCode10,
"message" .= ("The maximum number of rows allowed to change was surpassed" :: Text),
"details" .= T.unwords ["Results contain", show n, "rows changed but the maximum number allowed is", show maxs],
"hint" .= JSON.Null]
toJSON NotFound = JSON.object [] toJSON NotFound = JSON.object []
toJSON (PgErr err) = JSON.toJSON err toJSON (PgErr err) = JSON.toJSON err
toJSON (ApiRequestError err) = JSON.toJSON err toJSON (ApiRequestError err) = JSON.toJSON err
@@ -453,6 +435,13 @@ data ErrorCode
| ApiRequestErrorCode08 | ApiRequestErrorCode08
| ApiRequestErrorCode09 | ApiRequestErrorCode09
| ApiRequestErrorCode10 | ApiRequestErrorCode10
| ApiRequestErrorCode11
| ApiRequestErrorCode12
| ApiRequestErrorCode13
| ApiRequestErrorCode14
| ApiRequestErrorCode15
| ApiRequestErrorCode16
| ApiRequestErrorCode17
-- Schema Cache errors -- Schema Cache errors
| SchemaCacheErrorCode00 | SchemaCacheErrorCode00
| SchemaCacheErrorCode01 | SchemaCacheErrorCode01
@@ -462,20 +451,8 @@ data ErrorCode
| JWTErrorCode00 | JWTErrorCode00
| JWTErrorCode01 | JWTErrorCode01
| JWTErrorCode02 | JWTErrorCode02
-- Hasql library errors -- Internal errors related to the Hasql library
| HasqlErrorCode00 | InternalErrorCode00
| HasqlErrorCode01
| HasqlErrorCode02
| HasqlErrorCode03
| HasqlErrorCode04
-- Uncategorized errors that are not related to a single module
| GeneralErrorCode00
| GeneralErrorCode01
| GeneralErrorCode02
| GeneralErrorCode03
| GeneralErrorCode04
| GeneralErrorCode05
| GeneralErrorCode06
instance JSON.ToJSON ErrorCode where instance JSON.ToJSON ErrorCode where
toJSON e = JSON.toJSON (buildErrorCode e) toJSON e = JSON.toJSON (buildErrorCode e)
@@ -499,6 +476,13 @@ buildErrorCode code = "PGRST" <> case code of
ApiRequestErrorCode08 -> "108" ApiRequestErrorCode08 -> "108"
ApiRequestErrorCode09 -> "109" ApiRequestErrorCode09 -> "109"
ApiRequestErrorCode10 -> "110" ApiRequestErrorCode10 -> "110"
ApiRequestErrorCode11 -> "111"
ApiRequestErrorCode12 -> "112"
ApiRequestErrorCode13 -> "113"
ApiRequestErrorCode14 -> "114"
ApiRequestErrorCode15 -> "115"
ApiRequestErrorCode16 -> "116"
ApiRequestErrorCode17 -> "117"
SchemaCacheErrorCode00 -> "200" SchemaCacheErrorCode00 -> "200"
SchemaCacheErrorCode01 -> "201" SchemaCacheErrorCode01 -> "201"
@@ -509,16 +493,4 @@ buildErrorCode code = "PGRST" <> case code of
JWTErrorCode01 -> "301" JWTErrorCode01 -> "301"
JWTErrorCode02 -> "302" JWTErrorCode02 -> "302"
HasqlErrorCode00 -> "400" InternalErrorCode00 -> "X00"
HasqlErrorCode01 -> "401"
HasqlErrorCode02 -> "402"
HasqlErrorCode03 -> "403"
HasqlErrorCode04 -> "404"
GeneralErrorCode00 -> "500"
GeneralErrorCode01 -> "501"
GeneralErrorCode02 -> "502"
GeneralErrorCode03 -> "503"
GeneralErrorCode04 -> "504"
GeneralErrorCode05 -> "505"
GeneralErrorCode06 -> "506"
+3 -3
View File
@@ -27,7 +27,7 @@ spec = do
[json| [json|
{"hint": null, {"hint": null,
"details": null, "details": null,
"code": "PGRST506", "code": "PGRST117",
"message":"Unsupported HTTP verb: CONNECT"}|] "message":"Unsupported HTTP verb: CONNECT"}|]
{ matchStatus = 405 } { matchStatus = 405 }
@@ -39,7 +39,7 @@ spec = do
[json| [json|
{"hint": null, {"hint": null,
"details": null, "details": null,
"code": "PGRST506", "code": "PGRST117",
"message":"Unsupported HTTP verb: TRACE"}|] "message":"Unsupported HTTP verb: TRACE"}|]
{ matchStatus = 405 } { matchStatus = 405 }
@@ -51,6 +51,6 @@ spec = do
[json| [json|
{"hint": null, {"hint": null,
"details": null, "details": null,
"code": "PGRST506", "code": "PGRST117",
"message":"Unsupported HTTP verb: OTHER"}|] "message":"Unsupported HTTP verb: OTHER"}|]
{ matchStatus = 405 } { matchStatus = 405 }
+3 -3
View File
@@ -1013,21 +1013,21 @@ spec actualPgVersion = do
it "fails if a single column is not selected" $ do it "fails if a single column is not selected" $ do
request methodGet "/images?select=img,name&name=eq.A.png" (acceptHdrs "application/octet-stream") "" request methodGet "/images?select=img,name&name=eq.A.png" (acceptHdrs "application/octet-stream") ""
`shouldRespondWith` `shouldRespondWith`
[json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST502","details":null,"hint":null} |] [json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST113","details":null,"hint":null} |]
{ matchStatus = 406 } { matchStatus = 406 }
request methodGet "/images?select=*&name=eq.A.png" request methodGet "/images?select=*&name=eq.A.png"
(acceptHdrs "application/octet-stream") (acceptHdrs "application/octet-stream")
"" ""
`shouldRespondWith` `shouldRespondWith`
[json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST502","details":null,"hint":null} |] [json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST113","details":null,"hint":null} |]
{ matchStatus = 406 } { matchStatus = 406 }
request methodGet "/images?name=eq.A.png" request methodGet "/images?name=eq.A.png"
(acceptHdrs "application/octet-stream") (acceptHdrs "application/octet-stream")
"" ""
`shouldRespondWith` `shouldRespondWith`
[json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST502","details":null,"hint":null} |] [json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST113","details":null,"hint":null} |]
{ matchStatus = 406 } { matchStatus = 406 }
it "concatenates results if more than one row is returned" $ it "concatenates results if more than one row is returned" $
+6 -6
View File
@@ -1024,7 +1024,7 @@ spec actualPgVersion =
request methodPost "/rpc/ret_rows_with_base64_bin" request methodPost "/rpc/ret_rows_with_base64_bin"
(acceptHdrs "application/octet-stream") "" (acceptHdrs "application/octet-stream") ""
`shouldRespondWith` `shouldRespondWith`
[json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST502","details":null,"hint":null} |] [json| {"message":"application/octet-stream requested but more than one column was selected","code":"PGRST113","details":null,"hint":null} |]
{ matchStatus = 406 } { matchStatus = 406 }
context "only for GET rpc" $ do context "only for GET rpc" $ do
@@ -1094,25 +1094,25 @@ spec actualPgVersion =
it "fails when setting headers with wrong json structure" $ do it "fails when setting headers with wrong json structure" $ do
get "/rpc/bad_guc_headers_1" get "/rpc/bad_guc_headers_1"
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST500","details":null,"hint":null}|] [json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST111","details":null,"hint":null}|]
{ matchStatus = 500 { matchStatus = 500
, matchHeaders = [ matchContentTypeJson ] , matchHeaders = [ matchContentTypeJson ]
} }
get "/rpc/bad_guc_headers_2" get "/rpc/bad_guc_headers_2"
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST500","details":null,"hint":null}|] [json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST111","details":null,"hint":null}|]
{ matchStatus = 500 { matchStatus = 500
, matchHeaders = [ matchContentTypeJson ] , matchHeaders = [ matchContentTypeJson ]
} }
get "/rpc/bad_guc_headers_3" get "/rpc/bad_guc_headers_3"
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST500","details":null,"hint":null}|] [json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST111","details":null,"hint":null}|]
{ matchStatus = 500 { matchStatus = 500
, matchHeaders = [ matchContentTypeJson ] , matchHeaders = [ matchContentTypeJson ]
} }
post "/rpc/bad_guc_headers_1" [json|{}|] post "/rpc/bad_guc_headers_1" [json|{}|]
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST500","details":null,"hint":null}|] [json|{"message":"response.headers guc must be a JSON array composed of objects with a single key and a string value","code":"PGRST111","details":null,"hint":null}|]
{ matchStatus = 500 { matchStatus = 500
, matchHeaders = [ matchContentTypeJson ] , matchHeaders = [ matchContentTypeJson ]
} }
@@ -1183,7 +1183,7 @@ spec actualPgVersion =
it "fails when setting invalid status guc" $ it "fails when setting invalid status guc" $
get "/rpc/send_bad_status" get "/rpc/send_bad_status"
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"response.status guc must be a valid status code","code":"PGRST501","details":null,"hint":null}|] [json|{"message":"response.status guc must be a valid status code","code":"PGRST112","details":null,"hint":null}|]
{ matchStatus = 500 { matchStatus = 500
, matchHeaders = [ matchContentTypeJson ] , matchHeaders = [ matchContentTypeJson ]
} }
+16 -16
View File
@@ -69,7 +69,7 @@ spec =
[("Prefer", "tx=commit"), singular] [("Prefer", "tx=commit"), singular]
[json| { address: "zzz" } |] [json| { address: "zzz" } |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 4 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 4 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -85,7 +85,7 @@ spec =
[("Prefer", "tx=commit"), ("Prefer", "return=representation"), singular] [("Prefer", "tx=commit"), ("Prefer", "return=representation"), singular]
[json| { address: "zzz" } |] [json| { address: "zzz" } |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 4 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 4 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -100,7 +100,7 @@ spec =
request methodPatch "/items?id=gt.0&id=lt.0" request methodPatch "/items?id=gt.0&id=lt.0"
[singular] [json|{"id":1}|] [singular] [json|{"id":1}|]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -109,7 +109,7 @@ spec =
request methodPatch "/items?id=gt.0&id=lt.0" request methodPatch "/items?id=gt.0&id=lt.0"
[("Prefer", "return=representation"), singular] [json|{"id":1}|] [("Prefer", "return=representation"), singular] [json|{"id":1}|]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -141,7 +141,7 @@ spec =
[("Prefer", "tx=commit"), singular] [("Prefer", "tx=commit"), singular]
[json| [ { id: 200, address: "xxx" }, { id: 201, address: "yyy" } ] |] [json| [ { id: 200, address: "xxx" }, { id: 201, address: "yyy" } ] |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -157,7 +157,7 @@ spec =
[("Prefer", "tx=commit"), ("Prefer", "return=representation"), singular] [("Prefer", "tx=commit"), ("Prefer", "return=representation"), singular]
[json| [ { id: 202, address: "xxx" }, { id: 203, address: "yyy" } ] |] [json| [ { id: 202, address: "xxx" }, { id: 203, address: "yyy" } ] |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -173,7 +173,7 @@ spec =
[("Prefer", "tx=commit"), ("Prefer", "return=minimal"), singular] [("Prefer", "tx=commit"), ("Prefer", "return=minimal"), singular]
[json| [ { id: 204, address: "xxx" }, { id: 205, address: "yyy" } ] |] [json| [ { id: 204, address: "xxx" }, { id: 205, address: "yyy" } ] |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -189,7 +189,7 @@ spec =
[singular] [singular]
[json| [ ] |] [json| [ ] |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -199,7 +199,7 @@ spec =
[("Prefer", "return=representation"), singular] [("Prefer", "return=representation"), singular]
[json| [ ] |] [json| [ ] |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -222,7 +222,7 @@ spec =
[("Prefer", "tx=commit"), singular] [("Prefer", "tx=commit"), singular]
"" ""
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -240,7 +240,7 @@ spec =
request methodDelete "/items?id=gt.5&id=lt.11" request methodDelete "/items?id=gt.5&id=lt.11"
[("Prefer", "tx=commit"), ("Prefer", "return=representation"), singular] "" [("Prefer", "tx=commit"), ("Prefer", "return=representation"), singular] ""
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
@@ -257,7 +257,7 @@ spec =
request methodDelete "/items?id=lt.0" request methodDelete "/items?id=lt.0"
[singular] "" [singular] ""
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -266,7 +266,7 @@ spec =
request methodDelete "/items?id=lt.0" request methodDelete "/items?id=lt.0"
[("Prefer", "return=representation"), singular] "" [("Prefer", "return=representation"), singular] ""
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -276,7 +276,7 @@ spec =
request methodPost "/rpc/getproject" request methodPost "/rpc/getproject"
[singular] [json|{ "id": 9999999}|] [singular] [json|{ "id": 9999999}|]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 0 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -299,7 +299,7 @@ spec =
request methodPost "/rpc/getallprojects" request methodPost "/rpc/getallprojects"
[singular] "{}" [singular] "{}"
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 5 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [matchContentTypeSingular] , matchHeaders = [matchContentTypeSingular]
} }
@@ -314,7 +314,7 @@ spec =
[("Prefer", "tx=commit"), singular] [("Prefer", "tx=commit"), singular]
[json| {"id_l": 1, "id_h": 2, "name": "changed"} |] [json| {"id_l": 1, "id_h": 2, "name": "changed"} |]
`shouldRespondWith` `shouldRespondWith`
[json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST505","hint":null}|] [json|{"details":"Results contain 2 rows, application/vnd.pgrst.object+json requires 1 row","message":"JSON object requested, multiple (or no) rows returned","code":"PGRST116","hint":null}|]
{ matchStatus = 406 { matchStatus = 406
, matchHeaders = [ matchContentTypeSingular , matchHeaders = [ matchContentTypeSingular
, "Preference-Applied" <:> "tx=commit" ] , "Preference-Applied" <:> "tx=commit" ]
+5 -5
View File
@@ -199,21 +199,21 @@ spec actualPgVersion =
request methodPut "/tiobe_pls?name=eq.Javascript" [("Range", "0-5")] request methodPut "/tiobe_pls?name=eq.Javascript" [("Range", "0-5")]
[json| [ { "name": "Javascript", "rank": 1 } ]|] [json| [ { "name": "Javascript", "rank": 1 } ]|]
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT","code":"PGRST503","details":null,"hint":null}|] [json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT","code":"PGRST114","details":null,"hint":null}|]
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] } { matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
it "fails if limit is specified" $ it "fails if limit is specified" $
put "/tiobe_pls?name=eq.Javascript&limit=1" put "/tiobe_pls?name=eq.Javascript&limit=1"
[json| [ { "name": "Javascript", "rank": 1 } ]|] [json| [ { "name": "Javascript", "rank": 1 } ]|]
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT","code":"PGRST503","details":null,"hint":null}|] [json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT","code":"PGRST114","details":null,"hint":null}|]
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] } { matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
it "fails if offset is specified" $ it "fails if offset is specified" $
put "/tiobe_pls?name=eq.Javascript&offset=1" put "/tiobe_pls?name=eq.Javascript&offset=1"
[json| [ { "name": "Javascript", "rank": 1 } ]|] [json| [ { "name": "Javascript", "rank": 1 } ]|]
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT","code":"PGRST503","details":null,"hint":null}|] [json|{"message":"Range header and limit/offset querystring parameters are not allowed for PUT","code":"PGRST114","details":null,"hint":null}|]
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] } { matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
it "rejects every other filter than pk cols eq's" $ do it "rejects every other filter than pk cols eq's" $ do
@@ -254,12 +254,12 @@ spec actualPgVersion =
it "fails if the uri primary key doesn't match the payload primary key" $ do it "fails if the uri primary key doesn't match the payload primary key" $ do
put "/tiobe_pls?name=eq.MATLAB" [json| [ { "name": "Perl", "rank": 17 } ]|] put "/tiobe_pls?name=eq.MATLAB" [json| [ { "name": "Perl", "rank": 17 } ]|]
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"Payload values do not match URL in primary key column(s)","code":"PGRST504","details":null,"hint":null}|] [json|{"message":"Payload values do not match URL in primary key column(s)","code":"PGRST115","details":null,"hint":null}|]
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] } { matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
put "/employees?first_name=eq.Wendy&last_name=eq.Anderson" put "/employees?first_name=eq.Wendy&last_name=eq.Anderson"
[json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|] [json| [ { "first_name": "Susan", "last_name": "Heidt", "salary": "48000", "company": "GEX", "occupation": "Railroad engineer" } ]|]
`shouldRespondWith` `shouldRespondWith`
[json|{"message":"Payload values do not match URL in primary key column(s)","code":"PGRST504","details":null,"hint":null}|] [json|{"message":"Payload values do not match URL in primary key column(s)","code":"PGRST115","details":null,"hint":null}|]
{ matchStatus = 400 , matchHeaders = [matchContentTypeJson] } { matchStatus = 400 , matchHeaders = [matchContentTypeJson] }
it "fails if the table has no PK" $ it "fails if the table has no PK" $