From 26fad3868de7e89d993fe4f28754514788a8e53e Mon Sep 17 00:00:00 2001 From: parkerziegler Date: Mon, 12 Oct 2020 09:14:33 -0600 Subject: [PATCH] Begin migration to @reasonml-community/graphql-ppx, starting with client.execute* methods. --- bsconfig.json | 6 +- .../1-execute-query-mutation/bsconfig.json | 5 +- .../1-execute-query-mutation/package.json | 2 +- .../1-execute-query-mutation/public/index.css | 81 +++++ .../public/index.html | 12 +- .../1-execute-query-mutation/src/Previewer.re | 170 ++++----- .../src/PreviewerStyles.re | 53 --- examples/1-execute-query-mutation/yarn.lock | 17 +- package.json | 1 + src/Client.re | 344 +++++++++++------- src/Client.rei | 64 +++- src/Types.re | 19 +- src/Types.rei | 19 +- src/Utils.re | 4 +- src/Utils.rei | 4 +- src/hooks/UseMutation.re | 4 +- src/hooks/UseMutation.rei | 4 +- 17 files changed, 484 insertions(+), 325 deletions(-) create mode 100644 examples/1-execute-query-mutation/public/index.css delete mode 100644 examples/1-execute-query-mutation/src/PreviewerStyles.re diff --git a/bsconfig.json b/bsconfig.json index af135b5e..052247cc 100644 --- a/bsconfig.json +++ b/bsconfig.json @@ -23,7 +23,11 @@ } ], "suffix": ".bs.js", - "bs-dependencies": ["reason-react", "wonka", "bs-fetch"], + "bs-dependencies": [ + "reason-react", + "wonka", + "bs-fetch" + ], "bs-dev-dependencies": ["@glennsl/bs-jest"], "refmt": 3, "warnings": { diff --git a/examples/1-execute-query-mutation/bsconfig.json b/examples/1-execute-query-mutation/bsconfig.json index 4876dc00..7c78db27 100644 --- a/examples/1-execute-query-mutation/bsconfig.json +++ b/examples/1-execute-query-mutation/bsconfig.json @@ -21,11 +21,12 @@ "wonka", "reason-react", "bs-css-emotion", - "bs-css" + "bs-css", + "@reasonml-community/graphql-ppx" ], "refmt": 3, "warnings": { "error": "+5" }, - "ppx-flags": ["@baransu/graphql_ppx_re/ppx"] + "ppx-flags": ["@reasonml-community/graphql-ppx/ppx"] } diff --git a/examples/1-execute-query-mutation/package.json b/examples/1-execute-query-mutation/package.json index 6ca67899..6fdac9b6 100644 --- a/examples/1-execute-query-mutation/package.json +++ b/examples/1-execute-query-mutation/package.json @@ -12,12 +12,12 @@ "start:demo": "webpack-dev-server" }, "dependencies": { + "@reasonml-community/graphql-ppx": "^1.0.1", "bs-css-emotion": "^1.2.0", "reason-react": "^0.7.0", "reason-urql": "link:../../" }, "devDependencies": { - "@baransu/graphql_ppx_re": "^0.7.1", "bs-platform": "7.3.2", "webpack": "^4.43.0", "webpack-cli": "^3.3.11", diff --git a/examples/1-execute-query-mutation/public/index.css b/examples/1-execute-query-mutation/public/index.css new file mode 100644 index 00000000..f098a6ce --- /dev/null +++ b/examples/1-execute-query-mutation/public/index.css @@ -0,0 +1,81 @@ +.previewer { + display: grid; + grid-template-columns: 1fr; + row-gap: 1rem; + max-width: 1280px; + margin-left: auto; + margin-right: auto; +} + +@media (min-width: 640px) { + .previewer { + grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-template-rows: repeat(2, 1fr); + column-gap: 2rem; + height: 100%; + } +} + +.quadrant { + display: flex; + flex-direction: column; + overflow: hidden; +} + +.quadrant > * { + margin-top: 0; + margin-bottom: 0; +} + +.quadrant > * + * { + margin-top: 1rem; +} + +.quadrant__section { + margin: 1rem; +} + +.quadrant__title { + font-size: 2rem; + font-family: "DM Mono", monospace; +} + +.quadrant__button { + align-self: self-start; + background-color: white; + font-size: 1.4rem; + border-radius: 2.5rem; + padding: 0.75rem; + cursor: pointer; + border-width: 2px; + border-style: solid; +} + +.quadrant__button--teal { + border-color: #48a9dc; + color: #48a9dc; +} + +.quadrant__button--orange { + border-color: #db4d3f; + color: #db4d3f; +} + +.quadrant__code { + color: #ffffff; + padding: 1rem; + font-size: 1.4rem; + white-space: pre; + font-family: "DM Mono", monospace; + border-radius: 0.5rem; + max-height: 20rem; + overflow: auto; +} + +.quadrant__code--teal { + background: #48a9dc; +} + +.quadrant__code--orange { + background: #db4d3f; +} diff --git a/examples/1-execute-query-mutation/public/index.html b/examples/1-execute-query-mutation/public/index.html index 7f08433c..b1864c70 100644 --- a/examples/1-execute-query-mutation/public/index.html +++ b/examples/1-execute-query-mutation/public/index.html @@ -2,16 +2,26 @@ + reason-urql +
diff --git a/examples/1-execute-query-mutation/src/Previewer.re b/examples/1-execute-query-mutation/src/Previewer.re index 4365a932..d8bc551f 100644 --- a/examples/1-execute-query-mutation/src/Previewer.re +++ b/examples/1-execute-query-mutation/src/Previewer.re @@ -15,8 +15,6 @@ module GetAllDogs = [%graphql |} ]; -let queryRequest = GetAllDogs.make(); - module LikeDog = [%graphql {| mutation likeDog($key: ID!) { @@ -29,26 +27,24 @@ module LikeDog = [%graphql |} ]; -let mutationRequest = LikeDog.make(~key="VmeRTX7j-", ()); - type state = { - query: string, - mutation: string, + query: option(Js.Json.t), + mutation: option(Js.Json.t), fetchingQuery: bool, fetchingMutation: bool, }; type action = - | SetQuery(string) + | SetQuery(Js.Json.t) | ClearQuery - | SetMutation(string) + | SetMutation(Js.Json.t) | ClearMutation | SetQueryFetching(bool) | SetMutationFetching(bool); let initialState = { - query: "", - mutation: "", + query: None, + mutation: None, fetchingQuery: false, fetchingMutation: false, }; @@ -59,10 +55,10 @@ let make = () => { React.useReducer( (state, action) => switch (action) { - | SetQuery(query) => {...state, query} - | ClearQuery => {...state, query: ""} - | SetMutation(mutation) => {...state, mutation} - | ClearMutation => {...state, mutation: ""} + | SetQuery(query) => {...state, query: Some(query)} + | ClearQuery => {...state, query: None} + | SetMutation(mutation) => {...state, mutation: Some(mutation)} + | ClearMutation => {...state, mutation: None} | SetQueryFetching(fetching) => {...state, fetchingQuery: fetching} | SetMutationFetching(fetching) => { ...state, @@ -77,7 +73,8 @@ let make = () => { Client.executeQuery( ~client, - ~request=queryRequest, + ~request=(module GetAllDogs), + ~variables=GetAllDogs.makeVariables(), ~requestPolicy=`CacheAndNetwork, (), ) @@ -86,15 +83,9 @@ let make = () => { switch (Client.(data.response)) { | Data(d) => - switch (Js.Json.stringifyAny(d)) { - | Some(s) => dispatch(SetQuery(s)) - | None => () - } - | Error(e) => - switch (Js.Json.stringifyAny(e)) { - | Some(s) => dispatch(SetQuery(s)) - | None => () - } + dispatch(SetQuery(d->GetAllDogs.serialize->GetAllDogs.toJson)) + | Error(_e) => + dispatch(SetQuery(Js.Json.string("An error occured"))) | _ => () }; }); @@ -103,114 +94,105 @@ let make = () => { let executeMutation = () => { dispatch(SetMutationFetching(true)); - Client.executeMutation(~client, ~request=mutationRequest, ()) + Client.executeMutation( + ~client, + ~request=(module LikeDog), + ~variables=LikeDog.makeVariables(~key="VmeRTX7j-", ()), + (), + ) |> Wonka.subscribe((. data) => { dispatch(SetMutationFetching(false)); switch (Client.(data.response)) { | Data(d) => - switch (Js.Json.stringifyAny(d)) { - | Some(s) => dispatch(SetMutation(s)) - | None => () - } - | Error(e) => - switch (Js.Json.stringifyAny(e)) { - | Some(s) => dispatch(SetMutation(s)) - | None => () - } + dispatch(SetMutation(d->LikeDog.serialize->LikeDog.toJson)) + | Error(_e) => + dispatch(SetMutation(Js.Json.string("An error occurred"))) | _ => () }; }); }; -
-
-
- "Query"->React.string -
PreviewerStyles.code}> - {|query dogs { +
+
+ "Query"->React.string +
+ {|query dogs { dogs { name breed likes } }|} - ->React.string -
- -
- {switch (String.length(state.query), state.fetchingQuery) { - | (0, false) => React.null + ->React.string +
+ +
+
+ {switch (state.query, state.fetchingQuery) { + | (None, false) => React.null | (_, true) => -
- - "Loading"->React.string - -
+ "Loading"->React.string | _ => -
- - "Result"->React.string - -
PreviewerStyles.code}> - state.query->React.string + <> + "Result"->React.string +
+ {state.query + ->Belt.Option.getWithDefault(Js.Json.string("")) + ->Js.Json.stringifyWithSpace(2) + ->React.string}
-
+ }}
-
-
- "Mutation"->React.string -
PreviewerStyles.code}> - {|mutation likeDog($key: ID!) { +
+ "Mutation"->React.string +
+ {|mutation likeDog($key: ID!) { likeDog(key: $key) { name breed likes } }|} - ->React.string -
- -
- {switch (String.length(state.mutation), state.fetchingMutation) { - | (0, false) => React.null + ->React.string +
+ + +
+ {switch (state.mutation, state.fetchingMutation) { + | (None, false) => React.null | (_, true) => -
- - "Loading"->React.string - -
+ "Loading"->React.string + | _ => -
- - "Result"->React.string - -
PreviewerStyles.code}> - state.mutation->React.string + <> + "Result"->React.string +
+ {state.mutation + ->Belt.Option.getWithDefault(Js.Json.string("")) + ->Js.Json.stringifyWithSpace(2) + ->React.string}
-
+ }}
; diff --git a/examples/1-execute-query-mutation/src/PreviewerStyles.re b/examples/1-execute-query-mutation/src/PreviewerStyles.re deleted file mode 100644 index 5bd63f09..00000000 --- a/examples/1-execute-query-mutation/src/PreviewerStyles.re +++ /dev/null @@ -1,53 +0,0 @@ -open Css; - -let previewer = style([display(flexBox), padding(px(20))]); - -let side = - style([ - display(flexBox), - flexDirection(column), - alignItems(center), - flexBasis(pct(50.)), - ]); - -let section = style([margin(px(10))]); - -let title = - style([ - fontSize(rem(1.5)), - fontFamily(`custom("'Space Mono', sans-serif")), - margin(px(5)), - ]); - -let button = bdColor => - style([ - borderColor(hex(bdColor)), - color(hex(bdColor)), - backgroundColor(white), - fontSize(rem(1.2)), - margin(px(10)), - borderRadius(px(25)), - padding(px(10)), - cursor(`pointer), - ]); - -let code = bgColor => - style([ - backgroundColor(hex(bgColor)), - color(white), - padding(px(20)), - opacity(0.5), - whiteSpace(`pre), - fontFamily(`custom("'Space Mono', sans-serif")), - borderRadius(px(5)), - maxHeight(px(200)), - overflow(`auto), - width(vw(30.)), - ]); - -type colors = { - query: string, - mutation: string, -}; - -let colors = {query: "48a9dc", mutation: "db4d3f"}; diff --git a/examples/1-execute-query-mutation/yarn.lock b/examples/1-execute-query-mutation/yarn.lock index 55b3d88c..d1ecb267 100644 --- a/examples/1-execute-query-mutation/yarn.lock +++ b/examples/1-execute-query-mutation/yarn.lock @@ -46,11 +46,6 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@baransu/graphql_ppx_re@^0.7.1": - version "0.7.1" - resolved "https://registry.yarnpkg.com/@baransu/graphql_ppx_re/-/graphql_ppx_re-0.7.1.tgz#8146a36a94d56e65692d74488e2bd6cbd4eb8dc9" - integrity sha512-S9RYUWk8IkFxjE1Xl5eohRgbHJP5nCWOD6J1hMV3hY+D43igDrILq1doAXJatYB82BxcsrBC9V+VeU2LtCxIDw== - "@emotion/cache@^10.0.27": version "10.0.29" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0" @@ -107,6 +102,11 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== +"@reasonml-community/graphql-ppx@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@reasonml-community/graphql-ppx/-/graphql-ppx-1.0.1.tgz#aabbaa2d32b290c1576c4d4c53e26ffce4bed98c" + integrity sha512-lYPM6J5lth3VWyzOdAIEerStK70xm0jObC86iyhrfl7lm7RFls0W+QyxbOhajpzl8MwFtNGq5gYZAi/E9GL7bw== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -3386,11 +3386,8 @@ reason-react@^0.7.0: react-dom ">=16.8.1" "reason-urql@link:../..": - version "2.0.0" - dependencies: - bs-fetch "^0.6.2" - graphql "^15.3.0" - urql "1.10.0" + version "0.0.0" + uid "" regenerator-runtime@^0.13.4: version "0.13.5" diff --git a/package.json b/package.json index de69dbdf..8ae6e44a 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "reason-react": "^0.7.0" }, "peerDependencies": { + "@reasonml-community/graphql-ppx": "^1.0.1", "reason-react": "^0.7.0" }, "jest": { diff --git a/src/Client.re b/src/Client.re index a6668587..6498aae6 100644 --- a/src/Client.re +++ b/src/Client.re @@ -52,7 +52,7 @@ module Exchanges = { type exchangeIO = Wonka.Types.sourceT(Types.operation) => - Wonka.Types.sourceT(Types.operationResult); + Wonka.Types.sourceT(Types.operationResult(Js.Json.t)); type exchangeInput = { forward: exchangeIO, @@ -62,7 +62,7 @@ module Exchanges = { type t = exchangeInput => (. Wonka.Types.sourceT(Types.operation)) => - Wonka.Types.sourceT(Types.operationResult); + Wonka.Types.sourceT(Types.operationResult(Js.Json.t)); [@bs.module "urql"] external cacheExchange: t = "cacheExchange"; [@bs.module "urql"] external debugExchange: t = "debugExchange"; @@ -195,26 +195,27 @@ type clientResponse('response) = { stale: option(bool), }; -/** - * A function to convert the JS response from a client.execute* - * methods to typed a Reason record. - */ -let urqlClientResponseToReason = (~response: Types.operationResult, ~parse) => { - let {extensions, stale}: Types.operationResult = response; - - let data = response.data->Js.Nullable.toOption->Belt.Option.map(parse); - let error = - response.error->Belt.Option.map(CombinedError.combinedErrorToRecord); - - let response = - switch (data, error) { - | (Some(data), _) => Data(data) - | (None, Some(error)) => Error(error) - | (None, None) => Empty - }; - - {data, error, extensions, stale, response}; -}; +/* A function to convert the JS response from a client.execute* + methods to typed a Reason record. */ +let clientResponseToReason: + type data. + (~response: Types.operationResult('a), ~parse: 'a => data) => + clientResponse(data) = + (~response, ~parse) => { + let {extensions, stale}: Types.operationResult('a) = response; + let data = response.data->Js.Nullable.toOption->Belt.Option.map(parse); + let error = + response.error->Belt.Option.map(CombinedError.combinedErrorToRecord); + + let response = + switch (data, error) { + | (Some(data), _) => Data(data) + | (None, Some(error)) => Error(error) + | (None, None) => Empty + }; + + {data, error, extensions, stale, response}; + }; /* Execution methods on the client. These allow you to imperatively execute GraphQL operations outside of the provided hooks. */ @@ -226,48 +227,73 @@ external executeQueryJs: ~opts: Types.partialOperationContext=?, unit ) => - Wonka.Types.sourceT(Types.operationResult) = + Wonka.Types.sourceT(Types.operationResult('data)) = "executeQuery"; -let executeQuery = +let executeQuery: + type variables variablesJs data. ( ~client: t, - ~request, - ~additionalTypenames=?, - ~fetchOptions=?, - ~fetch=?, - ~requestPolicy=?, - ~url=?, - ~pollInterval=?, - ~meta=?, - ~suspense=?, - ~preferGetMethod=?, - (), - ) => { - let req = - Utils.createRequest( - ~query=request##query, - ~variables=request##variables, - (), - ); - let parse = request##parse; - let optsJs = - Types.partialOperationContext( - ~additionalTypenames?, - ~fetchOptions?, - ~fetch?, - ~requestPolicy=?requestPolicy->Belt.Option.map(Types.requestPolicyToJs), - ~url?, - ~pollInterval?, - ~meta?, - ~suspense?, - ~preferGetMethod?, - (), - ); + ~request: (module Types.Operation with + type t_variables = variables and + type Raw.t_variables = variablesJs and + type t = data), + ~variables: variables, + ~additionalTypenames: array(string)=?, + ~fetchOptions: Fetch.requestInit=?, + ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, + ~requestPolicy: Types.requestPolicy=?, + ~url: string=?, + ~pollInterval: int=?, + ~meta: Types.operationDebugMeta=?, + ~suspense: bool=?, + ~preferGetMethod: bool=?, + unit + ) => + Wonka.Types.sourceT(clientResponse(data)) = + ( + ~client, + ~request as (module Request), + ~variables: variables, + ~additionalTypenames=?, + ~fetchOptions=?, + ~fetch=?, + ~requestPolicy=?, + ~url=?, + ~pollInterval=?, + ~meta=?, + ~suspense=?, + ~preferGetMethod=?, + (), + ) => { + let req = + Utils.createRequest( + ~query=Request.query, + ~variables= + variables->Request.serializeVariables->Request.variablesToJson, + (), + ); - executeQueryJs(~client, ~query=req, ~opts=optsJs, ()) - |> Wonka.map((. response) => urqlClientResponseToReason(~response, ~parse)); -}; + let optsJs = + Types.partialOperationContext( + ~additionalTypenames?, + ~fetchOptions?, + ~fetch?, + ~requestPolicy=? + requestPolicy->Belt.Option.map(Types.requestPolicyToJs), + ~url?, + ~pollInterval?, + ~meta?, + ~suspense?, + ~preferGetMethod?, + (), + ); + + executeQueryJs(~client, ~query=req, ~opts=optsJs, ()) + |> Wonka.map((. response) => + clientResponseToReason(~response, ~parse=Request.parse) + ); + }; [@bs.send] external executeMutationJs: @@ -277,48 +303,71 @@ external executeMutationJs: ~opts: Types.partialOperationContext=?, unit ) => - Wonka.Types.sourceT(Types.operationResult) = + Wonka.Types.sourceT(Types.operationResult('data)) = "executeMutation"; -let executeMutation = +let executeMutation: + type variables variablesJs data. ( ~client: t, - ~request, - ~additionalTypenames=?, - ~fetchOptions=?, - ~fetch=?, - ~requestPolicy=?, - ~url=?, - ~pollInterval=?, - ~meta=?, - ~suspense=?, - ~preferGetMethod=?, - (), - ) => { - let req = - Utils.createRequest( - ~query=request##query, - ~variables=request##variables, - (), - ); - let parse = request##parse; - let optsJs = - Types.partialOperationContext( - ~additionalTypenames?, - ~fetchOptions?, - ~fetch?, - ~requestPolicy=?requestPolicy->Belt.Option.map(Types.requestPolicyToJs), - ~url?, - ~pollInterval?, - ~meta?, - ~suspense?, - ~preferGetMethod?, - (), - ); + ~request: (module Types.Operation with + type t_variables = variables and + type Raw.t_variables = variablesJs and + type t = data), + ~variables: variables, + ~additionalTypenames: array(string)=?, + ~fetchOptions: Fetch.requestInit=?, + ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, + ~requestPolicy: Types.requestPolicy=?, + ~url: string=?, + ~pollInterval: int=?, + ~meta: Types.operationDebugMeta=?, + ~suspense: bool=?, + ~preferGetMethod: bool=?, + unit + ) => + Wonka.Types.sourceT(clientResponse(data)) = + ( + ~client: t, + ~request as (module Request), + ~variables, + ~additionalTypenames=?, + ~fetchOptions=?, + ~fetch=?, + ~requestPolicy=?, + ~url=?, + ~pollInterval=?, + ~meta=?, + ~suspense=?, + ~preferGetMethod=?, + (), + ) => { + let req = + Utils.createRequest( + ~query=Request.query, + ~variables= + variables->Request.serializeVariables->Request.variablesToJson, + (), + ); + let parse = Request.parse; + let optsJs = + Types.partialOperationContext( + ~additionalTypenames?, + ~fetchOptions?, + ~fetch?, + ~requestPolicy=? + requestPolicy->Belt.Option.map(Types.requestPolicyToJs), + ~url?, + ~pollInterval?, + ~meta?, + ~suspense?, + ~preferGetMethod?, + (), + ); - executeMutationJs(~client, ~mutation=req, ~opts=optsJs, ()) - |> Wonka.map((. response) => urqlClientResponseToReason(~response, ~parse)); -}; + executeMutationJs(~client, ~mutation=req, ~opts=optsJs, ()) + |> Wonka.map((. response) => clientResponseToReason(~response, ~parse)); + }; [@bs.send] external executeSubscriptionJs: @@ -328,53 +377,77 @@ external executeSubscriptionJs: ~opts: Types.partialOperationContext=?, unit ) => - Wonka.Types.sourceT(Types.operationResult) = + Wonka.Types.sourceT(Types.operationResult('data)) = "executeSubscription"; -let executeSubscription = +let executeSubscription: + type variables variablesJs data. ( ~client: t, - ~request, - ~additionalTypenames=?, - ~fetchOptions=?, - ~fetch=?, - ~requestPolicy=?, - ~url=?, - ~pollInterval=?, - ~meta=?, - ~suspense=?, - ~preferGetMethod=?, - (), - ) => { - let req = - Utils.createRequest( - ~query=request##query, - ~variables=request##variables, - (), - ); - let parse = request##parse; - let optsJs = - Types.partialOperationContext( - ~additionalTypenames?, - ~fetchOptions?, - ~fetch?, - ~requestPolicy=?requestPolicy->Belt.Option.map(Types.requestPolicyToJs), - ~url?, - ~pollInterval?, - ~meta?, - ~suspense?, - ~preferGetMethod?, - (), - ); + ~request: (module Types.Operation with + type t_variables = variables and + type Raw.t_variables = variablesJs and + type t = data), + ~variables: variables, + ~additionalTypenames: array(string)=?, + ~fetchOptions: Fetch.requestInit=?, + ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, + ~requestPolicy: Types.requestPolicy=?, + ~url: string=?, + ~pollInterval: int=?, + ~meta: Types.operationDebugMeta=?, + ~suspense: bool=?, + ~preferGetMethod: bool=?, + unit + ) => + Wonka.Types.sourceT(clientResponse(data)) = + ( + ~client: t, + ~request as (module Request), + ~variables, + ~additionalTypenames=?, + ~fetchOptions=?, + ~fetch=?, + ~requestPolicy=?, + ~url=?, + ~pollInterval=?, + ~meta=?, + ~suspense=?, + ~preferGetMethod=?, + (), + ) => { + let req = + Utils.createRequest( + ~query=Request.query, + ~variables= + variables->Request.serializeVariables->Request.variablesToJson, + (), + ); + let parse = Request.parse; + let optsJs = + Types.partialOperationContext( + ~additionalTypenames?, + ~fetchOptions?, + ~fetch?, + ~requestPolicy=? + requestPolicy->Belt.Option.map(Types.requestPolicyToJs), + ~url?, + ~pollInterval?, + ~meta?, + ~suspense?, + ~preferGetMethod?, + (), + ); - executeSubscriptionJs(~client, ~subscription=req, ~opts=optsJs, ()) - |> Wonka.map((. response) => urqlClientResponseToReason(~response, ~parse)); -}; + executeSubscriptionJs(~client, ~subscription=req, ~opts=optsJs, ()) + |> Wonka.map((. response) => clientResponseToReason(~response, ~parse)); + }; let query = ( ~client, ~request, + ~variables, ~additionalTypenames=?, ~fetchOptions=?, ~fetch=?, @@ -389,6 +462,7 @@ let query = executeQuery( ~client, ~request, + ~variables, ~additionalTypenames?, ~fetchOptions?, ~fetch?, @@ -408,6 +482,7 @@ let mutation = ( ~client, ~request, + ~variables, ~additionalTypenames=?, ~fetchOptions=?, ~fetch=?, @@ -422,6 +497,7 @@ let mutation = executeMutation( ~client, ~request, + ~variables, ~additionalTypenames?, ~fetchOptions?, ~fetch?, @@ -443,6 +519,7 @@ let readQuery = ( ~client, ~request, + ~variables, ~additionalTypenames=?, ~fetchOptions=?, ~fetch=?, @@ -458,6 +535,7 @@ let readQuery = executeQuery( ~client, ~request, + ~variables, ~additionalTypenames?, ~fetchOptions?, ~fetch?, diff --git a/src/Client.rei b/src/Client.rei index 2c6b8296..f5272885 100644 --- a/src/Client.rei +++ b/src/Client.rei @@ -32,7 +32,7 @@ module Exchanges: { type exchangeIO = Wonka.Types.sourceT(Types.operation) => - Wonka.Types.sourceT(Types.operationResult); + Wonka.Types.sourceT(Types.operationResult(Js.Json.t)); type exchangeInput = { forward: exchangeIO, @@ -42,7 +42,7 @@ module Exchanges: { type t = exchangeInput => (. Wonka.Types.sourceT(Types.operation)) => - Wonka.Types.sourceT(Types.operationResult); + Wonka.Types.sourceT(Types.operationResult(Js.Json.t)); [@bs.module "urql"] external cacheExchange: t = "cacheExchange"; [@bs.module "urql"] external debugExchange: t = "debugExchange"; @@ -138,14 +138,18 @@ type clientResponse('response) = { stale: option(bool), }; -let urqlClientResponseToReason: - (~response: Types.operationResult, ~parse: Js.Json.t => 'response) => +let clientResponseToReason: + (~response: Types.operationResult('data), ~parse: 'data => 'response) => clientResponse('response); let executeQuery: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -157,12 +161,16 @@ let executeQuery: ~preferGetMethod: bool=?, unit ) => - Wonka.Types.sourceT(clientResponse('response)); + Wonka.Types.sourceT(clientResponse('data)); let executeMutation: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -174,12 +182,16 @@ let executeMutation: ~preferGetMethod: bool=?, unit ) => - Wonka.Types.sourceT(clientResponse('response)); + Wonka.Types.sourceT(clientResponse('data)); let executeSubscription: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -191,12 +203,16 @@ let executeSubscription: ~preferGetMethod: bool=?, unit ) => - Wonka.Types.sourceT(clientResponse('response)); + Wonka.Types.sourceT(clientResponse('data)); let query: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -208,12 +224,16 @@ let query: ~preferGetMethod: bool=?, unit ) => - Js.Promise.t(clientResponse('response)); + Js.Promise.t(clientResponse('data)); let mutation: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -225,12 +245,16 @@ let mutation: ~preferGetMethod: bool=?, unit ) => - Js.Promise.t(clientResponse('response)); + Js.Promise.t(clientResponse('data)); let subscription: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -242,12 +266,16 @@ let subscription: ~preferGetMethod: bool=?, unit ) => - Wonka.Types.sourceT(clientResponse('response)); + Wonka.Types.sourceT(clientResponse('data)); let readQuery: ( ~client: t, - ~request: Types.request('response), + ~request: (module Types.Operation with + type t = 'data and + type t_variables = 'variables and + type Raw.t_variables = 'variablesJs), + ~variables: 'variables, ~additionalTypenames: array(string)=?, ~fetchOptions: Fetch.requestInit=?, ~fetch: (string, Fetch.requestInit) => Js.Promise.t(Fetch.response)=?, @@ -259,4 +287,4 @@ let readQuery: ~preferGetMethod: bool=?, unit ) => - option(clientResponse('response)); + option(clientResponse('data)); diff --git a/src/Types.re b/src/Types.re index 6953dd3b..63635199 100644 --- a/src/Types.re +++ b/src/Types.re @@ -78,9 +78,9 @@ type operation = { }; /* The result of the GraphQL operation. */ -type operationResult = { +type operationResult('data) = { operation, - data: Js.Nullable.t(Js.Json.t), + data: Js.Nullable.t('data), error: option(CombinedError.combinedErrorJs), extensions: option(Js.Dict.t(string)), stale: option(bool), @@ -102,6 +102,21 @@ type request('response) = { "variables": Js.Json.t, }; +/* The signature of a graphql-ppx module. */ +module type Operation = { + module Raw: { + type t; + type t_variables; + }; + type t; + type t_variables; + + let query: string; + let parse: Raw.t => t; + let serializeVariables: t_variables => Raw.t_variables; + let variablesToJson: Raw.t_variables => Js.Json.t; +}; + /* The response variant wraps the parsed result of executing a GraphQL operation. */ type response('response) = | Fetching diff --git a/src/Types.rei b/src/Types.rei index 227dbca4..f47cc67e 100644 --- a/src/Types.rei +++ b/src/Types.rei @@ -68,9 +68,9 @@ type operation = { }; /* The result of the GraphQL operation. */ -type operationResult = { +type operationResult('data) = { operation, - data: Js.Nullable.t(Js.Json.t), + data: Js.Nullable.t('data), error: option(CombinedError.combinedErrorJs), extensions: option(Js.Dict.t(string)), stale: option(bool), @@ -92,6 +92,21 @@ type request('response) = { "variables": Js.Json.t, }; +/* The signature of a graphql-ppx module. */ +module type Operation = { + module Raw: { + type t; + type t_variables; + }; + type t; + type t_variables; + + let query: string; + let parse: Raw.t => t; + let serializeVariables: t_variables => Raw.t_variables; + let variablesToJson: Raw.t_variables => Js.Json.t; +}; + /* The response variant wraps the parsed result of executing a GraphQL operation. */ type response('response) = | Fetching diff --git a/src/Utils.re b/src/Utils.re index f6450fed..d0c93a76 100644 --- a/src/Utils.re +++ b/src/Utils.re @@ -8,12 +8,12 @@ external createRequest: [@bs.module "urql"] external makeResult: - (Types.operation, 'a, option('b)) => Types.operationResult = + (Types.operation, 'a, option('b)) => Types.operationResult('c) = "makeResult"; [@bs.module "urql"] external makeErrorResult: - (Types.operation, Js.Exn.t, option('a)) => Types.operationResult = + (Types.operation, Js.Exn.t, option('a)) => Types.operationResult('c) = "makeErrorResult"; [@bs.module "urql"] external formatDocument: 'a => 'a = "formatDocument"; diff --git a/src/Utils.rei b/src/Utils.rei index f6450fed..d0c93a76 100644 --- a/src/Utils.rei +++ b/src/Utils.rei @@ -8,12 +8,12 @@ external createRequest: [@bs.module "urql"] external makeResult: - (Types.operation, 'a, option('b)) => Types.operationResult = + (Types.operation, 'a, option('b)) => Types.operationResult('c) = "makeResult"; [@bs.module "urql"] external makeErrorResult: - (Types.operation, Js.Exn.t, option('a)) => Types.operationResult = + (Types.operation, Js.Exn.t, option('a)) => Types.operationResult('c) = "makeErrorResult"; [@bs.module "urql"] external formatDocument: 'a => 'a = "formatDocument"; diff --git a/src/hooks/UseMutation.re b/src/hooks/UseMutation.re index 19920108..86edb9f3 100644 --- a/src/hooks/UseMutation.re +++ b/src/hooks/UseMutation.re @@ -1,6 +1,6 @@ type executeMutationJs = (Js.Json.t, Types.partialOperationContext) => - Js.Promise.t(Types.operationResult); + Js.Promise.t(Types.operationResult(Js.Json.t)); type executeMutation = ( @@ -15,7 +15,7 @@ type executeMutation = ~preferGetMethod: bool=?, unit ) => - Js.Promise.t(Types.operationResult); + Js.Promise.t(Types.operationResult(Js.Json.t)); type useMutationResponseJs = ( Types.hookResponseJs(Js.Json.t), diff --git a/src/hooks/UseMutation.rei b/src/hooks/UseMutation.rei index 873449ae..e82b3db0 100644 --- a/src/hooks/UseMutation.rei +++ b/src/hooks/UseMutation.rei @@ -11,7 +11,7 @@ type executeMutation = ~preferGetMethod: bool=?, unit ) => - Js.Promise.t(Types.operationResult); + Js.Promise.t(Types.operationResult(Js.Json.t)); type useMutationResponse('response) = ( Types.hookResponse('response), @@ -24,7 +24,7 @@ let useMutation: let useDynamicMutation: Types.graphqlDefinition( 'parse, - Js.Promise.t(Types.operationResult), + Js.Promise.t(Types.operationResult(Js.Json.t)), 'executeMutation, ) => (