@khanacademy/wonder-blocks-data 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @khanacademy/wonder-blocks-data
2
2
 
3
+ ## 3.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6973afa2: useGql method now merges defaultContext and partial context by ignoring values explicitly set to undefined in the partial context. This ensures that that existing default context values are not overridden unless explicitly given a value other than undefined.
8
+
9
+ ## 3.1.3
10
+
11
+ ### Patch Changes
12
+
13
+ - 9931ae6b: Simplify GQL types
14
+
15
+ ## 3.1.2
16
+
17
+ ### Patch Changes
18
+
19
+ - @khanacademy/wonder-blocks-core@4.2.1
20
+
21
+ ## 3.1.1
22
+
23
+ ### Patch Changes
24
+
25
+ - 4ff59815: Add GraphQL fetch mock support to wonder-blocks-testing
26
+
3
27
  ## 3.1.0
4
28
 
5
29
  ### Minor Changes
package/dist/es/index.js CHANGED
@@ -865,6 +865,10 @@ const getGqlDataFromResponse = async response => {
865
865
  *
866
866
  * The fetch function will resolve null if the request was aborted, otherwise
867
867
  * it will resolve the data returned by the GraphQL server.
868
+ *
869
+ * Context is merged with the default context provided to the GqlRouter.
870
+ * Values in the partial context given to the returned fetch function will
871
+ * only be included if they have a value other than undefined.
868
872
  */
869
873
  const useGql = () => {
870
874
  // This hook only works if the `GqlRouter` has been used to setup context.
@@ -886,10 +890,22 @@ const useGql = () => {
886
890
  const gqlFetch = useMemo(() => (operation, options = Object.freeze({})) => {
887
891
  const {
888
892
  variables,
889
- context
890
- } = options; // Invoke the fetch and extract the data.
893
+ context = {}
894
+ } = options; // Let's merge the partial context of the fetch with the
895
+ // default context. We deliberately don't spread because
896
+ // spreading would overwrite default context values with
897
+ // undefined if the partial context includes a value explicitly
898
+ // set to undefined. Instead, we use a map/reduce of keys.
899
+
900
+ const mergedContext = Object.keys(context).reduce((acc, key) => {
901
+ if (context[key] !== undefined) {
902
+ acc[key] = context[key];
903
+ }
904
+
905
+ return acc;
906
+ }, _extends({}, defaultContext)); // Invoke the fetch and extract the data.
891
907
 
892
- return fetch(operation, variables, _extends({}, defaultContext, context)).then(getGqlDataFromResponse, error => {
908
+ return fetch(operation, variables, mergedContext).then(getGqlDataFromResponse, error => {
893
909
  // Return null if the request was aborted.
894
910
  // The only way to detect this reliably, it seems, is to
895
911
  // check the error name and see if it's "AbortError" (this
@@ -897,7 +913,10 @@ const useGql = () => {
897
913
  // Even then, it's reliant on the fetch supporting aborts.
898
914
  if (error.name === "AbortError") {
899
915
  return null;
900
- }
916
+ } // Need to make sure we pass other errors along.
917
+
918
+
919
+ throw error;
901
920
  });
902
921
  }, [fetch, defaultContext]);
903
922
  return gqlFetch;
package/dist/index.js CHANGED
@@ -1032,6 +1032,10 @@ const GqlRouter = ({
1032
1032
  *
1033
1033
  * The fetch function will resolve null if the request was aborted, otherwise
1034
1034
  * it will resolve the data returned by the GraphQL server.
1035
+ *
1036
+ * Context is merged with the default context provided to the GqlRouter.
1037
+ * Values in the partial context given to the returned fetch function will
1038
+ * only be included if they have a value other than undefined.
1035
1039
  */
1036
1040
  const useGql = () => {
1037
1041
  // This hook only works if the `GqlRouter` has been used to setup context.
@@ -1053,12 +1057,23 @@ const useGql = () => {
1053
1057
  const gqlFetch = Object(react__WEBPACK_IMPORTED_MODULE_0__["useMemo"])(() => (operation, options = Object.freeze({})) => {
1054
1058
  const {
1055
1059
  variables,
1056
- context
1057
- } = options; // Invoke the fetch and extract the data.
1060
+ context = {}
1061
+ } = options; // Let's merge the partial context of the fetch with the
1062
+ // default context. We deliberately don't spread because
1063
+ // spreading would overwrite default context values with
1064
+ // undefined if the partial context includes a value explicitly
1065
+ // set to undefined. Instead, we use a map/reduce of keys.
1066
+
1067
+ const mergedContext = Object.keys(context).reduce((acc, key) => {
1068
+ if (context[key] !== undefined) {
1069
+ acc[key] = context[key];
1070
+ }
1071
+
1072
+ return acc;
1073
+ }, { ...defaultContext
1074
+ }); // Invoke the fetch and extract the data.
1058
1075
 
1059
- return fetch(operation, variables, { ...defaultContext,
1060
- ...context
1061
- }).then(_util_get_gql_data_from_response_js__WEBPACK_IMPORTED_MODULE_2__[/* getGqlDataFromResponse */ "a"], error => {
1076
+ return fetch(operation, variables, mergedContext).then(_util_get_gql_data_from_response_js__WEBPACK_IMPORTED_MODULE_2__[/* getGqlDataFromResponse */ "a"], error => {
1062
1077
  // Return null if the request was aborted.
1063
1078
  // The only way to detect this reliably, it seems, is to
1064
1079
  // check the error name and see if it's "AbortError" (this
@@ -1066,7 +1081,10 @@ const useGql = () => {
1066
1081
  // Even then, it's reliant on the fetch supporting aborts.
1067
1082
  if (error.name === "AbortError") {
1068
1083
  return null;
1069
- }
1084
+ } // Need to make sure we pass other errors along.
1085
+
1086
+
1087
+ throw error;
1070
1088
  });
1071
1089
  }, [fetch, defaultContext]);
1072
1090
  return gqlFetch;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@khanacademy/wonder-blocks-data",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "design": "v1",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -14,14 +14,14 @@
14
14
  },
15
15
  "dependencies": {
16
16
  "@babel/runtime": "^7.16.3",
17
- "@khanacademy/wonder-blocks-core": "^4.0.0"
17
+ "@khanacademy/wonder-blocks-core": "^4.2.1"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@khanacademy/wonder-stuff-core": "^0.1.2",
21
21
  "react": "16.14.0"
22
22
  },
23
23
  "devDependencies": {
24
- "wb-dev-build-settings": "^0.2.0"
24
+ "wb-dev-build-settings": "^0.3.0"
25
25
  },
26
26
  "author": "",
27
27
  "license": "MIT"
@@ -5,7 +5,7 @@ import {GqlRouterContext} from "../util/gql-router-context.js";
5
5
 
6
6
  import type {
7
7
  GqlContext,
8
- FetchFn,
8
+ GqlFetchFn,
9
9
  GqlRouterConfiguration,
10
10
  } from "../util/gql-types.js";
11
11
 
@@ -18,7 +18,7 @@ type Props<TContext: GqlContext> = {|
18
18
  /**
19
19
  * The function to use when fetching requests.
20
20
  */
21
- fetch: FetchFn<any, any, any, TContext>,
21
+ fetch: GqlFetchFn<any, any, TContext>,
22
22
 
23
23
  /**
24
24
  * The children to be rendered inside the router.
@@ -80,6 +80,7 @@ describe("#useGql", () => {
80
80
  id: "MyQuery",
81
81
  };
82
82
  const gqlOpContext = {
83
+ a: undefined, // This should not get included.
83
84
  b: "overrideB",
84
85
  };
85
86
  const gqlOpVariables = {
@@ -9,7 +9,6 @@ import type {
9
9
  GqlContext,
10
10
  GqlOperation,
11
11
  GqlFetchOptions,
12
- GqlOperationType,
13
12
  } from "../util/gql-types.js";
14
13
 
15
14
  /**
@@ -17,14 +16,13 @@ import type {
17
16
  *
18
17
  * The fetch function will resolve null if the request was aborted, otherwise
19
18
  * it will resolve the data returned by the GraphQL server.
19
+ *
20
+ * Context is merged with the default context provided to the GqlRouter.
21
+ * Values in the partial context given to the returned fetch function will
22
+ * only be included if they have a value other than undefined.
20
23
  */
21
- export const useGql = (): (<
22
- TType: GqlOperationType,
23
- TData,
24
- TVariables: {...},
25
- TContext: GqlContext,
26
- >(
27
- operation: GqlOperation<TType, TData, TVariables>,
24
+ export const useGql = (): (<TData, TVariables: {...}, TContext: GqlContext>(
25
+ operation: GqlOperation<TData, TVariables>,
28
26
  options?: GqlFetchOptions<TVariables, TContext>,
29
27
  ) => Promise<?TData>) => {
30
28
  // This hook only works if the `GqlRouter` has been used to setup context.
@@ -41,33 +39,45 @@ export const useGql = (): (<
41
39
  // in hooks deps without fear of it triggering extra renders.
42
40
  const gqlFetch = useMemo(
43
41
  () =>
44
- <
45
- TType: GqlOperationType,
46
- TData,
47
- TVariables: {...},
48
- TContext: GqlContext,
49
- >(
50
- operation: GqlOperation<TType, TData, TVariables>,
42
+ <TData, TVariables: {...}, TContext: GqlContext>(
43
+ operation: GqlOperation<TData, TVariables>,
51
44
  options: GqlFetchOptions<TVariables, TContext> = Object.freeze(
52
45
  {},
53
46
  ),
54
47
  ) => {
55
- const {variables, context} = options;
48
+ const {variables, context = {}} = options;
49
+
50
+ // Let's merge the partial context of the fetch with the
51
+ // default context. We deliberately don't spread because
52
+ // spreading would overwrite default context values with
53
+ // undefined if the partial context includes a value explicitly
54
+ // set to undefined. Instead, we use a map/reduce of keys.
55
+ const mergedContext = Object.keys(context).reduce(
56
+ (acc, key) => {
57
+ if (context[key] !== undefined) {
58
+ acc[key] = context[key];
59
+ }
60
+ return acc;
61
+ },
62
+ {...defaultContext},
63
+ );
56
64
 
57
65
  // Invoke the fetch and extract the data.
58
- return fetch(operation, variables, {
59
- ...defaultContext,
60
- ...context,
61
- }).then(getGqlDataFromResponse, (error) => {
62
- // Return null if the request was aborted.
63
- // The only way to detect this reliably, it seems, is to
64
- // check the error name and see if it's "AbortError" (this
65
- // is also what Apollo does).
66
- // Even then, it's reliant on the fetch supporting aborts.
67
- if (error.name === "AbortError") {
68
- return null;
69
- }
70
- });
66
+ return fetch(operation, variables, mergedContext).then(
67
+ getGqlDataFromResponse,
68
+ (error) => {
69
+ // Return null if the request was aborted.
70
+ // The only way to detect this reliably, it seems, is to
71
+ // check the error name and see if it's "AbortError" (this
72
+ // is also what Apollo does).
73
+ // Even then, it's reliant on the fetch supporting aborts.
74
+ if (error.name === "AbortError") {
75
+ return null;
76
+ }
77
+ // Need to make sure we pass other errors along.
78
+ throw error;
79
+ },
80
+ );
71
81
  },
72
82
  [fetch, defaultContext],
73
83
  );
package/src/index.js CHANGED
@@ -60,4 +60,10 @@ export {useData} from "./hooks/use-data.js";
60
60
  export {GqlRouter} from "./components/gql-router.js";
61
61
  export {useGql} from "./hooks/use-gql.js";
62
62
  export * from "./util/gql-error.js";
63
- export type {GqlContext, GqlOperation} from "./util/gql-types.js";
63
+ export type {
64
+ GqlContext,
65
+ GqlOperation,
66
+ GqlOperationType,
67
+ GqlFetchOptions,
68
+ GqlFetchFn,
69
+ } from "./util/gql-types.js";
@@ -8,7 +8,6 @@ export type GqlOperationType = "mutation" | "query";
8
8
  * A GraphQL operation.
9
9
  */
10
10
  export type GqlOperation<
11
- TType: GqlOperationType,
12
11
  // TData is not used to define a field on this type, but it is used
13
12
  // to ensure that calls using this operation will properly return the
14
13
  // correct data type.
@@ -20,13 +19,14 @@ export type GqlOperation<
20
19
  // eslint-disable-next-line no-unused-vars
21
20
  TVariables: {...} = Empty,
22
21
  > = {
23
- type: TType,
22
+ type: GqlOperationType,
24
23
  id: string,
25
24
  // We allow other things here to be passed along to the fetch function.
26
25
  // For example, we might want to pass the full query/mutation definition
27
26
  // as a string here to allow that to be sent to an Apollo server that
28
27
  // expects it. This is a courtesy to calling code; these additional
29
28
  // values are ignored by WB Data, and passed through as-is.
29
+ [key: string]: mixed,
30
30
  ...
31
31
  };
32
32
 
@@ -37,8 +37,8 @@ export type GqlContext = {|
37
37
  /**
38
38
  * Functions that make fetches of GQL operations.
39
39
  */
40
- export type FetchFn<TType, TData, TVariables: {...}, TContext: GqlContext> = (
41
- operation: GqlOperation<TType, TData, TVariables>,
40
+ export type GqlFetchFn<TData, TVariables: {...}, TContext: GqlContext> = (
41
+ operation: GqlOperation<TData, TVariables>,
42
42
  variables: ?TVariables,
43
43
  context: TContext,
44
44
  ) => Promise<Response>;
@@ -47,7 +47,7 @@ export type FetchFn<TType, TData, TVariables: {...}, TContext: GqlContext> = (
47
47
  * The configuration stored in the GqlRouterContext context.
48
48
  */
49
49
  export type GqlRouterConfiguration<TContext: GqlContext> = {|
50
- fetch: FetchFn<any, any, any, any>,
50
+ fetch: GqlFetchFn<any, any, any>,
51
51
  defaultContext: TContext,
52
52
  |};
53
53