From 022975eb321bbe33d0d314aa0ac7c6e9789af1a8 Mon Sep 17 00:00:00 2001 From: Sean Grove Date: Sun, 24 Nov 2019 20:53:34 -0800 Subject: [PATCH 1/6] Unify dynamic mutation definition --- src/hooks/UrqlUseMutation.re | 7 ++++--- src/hooks/UrqlUseMutation.rei | 16 +++++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/hooks/UrqlUseMutation.re b/src/hooks/UrqlUseMutation.re index 30214df7..89f705ba 100644 --- a/src/hooks/UrqlUseMutation.re +++ b/src/hooks/UrqlUseMutation.re @@ -62,7 +62,8 @@ let useMutation = (~request) => { (response, executeMutation); }; -let useDynamicMutation = (~query, ~parse) => { +let useDynamicMutation = definition => { + let (parse, query, composeVariables) = definition; let (responseJs, executeMutationJs) = useMutationJs(query); let response = @@ -72,8 +73,8 @@ let useDynamicMutation = (~query, ~parse) => { ); let executeMutation = - React.useCallback1( - request => executeMutationJs(Some(request##variables)), + React.useMemo1( + () => composeVariables(request => executeMutationJs(Some(request))), [|executeMutationJs|], ); diff --git a/src/hooks/UrqlUseMutation.rei b/src/hooks/UrqlUseMutation.rei index 1a56d634..1beffe71 100644 --- a/src/hooks/UrqlUseMutation.rei +++ b/src/hooks/UrqlUseMutation.rei @@ -6,9 +6,15 @@ let useMutation: ); let useDynamicMutation: - (~query: string, ~parse: Js.Json.t => 'response) => ( - UrqlTypes.hookResponse('response), - {.. "variables": Js.Json.t} => - Js.Promise.t(UrqlClient.ClientTypes.operationResult), - ); + ( + // `parse` + Js.Json.t => 'a, + // `query` + string, + // `composeVariables` + (Js.Json.t => Js.Promise.t(UrqlClient.ClientTypes.operationResult)) => + 'b, + ) + ) => + (UrqlTypes.hookResponse('a), 'b); From d0dd4d3f611a453d079435b1afebbe48f06a582a Mon Sep 17 00:00:00 2001 From: Sean Grove Date: Sun, 24 Nov 2019 20:57:11 -0800 Subject: [PATCH 2/6] Update mutation example --- examples/3-mutation/src/Dog.re | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/3-mutation/src/Dog.re b/examples/3-mutation/src/Dog.re index 71f61902..ecf23b57 100644 --- a/examples/3-mutation/src/Dog.re +++ b/examples/3-mutation/src/Dog.re @@ -79,10 +79,7 @@ let make = /* Example of using hooks where the variables are only known when the mutation runs. */ let (_, executePatMutation) = - Hooks.useDynamicMutation( - ~query=Mutations.PatDog.query, - ~parse=Mutations.PatDog.parse, - ); + Hooks.useDynamicMutation(Mutations.PatDog.definition);
name @@ -98,9 +95,7 @@ let make = emoji={j|✋|j} count={string_of_int(pats)} hex="db4d3f" - onClick={_ => - executePatMutation(Mutations.PatDog.make(~key=id, ())) |> ignore - } + onClick={_ => executePatMutation(~key=id, ()) |> ignore} /> Date: Mon, 25 Nov 2019 12:24:00 -0800 Subject: [PATCH 3/6] Update docs --- docs/api.md | 21 ++++++++++----------- src/UrqlTypes.re | 9 +++++++++ src/hooks/UrqlUseMutation.rei | 16 +++++----------- 3 files changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/api.md b/docs/api.md index 5191fb2f..cf26f42c 100644 --- a/docs/api.md +++ b/docs/api.md @@ -121,25 +121,24 @@ Check out `examples/3-mutation` to see an example of using the `useMutation` hoo ### `useDynamicMutation` -`useDyanmicMutation` is quite similar to `useMutation`, except it is a hook reserved for when you want to **dynamically** pass in variables to the `executeMutation` function _at execution time_. In constrast, `useMutation` applies variables immediately when it is called _at render time_. +`useDynamicMutation` is quite similar to `useMutation`, except it is a hook reserved for when you want to **dynamically** pass in variables to the `executeMutation` function _at execution time_. In constrast, `useMutation` applies variables immediately when it is called _at render time_. -A good example of a case where `useDyanmicMutation` comes in handy is when you need to execute a mutation with variables retrieved from `useQuery` in the same component. With `useMutation`, you'd have to provide a "fallback" `variables` argument, then rely on `useQuery` running to populate the proper `variables` in `useMutation`. With `useDynamicMutation`, this becomes much simpler – see the Example section below. +A good example of a case where `useDynamicMutation` comes in handy is when you need to execute a mutation with variables retrieved from `useQuery` in the same component. With `useMutation`, you'd have to provide a "fallback" `variables` argument, then rely on `useQuery` running to populate the proper `variables` in `useMutation`. With `useDynamicMutation`, this becomes much simpler – see the Example section below. #### Arguments -| Argument | Type | Description | -| -------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `query` | `string` | The query string for your GraphQL mutation. | -| `parse` | `Js.Json.t => 'response` | A function describing how to parse the JSON returned by your GraphQL API. If using `graphql_ppx_re` or `graphql_ppx` this is provided by accessing the `parse` function on your mutation module. | +| Argument | Type | Description | +| ------------ | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------| +| `definition` | `(Js.Json.t => 'response, string, UrqlTypes.graphqlDefinition)` | The definition of your Graphql mutation. If using graphql_ppx_re, this is `MyMutation.definition`. | ### Return Type -`useDynamicMutation` returns nearly the same tuple as `useMutation`, containing the result of executing your GraphQL mutation as a record, `result`, and a function for executing the mutation imperatively, `executeMutation`. Unlike `useMutation`, the `executeMutation` function returned by `useDynamicMutation` accepts an argument for `variables` of type `Js.Json.t`. +`useDynamicMutation` returns nearly the same tuple as `useMutation`, containing the result of executing your GraphQL mutation as a record, `result`, and a function for executing the mutation imperatively, `executeMutation`. Unlike `useMutation`, the `executeMutation` function returned by `useDynamicMutation` accepts all your variables as named arguments. -| Return Value | Type | Description | -| ----------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `result` | `UrqlTypes.hookResponse('response)` | A record containing fields for `fetching`, `data`, `error`, and `response`. `response` is a variant containing constructors for `Data`, `Error`, `Fetching` and `NotFound`. Useful for pattern matching to render conditional UI. | -| `executeMutation` | `{.. variables: Js.Json.t } => Js.Promise.t(Client.Types.operationResult)` | A function for imperatively executing the mutation, which accepts a `variables` argument. | +| Return Value | Type | Description | +| ----------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `result` | `UrqlTypes.hookResponse('response)` | A record containing fields for `fetching`, `data`, `error`, and `response`. `response` is a variant containing constructors for `Data`, `Error`, `Fetching` and `NotFound`. Useful for pattern matching to render conditional UI. | +| `executeMutation` | `(~myVar1, ~myVar2, ()) => Js.Promise.t(Client.Types.operationResult)` | A function for imperatively executing the mutation, which accepts all the variables as named arguments. | #### Example diff --git a/src/UrqlTypes.re b/src/UrqlTypes.re index f7fc893f..c63535ee 100644 --- a/src/UrqlTypes.re +++ b/src/UrqlTypes.re @@ -48,3 +48,12 @@ type jsResponse('response) = { [@bs.optional] [@bs.as "error"] jsError: UrqlCombinedError.combinedErrorJs, }; + +type graphqlDefinition('parseResult, 'composeReturnType, 'hookReturnType) = ( + // `parse` + Js.Json.t => 'parseResult, + // `query` + string, + // `composeVariables` + (Js.Json.t => 'composeReturnType) => 'hookReturnType, +); diff --git a/src/hooks/UrqlUseMutation.rei b/src/hooks/UrqlUseMutation.rei index 1beffe71..cdbcaf9b 100644 --- a/src/hooks/UrqlUseMutation.rei +++ b/src/hooks/UrqlUseMutation.rei @@ -6,15 +6,9 @@ let useMutation: ); let useDynamicMutation: - ( - ( - // `parse` - Js.Json.t => 'a, - // `query` - string, - // `composeVariables` - (Js.Json.t => Js.Promise.t(UrqlClient.ClientTypes.operationResult)) => - 'b, - ) + UrqlTypes.graphqlDefinition( + 'parsedResponse, + Js.Promise.t(UrqlClient.ClientTypes.operationResult), + 'executeMutationFunction, ) => - (UrqlTypes.hookResponse('a), 'b); + (UrqlTypes.hookResponse('parsedResponse), 'executeMutationFunction); From cfeb3acb0eb9e5a6700c3e76b5927c6072b14485 Mon Sep 17 00:00:00 2001 From: Avery Morin Date: Mon, 25 Nov 2019 12:26:15 -0800 Subject: [PATCH 4/6] Add ellipsis to type --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index cf26f42c..911fa38f 100644 --- a/docs/api.md +++ b/docs/api.md @@ -138,7 +138,7 @@ A good example of a case where `useDynamicMutation` comes in handy is when you n | Return Value | Type | Description | | ----------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `result` | `UrqlTypes.hookResponse('response)` | A record containing fields for `fetching`, `data`, `error`, and `response`. `response` is a variant containing constructors for `Data`, `Error`, `Fetching` and `NotFound`. Useful for pattern matching to render conditional UI. | -| `executeMutation` | `(~myVar1, ~myVar2, ()) => Js.Promise.t(Client.Types.operationResult)` | A function for imperatively executing the mutation, which accepts all the variables as named arguments. | +| `executeMutation` | `(~myVar1, ~myVar2, ..., ()) => Js.Promise.t(Client.Types.operationResult)` | A function for imperatively executing the mutation, which accepts all the variables as named arguments. | #### Example From fada20ecbfcf8bfae3b00d354ced0e9d9fc51207 Mon Sep 17 00:00:00 2001 From: Avery Morin Date: Mon, 25 Nov 2019 16:58:40 -0800 Subject: [PATCH 5/6] Update ppx version in example --- examples/3-mutation/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/3-mutation/package.json b/examples/3-mutation/package.json index b0c54190..c3e1e7f1 100644 --- a/examples/3-mutation/package.json +++ b/examples/3-mutation/package.json @@ -17,7 +17,7 @@ "reason-urql": "link:../../" }, "devDependencies": { - "@baransu/graphql_ppx_re": "^0.3.2", + "@baransu/graphql_ppx_re": "^0.4.0", "bs-platform": "6.2.1", "webpack": "^4.29.6", "webpack-cli": "^3.2.3", From dc58ba756477b65d540fe6463d1edbc20293ef5a Mon Sep 17 00:00:00 2001 From: Avery Morin Date: Mon, 25 Nov 2019 17:00:02 -0800 Subject: [PATCH 6/6] update yarn.lock --- examples/3-mutation/yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/3-mutation/yarn.lock b/examples/3-mutation/yarn.lock index 8a0e3ebb..6eef9da7 100644 --- a/examples/3-mutation/yarn.lock +++ b/examples/3-mutation/yarn.lock @@ -25,10 +25,10 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" -"@baransu/graphql_ppx_re@^0.3.2": - version "0.3.2" - resolved "https://registry.yarnpkg.com/@baransu/graphql_ppx_re/-/graphql_ppx_re-0.3.2.tgz#6876609be84853b1da6184b7868731066a892851" - integrity sha512-DseaS4enJpd43MyTEQZagbEktCzE0wpI96QSxOYR9AHpkgLNrSaM92yi8FBV8Q4sYmFX9191Bdjp+30Y0KWXwQ== +"@baransu/graphql_ppx_re@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@baransu/graphql_ppx_re/-/graphql_ppx_re-0.4.0.tgz#24f01e19d030768bba85a8676c70679c8fb63725" + integrity sha512-vCWaBTbLRHDRvl72e80UH1Xo6Rp7JaBJgBgt24jBX1zXPdpvELObwxapmaSdPHK+wI31X0fRJu9z6yD7IAlBDA== "@emotion/babel-utils@^0.6.4": version "0.6.10"