diff --git a/examples/2-query/src/Monster.re b/examples/2-query/src/Monster.re
index c6baad2c..01c26087 100644
--- a/examples/2-query/src/Monster.re
+++ b/examples/2-query/src/Monster.re
@@ -16,14 +16,14 @@ module GetPokemon = [%graphql
{|
query pokemon($name: String!) {
pokemon(name: $name) {
- name
- classification
- height {
- maximum
- }
- weight {
- maximum
- }
+ name
+ classification
+ height {
+ maximum
+ }
+ weight {
+ maximum
+ }
image
}
}
diff --git a/examples/5-subscription/graphql_schema.json b/examples/5-subscription/graphql_schema.json
index 640f172f..f6132984 100644
--- a/examples/5-subscription/graphql_schema.json
+++ b/examples/5-subscription/graphql_schema.json
@@ -61,6 +61,30 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "floats",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ }
+ }
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
@@ -141,6 +165,16 @@
"enumValues": null,
"possibleTypes": null
},
+ {
+ "kind": "SCALAR",
+ "name": "Float",
+ "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point). ",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": null,
+ "possibleTypes": null
+ },
{
"kind": "OBJECT",
"name": "Subscription",
@@ -177,6 +211,22 @@
},
"isDeprecated": false,
"deprecationReason": null
+ },
+ {
+ "name": "newFloat",
+ "description": "",
+ "args": [],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "Float",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
}
],
"inputFields": null,
diff --git a/examples/5-subscription/src/app/App.re b/examples/5-subscription/src/app/App.re
index 3c17cbb0..45efc44a 100644
--- a/examples/5-subscription/src/app/App.re
+++ b/examples/5-subscription/src/app/App.re
@@ -7,5 +7,6 @@ let make = () =>
width="1000"
style={ReactDOMRe.Style.make(~border="1px solid blue", ())}>
+
- ;
\ No newline at end of file
+ ;
diff --git a/examples/5-subscription/src/app/Squares.re b/examples/5-subscription/src/app/Squares.re
new file mode 100644
index 00000000..3f06a92d
--- /dev/null
+++ b/examples/5-subscription/src/app/Squares.re
@@ -0,0 +1,61 @@
+open ReasonUrql;
+
+module SubscribeRandomFloat = [%graphql
+ {|
+ subscription subscribeFloat {
+ newFloat @bsDecoder(fn: "Js.Float.toString")
+ }
+|}
+];
+
+let handler = (prevSubscriptions, subscription) => {
+ switch (prevSubscriptions) {
+ | Some(subs) => Array.append(subs, [|subscription|])
+ | None => [|subscription|]
+ };
+};
+
+[@bs.scope "Math"] [@bs.val] external random: unit => float = "random";
+[@bs.scope "Math"] [@bs.val] external floor: float => int = "floor";
+[@bs.send] external toString: (int, int) => string = "toString";
+
+let getRandomInt = (max: int) => {
+ floor(random() *. float_of_int(max));
+};
+
+let getRandomHex = () => {
+ let encode = random() *. float_of_int(16777215) |> floor;
+ let hex = encode->toString(16);
+ {j|#$hex|j};
+};
+
+let request = SubscribeRandomFloat.make();
+
+[@react.component]
+let make = () => {
+
+ ...{({response}) =>
+ switch (response) {
+ | Fetching => "Loading"->React.string
+ | Data(d) =>
+ Array.mapi(
+ (index, datum) =>
+ string_of_int}
+ width={getRandomInt(30) |> string_of_int}
+ />,
+ d,
+ )
+ |> React.array
+ | Error(_e) => "Error"->React.string
+ | NotFound => "Not Found"->React.string
+ }
+ }
+ ;
+};
diff --git a/examples/5-subscription/src/server/schema.js b/examples/5-subscription/src/server/schema.js
index 2af1f8c9..d36997b6 100644
--- a/examples/5-subscription/src/server/schema.js
+++ b/examples/5-subscription/src/server/schema.js
@@ -5,17 +5,20 @@ const pubsub = new PubSub();
const store = {
messages: [],
- numbers: []
+ numbers: [],
+ floats: []
};
const typeDefs = `
type Query {
messages: [Message!]!
numbers: [Int!]!
+ floats: [Float!]!
}
type Subscription {
newMessage: Message!
newNumber: Int!
+ newFloat: Float!
}
type Message {
id: ID!,
@@ -26,7 +29,8 @@ type Message {
const resolvers = {
Query: {
messages: store.messages,
- numbers: store.numbers
+ numbers: store.numbers,
+ floats: store.floats
},
Subscription: {
newMessage: {
@@ -34,6 +38,9 @@ const resolvers = {
},
newNumber: {
subscribe: () => pubsub.asyncIterator("newNumber")
+ },
+ newFloat: {
+ subscribe: () => pubsub.asyncIterator("newFloat")
}
}
};
@@ -71,3 +78,9 @@ setInterval(() => {
newNumber: getRandomInt(1000)
});
}, 2000);
+
+setInterval(() => {
+ pubsub.publish("newFloat", {
+ newFloat: Math.random() * 1000
+ });
+}, 500);
diff --git a/src/ReasonUrql.re b/src/ReasonUrql.re
index 42cb58ae..81336471 100644
--- a/src/ReasonUrql.re
+++ b/src/ReasonUrql.re
@@ -8,7 +8,9 @@ module Query = UrqlQuery;
module Mutation = UrqlMutation;
-module Subscription = UrqlSubscription;
+module Subscription = UrqlSubscription.Subscription;
+
+module SubscriptionWithHandler = UrqlSubscription.SubscriptionWithHandler;
module Types = UrqlTypes;
@@ -19,12 +21,13 @@ module Error = UrqlCombinedError;
module Exchanges = UrqlClient.UrqlExchanges;
module Hooks = {
- type hookResponse('ret) = Types.hookResponse('ret) = {
- fetching: bool,
- data: option('ret),
- error: option(UrqlCombinedError.t),
- response: Types.response('ret)
- };
+ type hookResponse('ret) =
+ Types.hookResponse('ret) = {
+ fetching: bool,
+ data: option('ret),
+ error: option(UrqlCombinedError.t),
+ response: Types.response('ret),
+ };
include UrqlUseMutation;
include UrqlUseQuery;
include UrqlUseSubscription;
diff --git a/src/UrqlTypes.re b/src/UrqlTypes.re
index 6ec01860..43e6d9ce 100644
--- a/src/UrqlTypes.re
+++ b/src/UrqlTypes.re
@@ -92,18 +92,9 @@ type request('response) = {
"variables": Js.Json.t,
};
-/* The type of the handler function passed to Subscription and useSubscription.
- `handler` corresponds to the type of the handler function _before_ the latest subscription has been parsed.
- `parsedHandler` corresponds to the type of the handler function _after_ the latest subscription has been parsed. */
-type handler('acc) =
- (~prevSubscriptions: option('acc), ~subscription: Js.Json.t) => 'acc;
-
-type parsedHandler('acc, 'response) =
- (~prevSubscriptions: option('acc), ~subscription: 'response) => 'acc;
-
type hookResponse('ret) = {
fetching: bool,
data: option('ret),
error: option(UrqlCombinedError.t),
- response: response('ret)
-}
+ response: response('ret),
+};
diff --git a/src/components/UrqlSubscription.re b/src/components/UrqlSubscription.re
index 19e6779f..14ff69aa 100644
--- a/src/components/UrqlSubscription.re
+++ b/src/components/UrqlSubscription.re
@@ -1,17 +1,19 @@
+open UrqlTypes;
+
[@bs.deriving abstract]
-type subscriptionRenderPropsJs('a) = {
+type subscriptionRenderPropsJs('ret) = {
fetching: bool,
[@bs.optional]
- data: 'a,
+ data: 'ret,
[@bs.optional]
error: UrqlCombinedError.t,
};
-type subscriptionRenderProps('a) = {
+type subscriptionRenderProps('ret) = {
fetching: bool,
- data: option('a),
+ data: option('ret),
error: option(UrqlCombinedError.t),
- response: UrqlTypes.response('a),
+ response: UrqlTypes.response('ret),
};
module SubscriptionJs = {
@@ -19,22 +21,23 @@ module SubscriptionJs = {
external make:
(
~query: string,
- ~variables: Js.Json.t=?,
- ~handler: UrqlTypes.handler('acc)=?,
- ~children: subscriptionRenderPropsJs('a) => React.element
+ ~variables: Js.Json.t,
+ ~handler: (option('acc), Js.Json.t) => 'acc=?,
+ ~children: subscriptionRenderPropsJs('ret) => React.element
) =>
React.element =
"Subscription";
};
-let urqlDataToRecord = (result: subscriptionRenderPropsJs('a)) => {
- let data = result->dataGet;
+let urqlDataToRecord = (parse, result) => {
+ let data = result->dataGet->Belt.Option.map(parse);
let error = result->errorGet;
let fetching = result->fetchingGet;
- let response: UrqlTypes.response('a) =
+ let response =
switch (fetching, data, error) {
- | (true, _, _) => Fetching
+ | (true, None, _) => Fetching
+ | (true, Some(data), _) => Data(data)
| (false, Some(data), _) => Data(data)
| (false, _, Some(error)) => Error(error)
| (false, None, None) => NotFound
@@ -43,14 +46,39 @@ let urqlDataToRecord = (result: subscriptionRenderPropsJs('a)) => {
{fetching, data, error, response};
};
-[@react.component]
-let make =
- (
- ~query: string,
- ~variables: option(Js.Json.t)=?,
- ~handler: option(UrqlTypes.handler('acc))=?,
- ~children: subscriptionRenderProps('a) => React.element,
- ) =>
-
- {result => result |> urqlDataToRecord |> children}
- ;
+module Subscription = {
+ [@react.component]
+ let make =
+ (
+ ~request: request('response),
+ ~children: subscriptionRenderProps('response) => React.element,
+ ) => {
+ let query = request##query;
+ let variables = request##variables;
+ let parse = request##parse;
+
+
+ {result => result |> urqlDataToRecord(parse) |> children}
+ ;
+ };
+};
+
+module SubscriptionWithHandler = {
+ [@react.component]
+ let make =
+ (
+ ~request: request('response),
+ ~handler: (option('acc), 'response) => 'acc,
+ ~children: subscriptionRenderProps('acc) => React.element,
+ ) => {
+ let query = request##query;
+ let variables = request##variables;
+ let parse = request##parse;
+
+ let applyParsedResponse = (acc, data) => handler(acc, parse(data));
+
+
+ {result => result |> urqlDataToRecord(x => x) |> children}
+ ;
+ };
+};