From 5acdc8d5d684053987ce1f32262ca15eeae4a75e Mon Sep 17 00:00:00 2001
From: Anthony Mittaz <sync@me.com>
Date: Fri, 5 Jun 2020 14:44:34 +1000
Subject: [PATCH] Use defer on the fragment

---
 warp/defer/client/schema.graphql              |  10 +-
 .../__generated__/pagesQuery_graphql.bs.js    | 113 +++++++++-------
 .../src/__generated__/pagesQuery_graphql.re   | 122 ++++++++++--------
 .../__generated__/pages_book_graphql.bs.js    |  62 +++++++++
 .../src/__generated__/pages_book_graphql.re   |  74 +++++++++++
 .../pages_comments_book_graphql.bs.js         |  63 +++++++++
 .../pages_comments_book_graphql.re            |  72 +++++++++++
 warp/defer/client/src/pages/index.bs.js       |  74 +++++++++--
 warp/defer/client/src/pages/index.re          |  67 ++++++----
 9 files changed, 517 insertions(+), 140 deletions(-)
 create mode 100644 warp/defer/client/src/__generated__/pages_book_graphql.bs.js
 create mode 100644 warp/defer/client/src/__generated__/pages_book_graphql.re
 create mode 100644 warp/defer/client/src/__generated__/pages_comments_book_graphql.bs.js
 create mode 100644 warp/defer/client/src/__generated__/pages_comments_book_graphql.re

diff --git a/warp/defer/client/schema.graphql b/warp/defer/client/schema.graphql
index 482ec9d..1e0a002 100644
--- a/warp/defer/client/schema.graphql
+++ b/warp/defer/client/schema.graphql
@@ -1,6 +1,12 @@
-directive @defer on FIELD
+directive @defer(
+  """Relay fragment label"""
+  label: String
+) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
 
-directive @stream on FIELD
+directive @stream(
+  """Relay fragment label"""
+  label: String
+) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT
 
 type Book {
   title: String!
diff --git a/warp/defer/client/src/__generated__/pagesQuery_graphql.bs.js b/warp/defer/client/src/__generated__/pagesQuery_graphql.bs.js
index d1a525d..e9ebcf7 100644
--- a/warp/defer/client/src/__generated__/pagesQuery_graphql.bs.js
+++ b/warp/defer/client/src/__generated__/pagesQuery_graphql.bs.js
@@ -4,7 +4,7 @@ import * as ReasonRelay from "reason-relay/src/ReasonRelay.bs.js";
 
 var Types = { };
 
-var responseConverter = ({"__root":{"books_comments":{"n":""}}});
+var responseConverter = ({"__root":{"books":{"f":""}}});
 
 function convertResponse(v) {
   return ReasonRelay._convertObj(v, responseConverter, undefined, undefined);
@@ -27,84 +27,105 @@ var Internal = {
 
 var Utils = { };
 
-var node = ((function(){
-var v0 = [
-  {
-    "alias": null,
-    "args": null,
-    "concreteType": "Book",
-    "kind": "LinkedField",
-    "name": "books",
-    "plural": true,
+var node = ({
+  "fragment": {
+    "argumentDefinitions": [],
+    "kind": "Fragment",
+    "metadata": null,
+    "name": "pagesQuery",
     "selections": [
       {
         "alias": null,
         "args": null,
-        "kind": "ScalarField",
-        "name": "title",
-        "storageKey": null
-      },
-      {
-        "alias": null,
-        "args": null,
-        "kind": "ScalarField",
-        "name": "author",
+        "concreteType": "Book",
+        "kind": "LinkedField",
+        "name": "books",
+        "plural": true,
+        "selections": [
+          {
+            "args": null,
+            "kind": "FragmentSpread",
+            "name": "pages_book"
+          }
+        ],
         "storageKey": null
-      },
+      }
+    ],
+    "type": "Query"
+  },
+  "kind": "Request",
+  "operation": {
+    "argumentDefinitions": [],
+    "kind": "Operation",
+    "name": "pagesQuery",
+    "selections": [
       {
         "alias": null,
         "args": null,
-        "concreteType": "Comment",
+        "concreteType": "Book",
         "kind": "LinkedField",
-        "name": "comments",
+        "name": "books",
         "plural": true,
         "selections": [
           {
             "alias": null,
             "args": null,
             "kind": "ScalarField",
-            "name": "user",
+            "name": "title",
             "storageKey": null
           },
           {
             "alias": null,
             "args": null,
             "kind": "ScalarField",
-            "name": "text",
+            "name": "author",
             "storageKey": null
+          },
+          {
+            "if": null,
+            "kind": "Defer",
+            "label": "pages_book$defer$pages_comments_book",
+            "selections": [
+              {
+                "alias": null,
+                "args": null,
+                "concreteType": "Comment",
+                "kind": "LinkedField",
+                "name": "comments",
+                "plural": true,
+                "selections": [
+                  {
+                    "alias": null,
+                    "args": null,
+                    "kind": "ScalarField",
+                    "name": "text",
+                    "storageKey": null
+                  },
+                  {
+                    "alias": null,
+                    "args": null,
+                    "kind": "ScalarField",
+                    "name": "user",
+                    "storageKey": null
+                  }
+                ],
+                "storageKey": null
+              }
+            ]
           }
         ],
         "storageKey": null
       }
-    ],
-    "storageKey": null
-  }
-];
-return {
-  "fragment": {
-    "argumentDefinitions": [],
-    "kind": "Fragment",
-    "metadata": null,
-    "name": "pagesQuery",
-    "selections": (v0/*: any*/),
-    "type": "Query"
-  },
-  "kind": "Request",
-  "operation": {
-    "argumentDefinitions": [],
-    "kind": "Operation",
-    "name": "pagesQuery",
-    "selections": (v0/*: any*/)
+    ]
   },
   "params": {
     "id": null,
     "metadata": {},
     "name": "pagesQuery",
     "operationKind": "query",
-    "text": "query pagesQuery {\n  books {\n    title\n    author\n    comments @defer {\n      user\n      text\n    }\n  }\n}\n"
+    "text": "query pagesQuery {\n  books {\n    ...pages_book\n  }\n}\n\nfragment pages_book on Book {\n  title\n  author\n  ...pages_comments_book @defer(label: \"pages_book$defer$pages_comments_book\")\n}\n\nfragment pages_comments_book on Book {\n  comments {\n    text\n    user\n  }\n}\n"
   }
-};
-})());
+});
 
 var include = ReasonRelay.MakePreloadQuery({
       query: node,
diff --git a/warp/defer/client/src/__generated__/pagesQuery_graphql.re b/warp/defer/client/src/__generated__/pagesQuery_graphql.re
index aee45a5..fd9e13d 100644
--- a/warp/defer/client/src/__generated__/pagesQuery_graphql.re
+++ b/warp/defer/client/src/__generated__/pagesQuery_graphql.re
@@ -1,14 +1,9 @@
 /* @generated */
 
 module Types = {
-  type response_books_comments = {
-    user: string,
-    text: string,
-  };
   type response_books = {
-    title: string,
-    author: string,
-    comments: option(array(response_books_comments)),
+    getFragmentRefs:
+      unit => {. "__$fragment_ref__pages_book": Pages_book_graphql.t},
   };
 
   type response = {books: array(response_books)};
@@ -18,7 +13,7 @@ module Types = {
 module Internal = {
   type responseRaw;
   let responseConverter: Js.Dict.t(Js.Dict.t(Js.Dict.t(string))) = [%raw
-    {json| {"__root":{"books_comments":{"n":""}}} |json}
+    {json| {"__root":{"books":{"f":""}}} |json}
   ];
   let responseConverterMap = ();
   let convertResponse = v =>
@@ -49,84 +44,105 @@ module Utils = {};
 type operationType = ReasonRelay.queryNode;
 
 let node: operationType = [%raw
-  {json| (function(){
-var v0 = [
-  {
-    "alias": null,
-    "args": null,
-    "concreteType": "Book",
-    "kind": "LinkedField",
-    "name": "books",
-    "plural": true,
+  {json| {
+  "fragment": {
+    "argumentDefinitions": [],
+    "kind": "Fragment",
+    "metadata": null,
+    "name": "pagesQuery",
     "selections": [
       {
         "alias": null,
         "args": null,
-        "kind": "ScalarField",
-        "name": "title",
-        "storageKey": null
-      },
-      {
-        "alias": null,
-        "args": null,
-        "kind": "ScalarField",
-        "name": "author",
+        "concreteType": "Book",
+        "kind": "LinkedField",
+        "name": "books",
+        "plural": true,
+        "selections": [
+          {
+            "args": null,
+            "kind": "FragmentSpread",
+            "name": "pages_book"
+          }
+        ],
         "storageKey": null
-      },
+      }
+    ],
+    "type": "Query"
+  },
+  "kind": "Request",
+  "operation": {
+    "argumentDefinitions": [],
+    "kind": "Operation",
+    "name": "pagesQuery",
+    "selections": [
       {
         "alias": null,
         "args": null,
-        "concreteType": "Comment",
+        "concreteType": "Book",
         "kind": "LinkedField",
-        "name": "comments",
+        "name": "books",
         "plural": true,
         "selections": [
           {
             "alias": null,
             "args": null,
             "kind": "ScalarField",
-            "name": "user",
+            "name": "title",
             "storageKey": null
           },
           {
             "alias": null,
             "args": null,
             "kind": "ScalarField",
-            "name": "text",
+            "name": "author",
             "storageKey": null
+          },
+          {
+            "if": null,
+            "kind": "Defer",
+            "label": "pages_book$defer$pages_comments_book",
+            "selections": [
+              {
+                "alias": null,
+                "args": null,
+                "concreteType": "Comment",
+                "kind": "LinkedField",
+                "name": "comments",
+                "plural": true,
+                "selections": [
+                  {
+                    "alias": null,
+                    "args": null,
+                    "kind": "ScalarField",
+                    "name": "text",
+                    "storageKey": null
+                  },
+                  {
+                    "alias": null,
+                    "args": null,
+                    "kind": "ScalarField",
+                    "name": "user",
+                    "storageKey": null
+                  }
+                ],
+                "storageKey": null
+              }
+            ]
           }
         ],
         "storageKey": null
       }
-    ],
-    "storageKey": null
-  }
-];
-return {
-  "fragment": {
-    "argumentDefinitions": [],
-    "kind": "Fragment",
-    "metadata": null,
-    "name": "pagesQuery",
-    "selections": (v0/*: any*/),
-    "type": "Query"
-  },
-  "kind": "Request",
-  "operation": {
-    "argumentDefinitions": [],
-    "kind": "Operation",
-    "name": "pagesQuery",
-    "selections": (v0/*: any*/)
+    ]
   },
   "params": {
     "id": null,
     "metadata": {},
     "name": "pagesQuery",
     "operationKind": "query",
-    "text": "query pagesQuery {\n  books {\n    title\n    author\n    comments @defer {\n      user\n      text\n    }\n  }\n}\n"
+    "text": "query pagesQuery {\n  books {\n    ...pages_book\n  }\n}\n\nfragment pages_book on Book {\n  title\n  author\n  ...pages_comments_book @defer(label: \"pages_book$defer$pages_comments_book\")\n}\n\nfragment pages_comments_book on Book {\n  comments {\n    text\n    user\n  }\n}\n"
   }
-};
-})() |json}
+} |json}
 ];
 
 include ReasonRelay.MakePreloadQuery({
diff --git a/warp/defer/client/src/__generated__/pages_book_graphql.bs.js b/warp/defer/client/src/__generated__/pages_book_graphql.bs.js
new file mode 100644
index 0000000..57c972f
--- /dev/null
+++ b/warp/defer/client/src/__generated__/pages_book_graphql.bs.js
@@ -0,0 +1,62 @@
+
+
+import * as ReasonRelay from "reason-relay/src/ReasonRelay.bs.js";
+
+var Types = { };
+
+var fragmentConverter = ({"__root":{"":{"f":""}}});
+
+function convertFragment(v) {
+  return ReasonRelay._convertObj(v, fragmentConverter, undefined, undefined);
+}
+
+var Internal = {
+  fragmentConverter: fragmentConverter,
+  fragmentConverterMap: undefined,
+  convertFragment: convertFragment
+};
+
+var Utils = { };
+
+var node = ({
+  "argumentDefinitions": [],
+  "kind": "Fragment",
+  "metadata": null,
+  "name": "pages_book",
+  "selections": [
+    {
+      "alias": null,
+      "args": null,
+      "kind": "ScalarField",
+      "name": "title",
+      "storageKey": null
+    },
+    {
+      "alias": null,
+      "args": null,
+      "kind": "ScalarField",
+      "name": "author",
+      "storageKey": null
+    },
+    {
+      "kind": "Defer",
+      "selections": [
+        {
+          "args": null,
+          "kind": "FragmentSpread",
+          "name": "pages_comments_book"
+        }
+      ]
+    }
+  ],
+  "type": "Book"
+});
+
+export {
+  Types ,
+  Internal ,
+  Utils ,
+  node ,
+  
+}
+/* fragmentConverter Not a pure module */
diff --git a/warp/defer/client/src/__generated__/pages_book_graphql.re b/warp/defer/client/src/__generated__/pages_book_graphql.re
new file mode 100644
index 0000000..5c205b2
--- /dev/null
+++ b/warp/defer/client/src/__generated__/pages_book_graphql.re
@@ -0,0 +1,74 @@
+/* @generated */
+
+module Types = {
+  type fragment = {
+    title: string,
+    author: string,
+    getFragmentRefs:
+      unit =>
+      {
+        .
+        "__$fragment_ref__pages_comments_book": Pages_comments_book_graphql.t,
+      },
+  };
+};
+
+module Internal = {
+  type fragmentRaw;
+  let fragmentConverter: Js.Dict.t(Js.Dict.t(Js.Dict.t(string))) = [%raw
+    {json| {"__root":{"":{"f":""}}} |json}
+  ];
+  let fragmentConverterMap = ();
+  let convertFragment = v =>
+    v
+    ->ReasonRelay._convertObj(
+        fragmentConverter,
+        fragmentConverterMap,
+        Js.undefined,
+      );
+};
+
+type t;
+type fragmentRef;
+type fragmentRefSelector('a) = {.. "__$fragment_ref__pages_book": t} as 'a;
+external getFragmentRef: fragmentRefSelector('a) => fragmentRef = "%identity";
+
+module Utils = {};
+
+type operationType = ReasonRelay.fragmentNode;
+
+let node: operationType = [%raw
+  {json| {
+  "argumentDefinitions": [],
+  "kind": "Fragment",
+  "metadata": null,
+  "name": "pages_book",
+  "selections": [
+    {
+      "alias": null,
+      "args": null,
+      "kind": "ScalarField",
+      "name": "title",
+      "storageKey": null
+    },
+    {
+      "alias": null,
+      "args": null,
+      "kind": "ScalarField",
+      "name": "author",
+      "storageKey": null
+    },
+    {
+      "kind": "Defer",
+      "selections": [
+        {
+          "args": null,
+          "kind": "FragmentSpread",
+          "name": "pages_comments_book"
+        }
+      ]
+    }
+  ],
+  "type": "Book"
+} |json}
+];
diff --git a/warp/defer/client/src/__generated__/pages_comments_book_graphql.bs.js b/warp/defer/client/src/__generated__/pages_comments_book_graphql.bs.js
new file mode 100644
index 0000000..6dbe0c2
--- /dev/null
+++ b/warp/defer/client/src/__generated__/pages_comments_book_graphql.bs.js
@@ -0,0 +1,63 @@
+
+
+import * as ReasonRelay from "reason-relay/src/ReasonRelay.bs.js";
+
+var Types = { };
+
+var fragmentConverter = ({"__root":{"comments":{"n":""}}});
+
+function convertFragment(v) {
+  return ReasonRelay._convertObj(v, fragmentConverter, undefined, undefined);
+}
+
+var Internal = {
+  fragmentConverter: fragmentConverter,
+  fragmentConverterMap: undefined,
+  convertFragment: convertFragment
+};
+
+var Utils = { };
+
+var node = ({
+  "argumentDefinitions": [],
+  "kind": "Fragment",
+  "metadata": null,
+  "name": "pages_comments_book",
+  "selections": [
+    {
+      "alias": null,
+      "args": null,
+      "concreteType": "Comment",
+      "kind": "LinkedField",
+      "name": "comments",
+      "plural": true,
+      "selections": [
+        {
+          "alias": null,
+          "args": null,
+          "kind": "ScalarField",
+          "name": "text",
+          "storageKey": null
+        },
+        {
+          "alias": null,
+          "args": null,
+          "kind": "ScalarField",
+          "name": "user",
+          "storageKey": null
+        }
+      ],
+      "storageKey": null
+    }
+  ],
+  "type": "Book"
+});
+
+export {
+  Types ,
+  Internal ,
+  Utils ,
+  node ,
+  
+}
+/* fragmentConverter Not a pure module */
diff --git a/warp/defer/client/src/__generated__/pages_comments_book_graphql.re b/warp/defer/client/src/__generated__/pages_comments_book_graphql.re
new file mode 100644
index 0000000..c618c75
--- /dev/null
+++ b/warp/defer/client/src/__generated__/pages_comments_book_graphql.re
@@ -0,0 +1,72 @@
+/* @generated */
+
+module Types = {
+  type fragment_comments = {
+    text: string,
+    user: string,
+  };
+
+  type fragment = {comments: option(array(fragment_comments))};
+};
+
+module Internal = {
+  type fragmentRaw;
+  let fragmentConverter: Js.Dict.t(Js.Dict.t(Js.Dict.t(string))) = [%raw
+    {json| {"__root":{"comments":{"n":""}}} |json}
+  ];
+  let fragmentConverterMap = ();
+  let convertFragment = v =>
+    v
+    ->ReasonRelay._convertObj(
+        fragmentConverter,
+        fragmentConverterMap,
+        Js.undefined,
+      );
+};
+
+type t;
+type fragmentRef;
+type fragmentRefSelector('a) =
+  {.. "__$fragment_ref__pages_comments_book": t} as 'a;
+external getFragmentRef: fragmentRefSelector('a) => fragmentRef = "%identity";
+
+module Utils = {};
+
+type operationType = ReasonRelay.fragmentNode;
+
+let node: operationType = [%raw
+  {json| {
+  "argumentDefinitions": [],
+  "kind": "Fragment",
+  "metadata": null,
+  "name": "pages_comments_book",
+  "selections": [
+    {
+      "alias": null,
+      "args": null,
+      "concreteType": "Comment",
+      "kind": "LinkedField",
+      "name": "comments",
+      "plural": true,
+      "selections": [
+        {
+          "alias": null,
+          "args": null,
+          "kind": "ScalarField",
+          "name": "text",
+          "storageKey": null
+        },
+        {
+          "alias": null,
+          "args": null,
+          "kind": "ScalarField",
+          "name": "user",
+          "storageKey": null
+        }
+      ],
+      "storageKey": null
+    }
+  ],
+  "type": "Book"
+} |json}
+];
diff --git a/warp/defer/client/src/pages/index.bs.js b/warp/defer/client/src/pages/index.bs.js
index b6956ad..05a53fd 100644
--- a/warp/defer/client/src/pages/index.bs.js
+++ b/warp/defer/client/src/pages/index.bs.js
@@ -5,10 +5,13 @@ import * as React from "react";
 import * as RelayEnv from "../helpers/RelayEnv.bs.js";
 import * as Belt_Array from "bs-platform/lib/es6/belt_Array.js";
 import * as Belt_Option from "bs-platform/lib/es6/belt_Option.js";
+import * as Caml_option from "bs-platform/lib/es6/caml_option.js";
 import * as ReasonRelay from "reason-relay/src/ReasonRelay.bs.js";
 import * as ErrorBoundary from "../components/ErrorBoundary.bs.js";
 import * as ReactExperimental from "reason-relay/src/ReactExperimental.bs.js";
 import * as PagesQuery_graphql from "../__generated__/pagesQuery_graphql.bs.js";
+import * as Pages_book_graphql from "../__generated__/pages_book_graphql.bs.js";
+import * as Pages_comments_book_graphql from "../__generated__/pages_comments_book_graphql.bs.js";
 
 var convertResponse = PagesQuery_graphql.Internal.convertResponse;
 
@@ -38,9 +41,33 @@ var Query = {
   usePreloaded: Query_usePreloaded
 };
 
+var convertFragment = Pages_comments_book_graphql.Internal.convertFragment;
+
+var UseFragment = ReasonRelay.MakeUseFragment({
+      fragmentSpec: Pages_comments_book_graphql.node,
+      convertFragment: convertFragment
+    });
+
+function use$1(fRef) {
+  return Curry._1(UseFragment.use, fRef);
+}
+
+function useOpt(opt_fRef) {
+  return Curry._1(UseFragment.useOpt, opt_fRef !== undefined ? Caml_option.some(Caml_option.valFromOption(opt_fRef)) : undefined);
+}
+
+var BookCommentsFragment = {
+  Operation: undefined,
+  Types: undefined,
+  UseFragment: UseFragment,
+  use: use$1,
+  useOpt: useOpt
+};
+
 function Index$Comments(Props) {
-  var comments = Props.comments;
-  return Belt_Array.map(Belt_Option.getWithDefault(comments, []), (function (comment) {
+  var bookRef = Props.bookRef;
+  var book = Curry._1(UseFragment.use, bookRef);
+  return Belt_Array.map(Belt_Option.getWithDefault(book.comments, []), (function (comment) {
                 var text = comment.text;
                 var user = comment.user;
                 return React.createElement("li", {
@@ -53,12 +80,36 @@ var Comments = {
   make: Index$Comments
 };
 
+var convertFragment$1 = Pages_book_graphql.Internal.convertFragment;
+
+var UseFragment$1 = ReasonRelay.MakeUseFragment({
+      fragmentSpec: Pages_book_graphql.node,
+      convertFragment: convertFragment$1
+    });
+
+function use$2(fRef) {
+  return Curry._1(UseFragment$1.use, fRef);
+}
+
+function useOpt$1(opt_fRef) {
+  return Curry._1(UseFragment$1.useOpt, opt_fRef !== undefined ? Caml_option.some(Caml_option.valFromOption(opt_fRef)) : undefined);
+}
+
+var BookFragment = {
+  Operation: undefined,
+  Types: undefined,
+  UseFragment: UseFragment$1,
+  use: use$2,
+  useOpt: useOpt$1
+};
+
 function Index$Book(Props) {
-  var title = Props.title;
-  var author = Props.author;
-  var comments = Props.comments;
+  var bookRef = Props.bookRef;
+  var book = Curry._1(UseFragment$1.use, bookRef);
+  var title = book.title;
+  var author = book.author;
   return React.createElement("div", undefined, React.createElement("p", undefined, "" + (String(title) + (" by " + (String(author) + "")))), React.createElement(Index$Comments, {
-                  comments: comments
+                  bookRef: Curry._1(book.getFragmentRefs, undefined)
                 }));
 }
 
@@ -69,15 +120,12 @@ var Book = {
 function Index$Books(Props) {
   var response = Curry._6(use, undefined, undefined, undefined, undefined, undefined, undefined);
   var booksCount = response.books.length;
-  console.log("books: ", response.books);
   return React.createElement("div", undefined, React.createElement("h2", {
                   className: "text-4xl font-extrabold tracking-tight text-gray-900 leading-10 sm:text-5xl sm:leading-none md:text-6xl pb-10"
-                }, "Streaming " + (String(booksCount) + " books....")), Belt_Array.map(response.books, (function (book) {
+                }, "Streaming " + (String(booksCount) + " books....")), Belt_Array.mapWithIndex(response.books, (function (idx, book) {
                     return React.createElement(Index$Book, {
-                                title: book.title,
-                                author: book.author,
-                                comments: book.comments,
-                                key: book.title
+                                bookRef: Curry._1(book.getFragmentRefs, undefined),
+                                key: String(idx)
                               });
                   })));
 }
@@ -105,7 +153,9 @@ var $$default = Index;
 
 export {
   Query ,
+  BookCommentsFragment ,
   Comments ,
+  BookFragment ,
   Book ,
   Books ,
   make ,
diff --git a/warp/defer/client/src/pages/index.re b/warp/defer/client/src/pages/index.re
index 94cd61f..b0af85d 100644
--- a/warp/defer/client/src/pages/index.re
+++ b/warp/defer/client/src/pages/index.re
@@ -2,39 +2,58 @@ module Query = [%relay.query
   {|
     query pagesQuery {
       books {
-        title
-        author
-        comments @defer {
-          user
-          text
-        }
+        ...pages_book
       }
     }
   |}
 ];
 
+module BookCommentsFragment = [%relay.fragment
+  {|
+  fragment pages_comments_book on Book {
+    comments {
+      text
+      user
+    }
+  }
+|}
+];
+
 module Comments = {
   [@react.component]
-  let make = (~comments) => {
-    Query.Types.(
-      comments
-      ->Belt.Option.getWithDefault([||])
-      ->Belt.Array.map(comment => {
-          let text = comment.text;
-          let user = comment.user;
-          <li key=text> {j|$user: $text|j}->React.string </li>;
-        })
-      ->React.array
-    );
+  let make = (~bookRef) => {
+    let book = BookCommentsFragment.use(bookRef);
+    book.comments
+    ->Belt.Option.getWithDefault([||])
+    ->Belt.Array.map(comment => {
+        let text = comment.text;
+        let user = comment.user;
+        <li key=text> {j|$user: $text|j}->React.string </li>;
+      })
+    ->React.array;
   };
 };
 
+module BookFragment = [%relay.fragment
+  {|
+  fragment pages_book on Book {
+    title
+    author
+    ...pages_comments_book @defer
+  }
+|}
+];
+
 module Book = {
   [@react.component]
-  let make = (~title, ~author, ~comments) => {
+  let make = (~bookRef) => {
+    let book = BookFragment.use(bookRef);
+    let title = book.title;
+    let author = book.author;
+
     <div>
       <p> {j|$title by $author|j}->React.string </p>
-      <Comments comments />
+      <Comments bookRef={book.getFragmentRefs()} />
     </div>;
   };
 };
@@ -44,7 +63,6 @@ module Books = {
   let make = () => {
     let response = Query.use(~variables=(), ());
     let booksCount = response.books->Js.Array.length;
-    Js.log2("books: ", response.books);
 
     <div>
       <h2
@@ -52,13 +70,8 @@ module Books = {
         {j|Streaming $booksCount books....|j}->React.string
       </h2>
       {response.books
-       ->Belt.Array.map(book =>
-           <Book
-             key={book.title}
-             title={book.title}
-             author={book.author}
-             comments={book.comments}
-           />
+       ->Belt.Array.mapWithIndex((idx, book) =>
+           <Book key={string_of_int(idx)} bookRef={book.getFragmentRefs()} />
          )
        ->React.array}
     </div>;