From d36f7152e34552e533d5fbc1c10fde35017a6b09 Mon Sep 17 00:00:00 2001 From: Maksim Shylau Date: Wed, 24 Apr 2024 10:53:19 +0200 Subject: [PATCH] Add `includeUnusedVariables` option support remove console.log statements --- createUploadLink.mjs | 11 +++ createUploadLink.test.mjs | 142 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) diff --git a/createUploadLink.mjs b/createUploadLink.mjs index f0c3d3a..db29b81 100644 --- a/createUploadLink.mjs +++ b/createUploadLink.mjs @@ -11,6 +11,7 @@ import { } from "@apollo/client/link/http/selectHttpOptionsAndBody.js"; import { selectURI } from "@apollo/client/link/http/selectURI.js"; import { serializeFetchParameter } from "@apollo/client/link/http/serializeFetchParameter.js"; +import { filterOperationVariables } from "@apollo/client/link/utils/filterOperationVariables.js"; import { Observable } from "@apollo/client/utilities/observables/Observable.js"; import extractFiles from "extract-files/extractFiles.mjs"; @@ -63,6 +64,8 @@ import isExtractableFile from "./isExtractableFile.mjs"; * {@linkcode fetchOptions}. * @param {boolean} [options.includeExtensions] Toggles sending `extensions` * fields to the GraphQL server. Defaults to `false`. + * @param {boolean} [options.includeUnusedVariables] * If set to true, the default behavior of stripping unused variables + * from the request will be disabled. Defaults to `false`. * @returns A [terminating Apollo Link](https://www.apollographql.com/docs/react/api/link/introduction/#the-terminating-link). * @example * A basic Apollo Client setup: @@ -89,6 +92,7 @@ export default function createUploadLink({ credentials, headers, includeExtensions, + includeUnusedVariables = false, } = {}) { const linkConfig = { http: { includeExtensions }, @@ -136,6 +140,13 @@ export default function createUploadLink({ contextConfig, ); + if (body.variables && !includeUnusedVariables) { + body.variables = filterOperationVariables( + body.variables, + operation.query, + ); + } + const { clone, files } = extractFiles(body, customIsExtractableFile, ""); let uri = selectURI(operation, fetchUri); diff --git a/createUploadLink.test.mjs b/createUploadLink.test.mjs index e5f6890..982ae04 100644 --- a/createUploadLink.test.mjs +++ b/createUploadLink.test.mjs @@ -316,6 +316,147 @@ describe("Function `createUploadLink`.", { concurrency: true }, () => { deepStrictEqual(nextData, payload); }); + it("Option `includeUnusedVariables`, set to false", async () => { + /** @type {unknown} */ + let fetchInput; + + /** @type {RequestInit | undefined} */ + let fetchOptions; + + /** @type {unknown} */ + let nextData; + + const query = "query ($a: Boolean) {\n a(a: $a)\n}"; + const payload = { data: { a: true, b: true } }; + + await timeLimitPromise( + /** @type {Promise} */ ( + new Promise((resolve, reject) => { + execute( + createUploadLink({ + includeUnusedVariables: false, + async fetch(input, options) { + fetchInput = input; + fetchOptions = options; + + return new Response( + JSON.stringify(payload), + graphqlResponseOptions, + ); + }, + }), + { + query: gql(query), + variables: { + a: true, + b: true, + }, + }, + ).subscribe({ + next(data) { + nextData = data; + }, + error() { + reject(createUnexpectedCallError()); + }, + complete() { + resolve(); + }, + }); + }) + ), + ); + + strictEqual(fetchInput, defaultUri); + ok(typeof fetchOptions === "object"); + + const { signal: fetchOptionsSignal, ...fetchOptionsRest } = fetchOptions; + + ok(fetchOptionsSignal instanceof AbortSignal); + deepEqual(fetchOptionsRest, { + method: "POST", + headers: { accept: "*/*", "content-type": "application/json" }, + body: JSON.stringify({ + variables: { + a: true, + }, + query, + }), + }); + deepStrictEqual(nextData, payload); + }); + + it("Option `includeUnusedVariables`, set to true", async () => { + /** @type {unknown} */ + let fetchInput; + + /** @type {RequestInit | undefined} */ + let fetchOptions; + + /** @type {unknown} */ + let nextData; + + const query = "query ($a: Boolean) {\n a(a: $a)\n}"; + const payload = { data: { a: true, b: true } }; + + await timeLimitPromise( + /** @type {Promise} */ ( + new Promise((resolve, reject) => { + execute( + createUploadLink({ + includeUnusedVariables: true, + async fetch(input, options) { + fetchInput = input; + fetchOptions = options; + + return new Response( + JSON.stringify(payload), + graphqlResponseOptions, + ); + }, + }), + { + query: gql(query), + variables: { + a: true, + b: true, + }, + }, + ).subscribe({ + next(data) { + nextData = data; + }, + error() { + reject(createUnexpectedCallError()); + }, + complete() { + resolve(); + }, + }); + }) + ), + ); + + strictEqual(fetchInput, defaultUri); + ok(typeof fetchOptions === "object"); + + const { signal: fetchOptionsSignal, ...fetchOptionsRest } = fetchOptions; + + ok(fetchOptionsSignal instanceof AbortSignal); + deepEqual(fetchOptionsRest, { + method: "POST", + headers: { accept: "*/*", "content-type": "application/json" }, + body: JSON.stringify({ + variables: { + a: true, + b: true, + }, + query, + }), + }); + deepStrictEqual(nextData, payload); + }); + it("Option `print`.", async () => { /** @type {unknown} */ let fetchInput; @@ -608,6 +749,7 @@ describe("Function `createUploadLink`.", { concurrency: true }, () => { execute( createUploadLink({ useGETForQueries: true, + includeUnusedVariables: true, async fetch() { fetched = true;