feat: RPC POST for function w/single unnamed param

For POST on RPC, allows:

* passing a json object without using `Prefer: params=single-object`
  The function must be defined with a single unnamed json param and
  `Content-Type: application/json` must be specified.

* uploading binary to a function
  The function must be defined with a single unnamed bytea param and
  `Content-Type: application/octet-stream` must be specified.

* uploading raw text to a function
  The function must be defined with a single unnamed text param and
  `Content-Type: text/plain` must be specified.

BREAKING CHANGE If there's a function "my_func" having a single
unnamed json param and other overloaded pairs(with any number of
params), PostgREST won't be able to resolve a POST request to
"my_func". For solving this, you can name the unnamed json param.

my_func(json) -> my_func(prm json)
This commit is contained in:
steve-chavez
2021-08-30 18:17:59 -05:00
committed by Steve Chavez
parent caaa34b5de
commit d4c6abbaec
11 changed files with 209 additions and 76 deletions
+10 -9
View File
@@ -48,7 +48,7 @@ import PostgREST.RangeQuery (NonnegRange, allRange,
restrictRange)
import PostgREST.Request.ApiRequest (Action (..),
ApiRequest (..),
PayloadJSON (..))
Payload (..))
import PostgREST.Request.Parsers
import PostgREST.Request.Preferences
@@ -344,24 +344,25 @@ mutateRequest schema tName apiRequest pkCols readReq = mapLeft ApiRequestError $
-- update/delete filters can be only on the root table
(mutateFilters, logicFilters) = join (***) onlyRoot (iFilters apiRequest, iLogic apiRequest)
onlyRoot = filter (not . ( "." `isInfixOf` ) . fst)
body = pjRaw <$> iPayload apiRequest
body = payRaw <$> iPayload apiRequest -- the body is assumed to be json at this stage(ApiRequest validates)
callRequest :: ProcDescription -> ApiRequest -> ReadRequest -> CallRequest
callRequest proc apiReq readReq = FunctionCall {
funCQi = QualifiedIdentifier (pdSchema proc) (pdName proc)
, funCParams = specifiedParams
, funCArgs = pjRaw <$> iPayload apiReq
, funCParams = callParams
, funCArgs = payRaw <$> iPayload apiReq
, funCScalar = procReturnsScalar proc
, funCMultipleCall = iPreferParameters apiReq == Just MultipleObjects
, funCSingleParam = paramsAsSingleObject
, funCReturning = returningCols readReq []
}
where
paramsAsSingleObject = iPreferParameters apiReq == Just SingleObject
specifiedParams =
if paramsAsSingleObject
then pdParams proc
else filter (\x -> ppName x `S.member` iColumns apiReq) $ pdParams proc
callParams = case pdParams proc of
[prm] | paramsAsSingleObject -> OnePosParam prm
| ppName prm == mempty -> OnePosParam prm
| otherwise -> KeyParams $ specifiedParams [prm]
prms -> KeyParams $ specifiedParams prms
specifiedParams params = filter (\x -> ppName x `S.member` iColumns apiReq) params
returningCols :: ReadRequest -> [FieldName] -> [FieldName]
returningCols rr@(Node _ forest) pkCols