Repository: miragejs/miragejs (js)

Issue:
Public API for relationship introspection
I think there's a gap in the API today, its reasonable for folks to want to do things like

- have the server default include all direct relationships
- do things like in https://github.com/miragejs/miragejs/issues/298#issuecomment-574766130

We need a public API for folks to be able to introspect all the relationships.

We have these APIs on schema, just need to review them + make them public.

Also for the first bullet point above, we should pass `model` into the `include()` function.

Pull request description:
Pass the primary resource to serializer.include()
Closes #311

Patch:
diff --git a/lib/serializer.js b/lib/serializer.js
index 9cf0ce6..0ed3ec4 100644
--- a/lib/serializer.js
+++ b/lib/serializer.js
@@ -358,6 +358,8 @@ class Serializer {
     @return { Object } the json response
    */
   serialize(primaryResource /* , request */) {
+    this.primaryResource = primaryResource;
+
     return this.buildPayload(primaryResource);
   }
 
@@ -1110,7 +1112,9 @@ class Serializer {
   }
 
   getKeysForIncluded() {
-    return isFunction(this.include) ? this.include(this.request) : this.include;
+    return isFunction(this.include)
+      ? this.include(this.request, this.primaryResource)
+      : this.include;
   }
 
   /**


Test patch:
diff --git a/__tests__/internal/move-after-handle-request/serializers/includes-test.js b/__tests__/internal/move-after-handle-request/serializers/includes-test.js
new file mode 100644
index 0000000..17c83cf
--- /dev/null
+++ b/__tests__/internal/move-after-handle-request/serializers/includes-test.js
@@ -0,0 +1,158 @@
+import { Server, Model, hasMany, belongsTo, Serializer } from "miragejs";
+
+describe("Internal | MoveAfterHandleRequest | Serializers | includes", function() {
+  let server;
+
+  beforeEach(function() {
+    server = new Server({
+      environment: "test",
+      models: {
+        wordSmith: Model.extend({
+          posts: hasMany("blog-post")
+        }),
+        blogPost: Model.extend({
+          author: belongsTo("word-smith"),
+          comments: hasMany("fine-comment")
+        }),
+        fineComment: Model.extend({
+          post: belongsTo("blog-post")
+        })
+      },
+      routes() {
+        this.resource("blog-posts");
+      }
+    });
+
+    let wordSmith = server.schema.wordSmiths.create({ name: "Link" });
+    let blogPost = wordSmith.createPost({ title: "Lorem" });
+    blogPost.createComment({ text: "pwned" });
+  });
+
+  afterEach(function() {
+    server.shutdown();
+  });
+
+  test("include can be an array of relationship names", async () => {
+    server.config({
+      serializers: {
+        blogPost: Serializer.extend({
+          include: ["author", "comments"]
+        })
+      }
+    });
+
+    let json = await fetch("/blog-posts/1").then(res => res.json());
+
+    expect(json).toEqual({
+      blogPost: {
+        authorId: "1",
+        commentIds: ["1"],
+        id: "1",
+        title: "Lorem"
+      },
+      fineComments: [
+        {
+          id: "1",
+          text: "pwned"
+        }
+      ],
+      wordSmiths: [
+        {
+          id: "1",
+          name: "Link"
+        }
+      ]
+    });
+  });
+
+  test("include can be a function", async () => {
+    server.config({
+      serializers: {
+        blogPost: Serializer.extend({
+          include() {
+            return ["comments"];
+          }
+        })
+      }
+    });
+
+    let json = await fetch("/blog-posts/1").then(res => res.json());
+
+    expect(json).toEqual({
+      blogPost: {
+        commentIds: ["1"],
+        id: "1",
+        title: "Lorem"
+      },
+      fineComments: [
+        {
+          id: "1",
+          text: "pwned"
+        }
+      ]
+    });
+  });
+
+  test("include gets the request as the first param", async () => {
+    server.config({
+      serializers: {
+        blogPost: Serializer.extend({
+          include(request) {
+            return request.queryParams.include ? ["comments"] : [];
+          }
+        })
+      }
+    });
+
+    let json = await fetch("/blog-posts/1?include").then(res => res.json());
+
+    expect(json).toEqual({
+      blogPost: {
+        commentIds: ["1"],
+        id: "1",
+        title: "Lorem"
+      },
+      fineComments: [
+        {
+          id: "1",
+          text: "pwned"
+        }
+      ]
+    });
+  });
+
+  test("include gets the model as the second param", async () => {
+    server.config({
+      serializers: {
+        blogPost: Serializer.extend({
+          include(request, model) {
+            return Object.keys(model.associations);
+          }
+        })
+      }
+    });
+
+    let json = await fetch("/blog-posts/1?include").then(res => res.json());
+
+    expect(json).toEqual({
+      blogPost: {
+        authorId: "1",
+        commentIds: ["1"],
+        id: "1",
+        title: "Lorem"
+      },
+      fineComments: [
+        {
+          id: "1",
+          text: "pwned"
+        }
+      ],
+      wordSmiths: [
+        {
+          id: "1",
+          name: "Link"
+        }
+      ]
+    });
+  });
+});