@@ -44,6 +44,7 @@ getPayload reqBody contentMediaType QueryParams{qsColumns} action = do
4444 (Just ProcessedJSON {payKeys}, _) -> payKeys
4545 (Just ProcessedUrlEncoded {payKeys}, _) -> payKeys
4646 (Just RawJSON {}, Just cls) -> cls
47+ (Just PgrstPatch {payFields}, _) -> payFields
4748 _ -> S. empty
4849 return (checkedPayload, cols)
4950 where
@@ -69,6 +70,12 @@ getPayload reqBody contentMediaType QueryParams{qsColumns} action = do
6970 (MTTextPlain , True ) -> Right $ RawPay reqBody
7071 (MTTextXML , True ) -> Right $ RawPay reqBody
7172 (MTOctetStream , True ) -> Right $ RawPay reqBody
73+ (MTVndPgrstPatch , False ) ->
74+ if isJust columns
75+ then Right $ RawJSON reqBody
76+ -- Error message too generic?
77+ else note " All objects should contain 3 key-vals: 'op','path' and 'value', where op and path must be a string"
78+ (pgrstPatchPayloadFields reqBody =<< JSON. decode reqBody)
7279 (ct, _) -> Left $ " Content-Type not acceptable: " <> MediaType. toMime ct
7380
7481 shouldParsePayload = case action of
@@ -78,10 +85,10 @@ getPayload reqBody contentMediaType QueryParams{qsColumns} action = do
7885 _ -> False
7986
8087 columns = case action of
81- ActDb (ActRelationMut _ MutationCreate ) -> qsColumns
82- ActDb (ActRelationMut _ MutationUpdate ) -> qsColumns
83- ActDb (ActRoutine _ Inv ) -> qsColumns
84- _ -> Nothing
88+ ActDb (ActRelationMut _ MutationCreate ) -> qsColumns
89+ ActDb (ActRelationMut _ ( MutationUpdate _) ) -> qsColumns
90+ ActDb (ActRoutine _ Inv ) -> qsColumns
91+ _ -> Nothing
8592
8693 isProc = case action of
8794 ActDb (ActRoutine _ _) -> True
@@ -136,3 +143,45 @@ payloadAttributes raw json =
136143 _ -> Just emptyPJArray
137144 where
138145 emptyPJArray = ProcessedJSON (JSON. encode emptyArray) S. empty
146+
147+ -- Here, we verify the following about pgrst patch body:
148+ -- 1. The JSON must be a json array.
149+ -- 2. All objects in the array must have only these three fields:
150+ -- 'op', 'path', 'value'.
151+ -- 3. Finally, extract the 'path' values as fields
152+ --
153+ -- TODO: Return (Either ByteString Payload) for better error messages
154+ pgrstPatchPayloadFields :: RequestBody -> JSON. Value -> Maybe Payload
155+ pgrstPatchPayloadFields raw (JSON. Array arr) =
156+ if V. all isValidPatchObject arr
157+ then PgrstPatch raw . S. fromList <$> getPaths arr
158+ else Nothing
159+ where
160+ isValidPatchObject (JSON. Object o) =
161+ KM. member " op" o &&
162+ KM. member " path" o &&
163+ KM. member " value" o &&
164+ length (KM. keys o) == 3
165+ isValidPatchObject _ = False
166+
167+ getPaths :: V. Vector JSON. Value -> Maybe [Text ]
168+ getPaths ar = if any isNothing maybePaths || not (all extractOp $ V. toList ar)
169+ then Nothing
170+ else Just $ catMaybes maybePaths
171+ where
172+ maybePaths :: [Maybe Text ]
173+ maybePaths = map extractPath $ V. toList ar
174+
175+ extractOp (JSON. Object o) =
176+ case KM. lookup " op" o of
177+ Just op -> op == " set" -- we only have "set" operation, for now
178+ Nothing -> False
179+ extractOp _ = False
180+
181+ extractPath (JSON. Object o) =
182+ case KM. lookup " path" o of
183+ Just (JSON. String path) -> Just path
184+ _ -> Nothing
185+ extractPath _ = Nothing
186+
187+ pgrstPatchPayloadFields _ _ = Nothing
0 commit comments