Remove PUT restriction for all columns/single row

Fixes https://github.com/PostgREST/postgrest/issues/1452.

The single row restriction can be lifted because the
PUT will consider only the first object of the array.
This commit is contained in:
steve-chavez
2020-05-02 11:51:32 -05:00
committed by Steve Chavez
parent 9a52632024
commit 10c363b588
6 changed files with 27 additions and 56 deletions
+5 -6
View File
@@ -191,11 +191,10 @@ userApiRequest confSchemas rootSpec req reqBody
(CTOther "application/x-www-form-urlencoded", _) ->
let json = M.fromList . map (toS *** JSON.String . toS) . parseSimpleQuery $ toS reqBody
keys = S.fromList $ M.keys json in
Right $ ProcessedJSON (JSON.encode json) PJObject keys
Right $ ProcessedJSON (JSON.encode json) keys
(ct, _) ->
Left $ toS $ "Content-Type not acceptable: " <> toMime ct
rpcPrmsToJson = ProcessedJSON (JSON.encode $ M.fromList $ second JSON.toJSON <$> rpcQParams)
PJObject (S.fromList $ fst <$> rpcQParams)
rpcPrmsToJson = ProcessedJSON (JSON.encode $ M.fromList $ second JSON.toJSON <$> rpcQParams) (S.fromList $ fst <$> rpcQParams)
topLevelRange = fromMaybe allRange $ M.lookup "limit" ranges -- if no limit is specified, get all the request rows
action =
case method of
@@ -334,14 +333,14 @@ payloadAttributes raw json =
JSON.Object x -> S.fromList (M.keys x) == canonicalKeys
_ -> False) arr in
if areKeysUniform
then Just $ ProcessedJSON raw (PJArray $ V.length arr) canonicalKeys
then Just $ ProcessedJSON raw canonicalKeys
else Nothing
Just _ -> Nothing
Nothing -> Just emptyPJArray
JSON.Object o -> Just $ ProcessedJSON raw PJObject (S.fromList $ M.keys o)
JSON.Object o -> Just $ ProcessedJSON raw (S.fromList $ M.keys o)
-- truncate everything else to an empty array.
_ -> Just emptyPJArray
where
emptyPJArray = ProcessedJSON (JSON.encode emptyArray) (PJArray 0) S.empty
emptyPJArray = ProcessedJSON (JSON.encode emptyArray) S.empty
+3 -11
View File
@@ -219,22 +219,14 @@ app dbStructure proc cols conf apiRequest =
else
return $ responseLBS status headers rBody
(ActionSingleUpsert, TargetIdent (QualifiedIdentifier tSchema tName), Just ProcessedJSON{pjRaw, pjType, pjKeys}) ->
(ActionSingleUpsert, TargetIdent (QualifiedIdentifier tSchema tName), Just pJson) ->
case mutateSqlParts tSchema tName of
Left errorResponse -> return errorResponse
Right (sq, mq) -> do
let isSingle = case pjType of
PJArray len -> len == 1
PJObject -> True
colNames = colName <$> tableCols dbStructure tSchema tName
Right (sq, mq) ->
if topLevelRange /= allRange
then return . errorResponseFor $ PutRangeNotAllowedError
else if not isSingle
then return . errorResponseFor $ PutSingletonError
else if S.fromList colNames /= pjKeys
then return . errorResponseFor $ PutPayloadIncompleteError
else do
row <- H.statement (toS pjRaw) $
row <- H.statement (toS $ pjRaw pJson) $
createWriteStatement sq mq (contentType == CTSingularJSON) False
(contentType == CTTextCSV) (iPreferRepresentation apiRequest) [] pgVer
let (_, queryTotal, _, body, gucHeaders) = row
+9 -17
View File
@@ -223,10 +223,8 @@ data SimpleError
= GucHeadersError
| BinaryFieldError ContentType
| ConnectionLostError
| PutSingletonError
| PutMatchingPkError
| PutRangeNotAllowedError
| PutPayloadIncompleteError
| JwtTokenMissing
| JwtTokenInvalid Text
| SingularityError Integer
@@ -234,17 +232,15 @@ data SimpleError
deriving (Show, Eq)
instance PgrstError SimpleError where
status GucHeadersError = HT.status500
status (BinaryFieldError _) = HT.status406
status ConnectionLostError = HT.status503
status PutSingletonError = HT.status400
status PutMatchingPkError = HT.status400
status PutRangeNotAllowedError = HT.status400
status PutPayloadIncompleteError = HT.status400
status JwtTokenMissing = HT.status500
status (JwtTokenInvalid _) = HT.unauthorized401
status (SingularityError _) = HT.status406
status (ContentTypeError _) = HT.status415
status GucHeadersError = HT.status500
status (BinaryFieldError _) = HT.status406
status ConnectionLostError = HT.status503
status PutMatchingPkError = HT.status400
status PutRangeNotAllowedError = HT.status400
status JwtTokenMissing = HT.status500
status (JwtTokenInvalid _) = HT.unauthorized401
status (SingularityError _) = HT.status406
status (ContentTypeError _) = HT.status415
headers (SingularityError _) = [toHeader CTSingularJSON]
headers (JwtTokenInvalid m) = [toHeader CTApplicationJSON, invalidTokenHeader m]
@@ -258,12 +254,8 @@ instance JSON.ToJSON SimpleError where
toJSON ConnectionLostError = JSON.object [
"message" .= ("Database connection lost, retrying the connection." :: Text)]
toJSON PutSingletonError = JSON.object [
"message" .= ("PUT payload must contain a single row" :: Text)]
toJSON PutRangeNotAllowedError = JSON.object [
"message" .= ("Range header and limit/offset querystring parameters are not allowed for PUT" :: Text)]
toJSON PutPayloadIncompleteError = JSON.object [
"message" .= ("You must specify all columns in the payload when using PUT" :: Text)]
toJSON PutMatchingPkError = JSON.object [
"message" .= ("Payload values do not match URL in primary key column(s)" :: Text)]
+1 -2
View File
@@ -309,9 +309,8 @@ data PayloadJSON =
ProcessedJSON {
-- | This is the raw ByteString that comes from the request body.
-- We cache this instead of an Aeson Value because it was detected that for large payloads the encoding
-- had high memory usage, see #1005 for more details
-- had high memory usage, see https://github.com/PostgREST/postgrest/pull/1005 for more details
pjRaw :: BL.ByteString
, pjType :: PJType
-- | Keys of the object or if it's an array these keys are guaranteed to be the same across all its objects
, pjKeys :: S.Set Text
}|