From 99a63c77d9b9911759a2a6774365150785c12759 Mon Sep 17 00:00:00 2001 From: rakeshkky Date: Fri, 25 Jan 2019 18:09:35 +0530 Subject: [PATCH] fix empty set object returns postgres-error, fix #1448 --- .../src-lib/Hasura/GraphQL/Resolve/Insert.hs | 14 +-------- .../Hasura/GraphQL/Resolve/Mutation.hs | 24 +++++++++++++-- .../update/basic/author_empty_set.yaml | 30 +++++++++++++++++++ server/tests-py/test_graphql_mutations.py | 4 +++ 4 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 server/tests-py/queries/graphql_mutation/update/basic/author_empty_set.yaml diff --git a/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs b/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs index 85b95c8fdb339..808f8c46908e6 100644 --- a/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs +++ b/server/src-lib/Hasura/GraphQL/Resolve/Insert.hs @@ -2,7 +2,6 @@ module Hasura.GraphQL.Resolve.Insert (convertInsert) where -import Control.Arrow (second) import Data.Has import Hasura.Prelude import Hasura.Server.Utils @@ -445,17 +444,6 @@ insertMultipleObjects role tn multiObjIns addCols mutFlds errP = getRet (t, r@(RR.MRet _)) = Just (t, r) getRet _ = Nothing --- | build mutation response for empty objects -withEmptyObjs :: RR.MutFlds -> Convert RespTx -withEmptyObjs = return . mkTx - where - mkTx = return . J.encode . OMap.fromList . map (second convMutFld) - -- generate empty mutation response - convMutFld = \case - RR.MCount -> J.toJSON (0 :: Int) - RR.MExp e -> J.toJSON e - RR.MRet _ -> J.toJSON ([] :: [J.Value]) - prefixErrPath :: (MonadError QErr m) => Field -> m a -> m a prefixErrPath fld = withPathK "selectionSet" . fieldAsPath fld . withPathK "args" @@ -470,7 +458,7 @@ convertInsert role tn fld = prefixErrPath fld $ do annVals <- withArg arguments "objects" asArray -- if insert input objects is empty array then -- do not perform insert and return mutation response - bool (withNonEmptyObjs annVals mutFlds) (withEmptyObjs mutFlds) $ null annVals + bool (withNonEmptyObjs annVals mutFlds) (buildEmptyMutResp mutFlds) $ null annVals where withNonEmptyObjs annVals mutFlds = do InsCtx vn tableCols defValMap relInfoMap updPerm <- getInsCtx tn diff --git a/server/src-lib/Hasura/GraphQL/Resolve/Mutation.hs b/server/src-lib/Hasura/GraphQL/Resolve/Mutation.hs index 23ad40ee656ff..fd15b368a8467 100644 --- a/server/src-lib/Hasura/GraphQL/Resolve/Mutation.hs +++ b/server/src-lib/Hasura/GraphQL/Resolve/Mutation.hs @@ -2,10 +2,13 @@ module Hasura.GraphQL.Resolve.Mutation ( convertUpdate , convertDelete , convertMutResp + , buildEmptyMutResp ) where +import Control.Arrow (second) import Hasura.Prelude +import qualified Data.Aeson as J import qualified Data.HashMap.Strict.InsOrd as OMap import qualified Language.GraphQL.Draft.Syntax as G @@ -117,13 +120,17 @@ convertUpdate tn filterExp fld = do let updExpsM = [ setExpM, incExpM, appendExpM, prependExpM , deleteKeyExpM, deleteElemExpM, deleteAtPathExpM ] - updExp = concat $ catMaybes updExpsM + setItems = concat $ catMaybes updExpsM -- atleast one of update operators is expected unless (any isJust updExpsM) $ throwVE $ "atleast any one of _set, _inc, _append, _prepend, _delete_key, _delete_elem and " <> " _delete_at_path operator is expected" - let p1 = RU.UpdateQueryP1 tn updExp (filterExp, whereExp) mutFlds - return $ RU.updateQueryToTx (p1, prepArgs) + let p1 = RU.UpdateQueryP1 tn setItems (filterExp, whereExp) mutFlds + whenNonEmptyItems = return $ RU.updateQueryToTx (p1, prepArgs) + whenEmptyItems = buildEmptyMutResp mutFlds + -- if there are not set items then do not perform + -- update and return empty mutation response + bool whenNonEmptyItems whenEmptyItems $ null setItems where args = _fArguments fld @@ -138,3 +145,14 @@ convertDelete tn filterExp fld = do args <- get let p1 = RD.DeleteQueryP1 tn (filterExp, whereExp) mutFlds return $ RD.deleteQueryToTx (p1, args) + +-- | build mutation response for empty objects +buildEmptyMutResp :: Monad m => RR.MutFlds -> m RespTx +buildEmptyMutResp = return . mkTx + where + mkTx = return . J.encode . OMap.fromList . map (second convMutFld) + -- generate empty mutation response + convMutFld = \case + RR.MCount -> J.toJSON (0 :: Int) + RR.MExp e -> J.toJSON e + RR.MRet _ -> J.toJSON ([] :: [J.Value]) diff --git a/server/tests-py/queries/graphql_mutation/update/basic/author_empty_set.yaml b/server/tests-py/queries/graphql_mutation/update/basic/author_empty_set.yaml new file mode 100644 index 0000000000000..4cabc10a86baa --- /dev/null +++ b/server/tests-py/queries/graphql_mutation/update/basic/author_empty_set.yaml @@ -0,0 +1,30 @@ +description: Update mutation on author +url: /v1alpha1/graphql +status: 200 +response: + data: + update_author: + affected_rows: 0 + returning: [] +query: + variables: + set: {} + query: | + mutation update_author ($set: author_set_input!) { + update_author( + where: {id: {_eq: 1}}, + _set: $set + ) { + affected_rows + returning{ + id + name + articles{ + id + title + content + is_published + } + } + } + } diff --git a/server/tests-py/test_graphql_mutations.py b/server/tests-py/test_graphql_mutations.py index 447ffb39844c5..dd74f6c215309 100644 --- a/server/tests-py/test_graphql_mutations.py +++ b/server/tests-py/test_graphql_mutations.py @@ -255,6 +255,10 @@ class TestGraphqlUpdateBasic(DefaultTestQueries): def test_set_author_name(self, hge_ctx): check_query_f(hge_ctx, self.dir() + "/author_set_name.yaml") + def test_empty_set_author(self, hge_ctx): + check_query_f(hge_ctx, self.dir() + "/author_empty_set.yaml") + hge_ctx.may_skip_test_teardown = True + def test_set_person_details(self, hge_ctx): check_query_f(hge_ctx, self.dir() + "/person_set_details.yaml")