fix: filtering the returned representation whenn using or/and filters on mutations
This commit is contained in:
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. From versio
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Ensure Listener connections are released by @mkleczek in #4614
|
- Ensure Listener connections are released by @mkleczek in #4614
|
||||||
|
- Fix incorrectly filtering the returned representation for PATCH requests when using `or/and` filters by @laurenceisla in #3707
|
||||||
|
|
||||||
## [14.3] - 2026-01-03
|
## [14.3] - 2026-01-03
|
||||||
|
|
||||||
|
|||||||
@@ -963,10 +963,17 @@ addRanges ApiRequest{..} rReq =
|
|||||||
|
|
||||||
addLogicTrees :: ResolverContext -> ApiRequest -> ReadPlanTree -> Either Error ReadPlanTree
|
addLogicTrees :: ResolverContext -> ApiRequest -> ReadPlanTree -> Either Error ReadPlanTree
|
||||||
addLogicTrees ctx ApiRequest{..} rReq =
|
addLogicTrees ctx ApiRequest{..} rReq =
|
||||||
foldr addLogicTreeToNode (Right rReq) qsLogic
|
foldr addLogicTreeToNode (Right rReq) logic
|
||||||
where
|
where
|
||||||
QueryParams.QueryParams{..} = iQueryParams
|
QueryParams.QueryParams{..} = iQueryParams
|
||||||
|
|
||||||
|
logic =
|
||||||
|
case iAction of
|
||||||
|
ActDb (ActRelationRead _ _) -> qsLogic
|
||||||
|
ActDb (ActRoutine _ _) -> qsLogic
|
||||||
|
-- For mutations, take the non-root logic filters. These will only affect the embeddings and not the top level of the returned representation.
|
||||||
|
_ -> filter (not . null . fst) qsLogic
|
||||||
|
|
||||||
addLogicTreeToNode :: (EmbedPath, LogicTree) -> Either Error ReadPlanTree -> Either Error ReadPlanTree
|
addLogicTreeToNode :: (EmbedPath, LogicTree) -> Either Error ReadPlanTree -> Either Error ReadPlanTree
|
||||||
addLogicTreeToNode = updateNode (\t (Node q@ReadPlan{from=fromTable, where_=lf} f) -> Node q{ReadPlan.where_=resolveLogicTree ctx{qi=fromTable} t:lf} f)
|
addLogicTreeToNode = updateNode (\t (Node q@ReadPlan{from=fromTable, where_=lf} f) -> Node q{ReadPlan.where_=resolveLogicTree ctx{qi=fromTable} t:lf} f)
|
||||||
|
|
||||||
|
|||||||
@@ -252,21 +252,39 @@ spec =
|
|||||||
[json|[{"id": 7, "entities":null}, {"id": 8, "entities": {"id": 2}}, {"id": 9, "entities": {"id": 3}}]|]
|
[json|[{"id": 7, "entities":null}, {"id": 8, "entities": {"id": 2}}, {"id": 9, "entities": {"id": 3}}]|]
|
||||||
{ matchStatus = 201 }
|
{ matchStatus = 201 }
|
||||||
|
|
||||||
context "used with PATCH" $
|
context "used with PATCH" $ do
|
||||||
it "succeeds when using and/or params" $
|
it "succeeds when using and/or params" $
|
||||||
request methodPatch "/grandchild_entities?or=(id.eq.1,id.eq.2)&select=id,name"
|
request methodPatch "/grandchild_entities?or=(id.eq.1,id.eq.2)&select=id,name"
|
||||||
[("Prefer", "return=representation")]
|
[("Prefer", "return=representation")]
|
||||||
[json|{ name : "updated grandchild entity"}|] `shouldRespondWith`
|
[json|{ name : "updated grandchild entity"}|] `shouldRespondWith`
|
||||||
[json|[{ "id": 1, "name" : "updated grandchild entity"},{ "id": 2, "name" : "updated grandchild entity"}]|]
|
[json|[{ "id": 1, "name" : "updated grandchild entity"},{ "id": 2, "name" : "updated grandchild entity"}]|]
|
||||||
{ matchHeaders = [matchContentTypeJson] }
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
it "succeeds when the filtered column is modified" $
|
||||||
|
request methodPatch "/entities?select=id,name&or=(name.is.null,name.like.*test*)"
|
||||||
|
[("Prefer", "return=representation")]
|
||||||
|
[json|{ "name" : "updated entity" }|] `shouldRespondWith`
|
||||||
|
[json|[{ "id": 4, "name": "updated entity" }]|]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
it "succeeds when the filtered column is not selected in the returned representation" $
|
||||||
|
request methodPatch "/entities?select=id&or=(name.is.null,name.like.*test*)"
|
||||||
|
[("Prefer", "return=representation")]
|
||||||
|
[json|{ "name" : "updated entity" }|] `shouldRespondWith`
|
||||||
|
[json|[{ "id": 4 }]|]
|
||||||
|
{ matchHeaders = [matchContentTypeJson] }
|
||||||
|
|
||||||
context "used with DELETE" $
|
context "used with DELETE" $ do
|
||||||
it "succeeds when using and/or params" $
|
it "succeeds when using and/or params" $
|
||||||
request methodDelete "/grandchild_entities?or=(id.eq.1,id.eq.2)&select=id,name"
|
request methodDelete "/grandchild_entities?or=(id.eq.1,id.eq.2)&select=id,name"
|
||||||
[("Prefer", "return=representation")]
|
[("Prefer", "return=representation")]
|
||||||
""
|
""
|
||||||
`shouldRespondWith`
|
`shouldRespondWith`
|
||||||
[json|[{ "id": 1, "name" : "grandchild entity 1" },{ "id": 2, "name" : "grandchild entity 2" }]|]
|
[json|[{ "id": 1, "name" : "grandchild entity 1" },{ "id": 2, "name" : "grandchild entity 2" }]|]
|
||||||
|
it "succeeds when the filtered column is not selected in the returned representation" $
|
||||||
|
request methodDelete "/entities?select=id&or=(name.is.null,name.like.*test*)"
|
||||||
|
[("Prefer", "return=representation")]
|
||||||
|
""
|
||||||
|
`shouldRespondWith`
|
||||||
|
[json|[{ "id": 4 }]|]
|
||||||
|
|
||||||
it "can query columns that begin with and/or reserved words" $
|
it "can query columns that begin with and/or reserved words" $
|
||||||
get "/grandchild_entities?or=(and_starting_col.eq.smth, or_starting_col.eq.smth)" `shouldRespondWith` 200
|
get "/grandchild_entities?or=(and_starting_col.eq.smth, or_starting_col.eq.smth)" `shouldRespondWith` 200
|
||||||
|
|||||||
Reference in New Issue
Block a user