@graphql-box/cache-manager 2.1.4 → 2.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.
Files changed (109) hide show
  1. package/lib/browser/index.js +1 -1
  2. package/lib/browser/index.js.map +1 -1
  3. package/lib/browser/production.analysis.txt +129 -17
  4. package/lib/main/debug/log-cache-entry/index.js.map +1 -1
  5. package/lib/main/debug/log-partial-compiled/index.js.map +1 -1
  6. package/lib/main/helpers/buildKeysAndPaths.js +73 -0
  7. package/lib/main/helpers/buildKeysAndPaths.js.map +1 -0
  8. package/lib/main/helpers/checkFieldPathChecklist.js +40 -0
  9. package/lib/main/helpers/checkFieldPathChecklist.js.map +1 -0
  10. package/lib/main/helpers/createFragmentSpreadChecklist.js +28 -0
  11. package/lib/main/helpers/createFragmentSpreadChecklist.js.map +1 -0
  12. package/lib/main/helpers/filterField.js +97 -0
  13. package/lib/main/helpers/filterField.js.map +1 -0
  14. package/lib/main/helpers/filterFragmentDefinitions.js +50 -0
  15. package/lib/main/helpers/filterFragmentDefinitions.js.map +1 -0
  16. package/lib/main/helpers/filterFragmentSpreads.js +37 -0
  17. package/lib/main/helpers/filterFragmentSpreads.js.map +1 -0
  18. package/lib/main/helpers/filterIDsAndTypeNames.js +47 -0
  19. package/lib/main/helpers/filterIDsAndTypeNames.js.map +1 -0
  20. package/lib/main/helpers/filterInlineFragments.js +42 -0
  21. package/lib/main/helpers/filterInlineFragments.js.map +1 -0
  22. package/lib/main/helpers/filterOutPropsWithArgsOrDirectives.js +39 -0
  23. package/lib/main/helpers/filterOutPropsWithArgsOrDirectives.js.map +1 -0
  24. package/lib/main/helpers/filterQuery.js +59 -0
  25. package/lib/main/helpers/filterQuery.js.map +1 -0
  26. package/lib/main/helpers/normalizeResponseData.js +23 -0
  27. package/lib/main/helpers/normalizeResponseData.js.map +1 -0
  28. package/lib/main/helpers/validTypeIDValue.js +20 -0
  29. package/lib/main/helpers/validTypeIDValue.js.map +1 -0
  30. package/lib/main/main/index.js +468 -472
  31. package/lib/main/main/index.js.map +1 -1
  32. package/lib/module/debug/log-cache-entry/index.js.map +1 -1
  33. package/lib/module/debug/log-partial-compiled/index.js.map +1 -1
  34. package/lib/module/helpers/buildKeysAndPaths.js +54 -0
  35. package/lib/module/helpers/buildKeysAndPaths.js.map +1 -0
  36. package/lib/module/helpers/checkFieldPathChecklist.js +31 -0
  37. package/lib/module/helpers/checkFieldPathChecklist.js.map +1 -0
  38. package/lib/module/helpers/createFragmentSpreadChecklist.js +15 -0
  39. package/lib/module/helpers/createFragmentSpreadChecklist.js.map +1 -0
  40. package/lib/module/helpers/filterField.js +81 -0
  41. package/lib/module/helpers/filterField.js.map +1 -0
  42. package/lib/module/helpers/filterFragmentDefinitions.js +39 -0
  43. package/lib/module/helpers/filterFragmentDefinitions.js.map +1 -0
  44. package/lib/module/helpers/filterFragmentSpreads.js +23 -0
  45. package/lib/module/helpers/filterFragmentSpreads.js.map +1 -0
  46. package/lib/module/helpers/filterIDsAndTypeNames.js +36 -0
  47. package/lib/module/helpers/filterIDsAndTypeNames.js.map +1 -0
  48. package/lib/module/helpers/filterInlineFragments.js +32 -0
  49. package/lib/module/helpers/filterInlineFragments.js.map +1 -0
  50. package/lib/module/helpers/filterOutPropsWithArgsOrDirectives.js +25 -0
  51. package/lib/module/helpers/filterOutPropsWithArgsOrDirectives.js.map +1 -0
  52. package/lib/module/helpers/filterQuery.js +43 -0
  53. package/lib/module/helpers/filterQuery.js.map +1 -0
  54. package/lib/module/helpers/normalizeResponseData.js +11 -0
  55. package/lib/module/helpers/normalizeResponseData.js.map +1 -0
  56. package/lib/module/helpers/validTypeIDValue.js +8 -0
  57. package/lib/module/helpers/validTypeIDValue.js.map +1 -0
  58. package/lib/module/main/index.js +465 -470
  59. package/lib/module/main/index.js.map +1 -1
  60. package/lib/types/debug/log-cache-entry/index.d.ts.map +1 -1
  61. package/lib/types/debug/log-cache-query/index.d.ts.map +1 -1
  62. package/lib/types/debug/log-partial-compiled/index.d.ts.map +1 -1
  63. package/lib/types/defs/index.d.ts +19 -9
  64. package/lib/types/defs/index.d.ts.map +1 -1
  65. package/lib/types/helpers/buildKeysAndPaths.d.ts +10 -0
  66. package/lib/types/helpers/buildKeysAndPaths.d.ts.map +1 -0
  67. package/lib/types/helpers/checkFieldPathChecklist.d.ts +4 -0
  68. package/lib/types/helpers/checkFieldPathChecklist.d.ts.map +1 -0
  69. package/lib/types/helpers/createFragmentSpreadChecklist.d.ts +11 -0
  70. package/lib/types/helpers/createFragmentSpreadChecklist.d.ts.map +1 -0
  71. package/lib/types/helpers/filterField.d.ts +6 -0
  72. package/lib/types/helpers/filterField.d.ts.map +1 -0
  73. package/lib/types/helpers/filterFragmentDefinitions.d.ts +10 -0
  74. package/lib/types/helpers/filterFragmentDefinitions.d.ts.map +1 -0
  75. package/lib/types/helpers/filterFragmentSpreads.d.ts +6 -0
  76. package/lib/types/helpers/filterFragmentSpreads.d.ts.map +1 -0
  77. package/lib/types/helpers/filterIDsAndTypeNames.d.ts +5 -0
  78. package/lib/types/helpers/filterIDsAndTypeNames.d.ts.map +1 -0
  79. package/lib/types/helpers/filterInlineFragments.d.ts +5 -0
  80. package/lib/types/helpers/filterInlineFragments.d.ts.map +1 -0
  81. package/lib/types/helpers/filterOutPropsWithArgsOrDirectives.d.ts +6 -0
  82. package/lib/types/helpers/filterOutPropsWithArgsOrDirectives.d.ts.map +1 -0
  83. package/lib/types/helpers/filterQuery.d.ts +5 -0
  84. package/lib/types/helpers/filterQuery.d.ts.map +1 -0
  85. package/lib/types/helpers/normalizeResponseData.d.ts +10 -0
  86. package/lib/types/helpers/normalizeResponseData.d.ts.map +1 -0
  87. package/lib/types/helpers/validTypeIDValue.d.ts +3 -0
  88. package/lib/types/helpers/validTypeIDValue.d.ts.map +1 -0
  89. package/lib/types/main/index.d.ts +13 -20
  90. package/lib/types/main/index.d.ts.map +1 -1
  91. package/package.json +2 -2
  92. package/src/__snapshots__/index.test.ts.snap +17449 -7185
  93. package/src/debug/log-cache-entry/index.ts +1 -1
  94. package/src/debug/log-partial-compiled/index.ts +1 -1
  95. package/src/defs/index.ts +18 -10
  96. package/src/helpers/buildKeysAndPaths.ts +71 -0
  97. package/src/helpers/checkFieldPathChecklist.ts +21 -0
  98. package/src/helpers/createFragmentSpreadChecklist.ts +17 -0
  99. package/src/helpers/filterField.ts +73 -0
  100. package/src/helpers/filterFragmentDefinitions.ts +40 -0
  101. package/src/helpers/filterFragmentSpreads.ts +28 -0
  102. package/src/helpers/filterIDsAndTypeNames.ts +31 -0
  103. package/src/helpers/filterInlineFragments.ts +29 -0
  104. package/src/helpers/filterOutPropsWithArgsOrDirectives.ts +30 -0
  105. package/src/helpers/filterQuery.ts +38 -0
  106. package/src/helpers/normalizeResponseData.ts +9 -0
  107. package/src/helpers/validTypeIDValue.ts +11 -0
  108. package/src/index.test.ts +179 -3
  109. package/src/main/index.ts +506 -499
@@ -11,7 +11,7 @@ export default function logCacheEntry() {
11
11
  if (!method) return;
12
12
 
13
13
  descriptor.value = async function descriptorValue(...args: any[]): Promise<any> {
14
- return new Promise(async resolve => {
14
+ return new Promise<void>(async resolve => {
15
15
  const { debugManager, ...otherContext } = args[5] as RequestContext;
16
16
 
17
17
  if (!debugManager) {
@@ -11,7 +11,7 @@ export default function logPartialCompiled() {
11
11
  if (!method) return;
12
12
 
13
13
  descriptor.value = async function descriptorValue(...args: any[]): Promise<any> {
14
- return new Promise(async resolve => {
14
+ return new Promise<void>(async resolve => {
15
15
  const { debugManager, ...otherContext } = args[3] as RequestContext;
16
16
 
17
17
  if (!debugManager) {
package/src/defs/index.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  RequestOptions,
13
13
  ResponseData,
14
14
  } from "@graphql-box/core";
15
+ import { FragmentDefinitionNodeMap } from "@graphql-box/helpers";
15
16
  import Cacheability from "cacheability";
16
17
 
17
18
  export interface UserOptions {
@@ -62,6 +63,11 @@ export interface ConstructorOptions {
62
63
  typeIDKey: string;
63
64
  }
64
65
 
66
+ export interface CacheManagerContext extends RequestContext {
67
+ fragmentDefinitions?: FragmentDefinitionNodeMap;
68
+ typeIDKey?: string;
69
+ }
70
+
65
71
  export interface PartialQueryResponse {
66
72
  cacheMetadata: CacheMetadata;
67
73
  data: PlainObjectMap;
@@ -75,6 +81,8 @@ export interface FieldCount {
75
81
  }
76
82
 
77
83
  export interface FieldPathChecklistValue {
84
+ fragmentKind: string | undefined;
85
+ fragmentName: string | undefined;
78
86
  hasData: boolean;
79
87
  typeName?: string | undefined;
80
88
  }
@@ -100,12 +108,6 @@ export interface AncestorKeysAndPaths {
100
108
  responseDataPath?: string;
101
109
  }
102
110
 
103
- export interface CachedFieldData {
104
- cacheability?: Cacheability;
105
- dataEntityData?: any;
106
- requestFieldPathData?: any;
107
- }
108
-
109
111
  export interface MergedCachedFieldData {
110
112
  cacheability?: Cacheability;
111
113
  data: any;
@@ -113,7 +115,9 @@ export interface MergedCachedFieldData {
113
115
 
114
116
  export interface CachedAncestorFieldData {
115
117
  cacheability?: Cacheability;
116
- dataEntityData?: any;
118
+ entityData?: any;
119
+ fragmentKind?: string;
120
+ fragmentName?: string;
117
121
  index?: number;
118
122
  requestFieldCacheKey?: string;
119
123
  requestFieldPath?: string;
@@ -136,14 +140,18 @@ export interface KeysAndPaths {
136
140
  responseDataPath: string;
137
141
  }
138
142
 
139
- export interface TypeNames {
143
+ export interface TypeNamesAndKind {
140
144
  dataTypeName: string | undefined;
141
145
  fieldTypeName: string | undefined;
146
+ fragmentKind: string | undefined;
147
+ fragmentName: string | undefined;
142
148
  }
143
149
 
150
+ export type FragmentSpreadFieldCounter = Record<string, { hasData: number; total: number }>;
151
+
144
152
  export interface ResponseDataForCaching {
145
153
  cacheMetadata: CacheMetadata;
146
- dataEntityData: PlainObjectMap;
154
+ entityData: PlainObjectMap;
147
155
  requestFieldPathData: PlainObjectMap;
148
156
  }
149
157
 
@@ -165,7 +173,7 @@ export interface AnalyzeQueryResult {
165
173
 
166
174
  export interface CheckCacheEntryResult {
167
175
  cacheability: Cacheability;
168
- entry: PlainObjectMap | any[];
176
+ entry: any;
169
177
  }
170
178
 
171
179
  export interface QueryResponseCacheEntry {
@@ -0,0 +1,71 @@
1
+ import { FieldTypeInfo, PlainObjectMap } from "@graphql-box/core";
2
+ import { getAlias, getArguments, getName, hashRequest } from "@graphql-box/helpers";
3
+ import { FieldNode } from "graphql";
4
+ import { isNumber } from "lodash";
5
+ import { CacheManagerContext, KeysAndPaths, KeysAndPathsOptions } from "../defs";
6
+
7
+ export const buildKey = (path: string, key: string | number) => {
8
+ const paths: (string | number)[] = [];
9
+
10
+ if (path.length) {
11
+ paths.push(path);
12
+ }
13
+
14
+ paths.push(key);
15
+ return paths.join(".");
16
+ };
17
+
18
+ export const buildRequestFieldCacheKey = (
19
+ name: string,
20
+ requestFieldCacheKey: string,
21
+ args: PlainObjectMap | undefined,
22
+ directives?: FieldTypeInfo["directives"],
23
+ index?: number,
24
+ ) => {
25
+ let key = `${isNumber(index) ? index : name}`;
26
+
27
+ if (args) {
28
+ key = `${key}(${JSON.stringify(args)})`;
29
+ }
30
+
31
+ if (directives?.inherited?.length) {
32
+ key = `${directives.inherited.join(" ")} ${key}`;
33
+ }
34
+
35
+ if (directives?.own?.length) {
36
+ key = `${key} ${directives.own.join(" ")}`;
37
+ }
38
+
39
+ return buildKey(requestFieldCacheKey, key);
40
+ };
41
+
42
+ export const buildFieldKeysAndPaths = (
43
+ field: FieldNode,
44
+ options: KeysAndPathsOptions,
45
+ context: CacheManagerContext,
46
+ ): KeysAndPaths => {
47
+ const name = getName(field) as FieldNode["name"]["value"];
48
+ const { index, requestFieldCacheKey = "", requestFieldPath = "", responseDataPath = "" } = options;
49
+ const fieldAliasOrName = getAlias(field) || name;
50
+ const updatedRequestFieldPath = isNumber(index) ? requestFieldPath : buildKey(requestFieldPath, fieldAliasOrName);
51
+ const fieldTypeInfo = context.fieldTypeMap.get(updatedRequestFieldPath);
52
+
53
+ const updatedRequestFieldCacheKey = buildRequestFieldCacheKey(
54
+ name,
55
+ requestFieldCacheKey,
56
+ getArguments(field),
57
+ fieldTypeInfo?.directives,
58
+ index,
59
+ );
60
+
61
+ const propNameOrIndex = isNumber(index) ? index : fieldAliasOrName;
62
+ const updatedResponseDataPath = buildKey(responseDataPath, propNameOrIndex);
63
+
64
+ return {
65
+ hashedRequestFieldCacheKey: hashRequest(updatedRequestFieldCacheKey),
66
+ propNameOrIndex,
67
+ requestFieldCacheKey: updatedRequestFieldCacheKey,
68
+ requestFieldPath: updatedRequestFieldPath,
69
+ responseDataPath: updatedResponseDataPath,
70
+ };
71
+ };
@@ -0,0 +1,21 @@
1
+ import { CheckFieldPathChecklistResult, FieldPathChecklistValue } from "../defs";
2
+
3
+ export default (
4
+ fieldPathChecklistValues: FieldPathChecklistValue[] | undefined,
5
+ fieldTypeName: string | undefined,
6
+ ): CheckFieldPathChecklistResult => {
7
+ if (!fieldPathChecklistValues || !fieldPathChecklistValues.length) {
8
+ return { hasData: false, typeUnused: !!fieldTypeName };
9
+ }
10
+
11
+ if (fieldPathChecklistValues.length === 1) {
12
+ const { hasData, typeName } = fieldPathChecklistValues[0];
13
+ const typeUnused = !typeName ? undefined : typeName !== fieldTypeName;
14
+ return { hasData, typeUnused };
15
+ }
16
+
17
+ return {
18
+ hasData: fieldPathChecklistValues.some(({ hasData, typeName }) => typeName === fieldTypeName && hasData),
19
+ typeUnused: !fieldPathChecklistValues.every(({ typeName }) => typeName === fieldTypeName),
20
+ };
21
+ };
@@ -0,0 +1,17 @@
1
+ import { getFragmentDefinitions } from "@graphql-box/helpers";
2
+ import { DocumentNode } from "graphql";
3
+ import { keys } from "lodash";
4
+
5
+ export type FragmentSpreadCheckist = {
6
+ [key: string]: {
7
+ deleted: number;
8
+ paths: string[];
9
+ total: number;
10
+ };
11
+ };
12
+
13
+ export default (ast: DocumentNode) =>
14
+ keys(getFragmentDefinitions(ast) ?? {}).reduce((acc: FragmentSpreadCheckist, name) => {
15
+ acc[name] = { deleted: 0, paths: [], total: 0 };
16
+ return acc;
17
+ }, {});
@@ -0,0 +1,73 @@
1
+ import { TYPE_NAME_KEY } from "@graphql-box/core";
2
+ import { FRAGMENT_SPREAD, deleteChildFields, getChildFields, getName, hasChildFields } from "@graphql-box/helpers";
3
+ import { FieldNode, FragmentDefinitionNode } from "graphql";
4
+ import { CacheManagerContext, FieldPathChecklist, FragmentSpreadFieldCounter } from "../defs";
5
+ import { buildFieldKeysAndPaths } from "./buildKeysAndPaths";
6
+ import checkFieldPathChecklist from "./checkFieldPathChecklist";
7
+ import { FragmentSpreadCheckist } from "./createFragmentSpreadChecklist";
8
+ import filterFragmentSpreads from "./filterFragmentSpreads";
9
+ import filterIDsAndTypeNames from "./filterIDsAndTypeNames";
10
+ import filterInlineFragments from "./filterInlineFragments";
11
+
12
+ const filterField = (
13
+ field: FieldNode | FragmentDefinitionNode,
14
+ fieldPathChecklist: FieldPathChecklist,
15
+ fragmentSpreadChecklist: FragmentSpreadCheckist,
16
+ ancestorRequestFieldPath: string,
17
+ context: CacheManagerContext,
18
+ ): boolean => {
19
+ const { fragmentDefinitions, typeIDKey } = context;
20
+ const fieldsAndTypeNames = getChildFields(field, { fragmentDefinitions });
21
+
22
+ if (!fieldsAndTypeNames) {
23
+ return false;
24
+ }
25
+
26
+ const fragmentSpreadFieldCounter: FragmentSpreadFieldCounter = {};
27
+
28
+ for (let i = fieldsAndTypeNames.length - 1; i >= 0; i -= 1) {
29
+ const { fieldNode: childField, fragmentKind, fragmentName, typeName: childTypeName } = fieldsAndTypeNames[i];
30
+
31
+ if (fragmentKind === FRAGMENT_SPREAD && fragmentName && !fragmentSpreadFieldCounter[fragmentName]) {
32
+ fragmentSpreadFieldCounter[fragmentName] = {
33
+ hasData: 0,
34
+ total: fragmentDefinitions?.[fragmentName]
35
+ ? getChildFields(fragmentDefinitions?.[fragmentName], { fragmentDefinitions })?.length ?? 0
36
+ : 0,
37
+ };
38
+ }
39
+
40
+ const childFieldName = getName(childField);
41
+
42
+ if (childFieldName === typeIDKey || childFieldName === TYPE_NAME_KEY) {
43
+ continue;
44
+ }
45
+
46
+ const { requestFieldPath } = buildFieldKeysAndPaths(
47
+ childField,
48
+ {
49
+ requestFieldPath: ancestorRequestFieldPath,
50
+ },
51
+ context,
52
+ );
53
+
54
+ const { hasData, typeUnused } = checkFieldPathChecklist(fieldPathChecklist.get(requestFieldPath), childTypeName);
55
+
56
+ if (hasData || typeUnused) {
57
+ if (fragmentKind === FRAGMENT_SPREAD) {
58
+ fragmentSpreadFieldCounter[fragmentName as string].hasData += 1;
59
+ } else if (!hasChildFields(childField, { fragmentDefinitions })) {
60
+ deleteChildFields(field, childField);
61
+ } else if (filterField(childField, fieldPathChecklist, fragmentSpreadChecklist, requestFieldPath, context)) {
62
+ deleteChildFields(field, childField);
63
+ }
64
+ }
65
+ }
66
+
67
+ filterFragmentSpreads(field, fragmentSpreadFieldCounter, fragmentSpreadChecklist, ancestorRequestFieldPath);
68
+ filterInlineFragments(field, context);
69
+ filterIDsAndTypeNames(field, context);
70
+ return !hasChildFields(field, { fragmentDefinitions });
71
+ };
72
+
73
+ export default filterField;
@@ -0,0 +1,40 @@
1
+ import { deleteFragmentDefinitions, getFragmentDefinitions } from "@graphql-box/helpers";
2
+ import { DocumentNode } from "graphql";
3
+ import { keys } from "lodash";
4
+ import { CacheManagerContext, FieldPathChecklist } from "../defs";
5
+ import { FragmentSpreadCheckist } from "./createFragmentSpreadChecklist";
6
+ import filterField from "./filterField";
7
+
8
+ export default (
9
+ ast: DocumentNode,
10
+ fieldPathChecklist: FieldPathChecklist,
11
+ fragmentSpreadChecklist: FragmentSpreadCheckist,
12
+ context: CacheManagerContext,
13
+ ) => {
14
+ const definitionsToFilter = keys(fragmentSpreadChecklist).reduce(
15
+ (namesAndPaths: { name: string; path: string }[], key) => {
16
+ const { deleted, total } = fragmentSpreadChecklist[key];
17
+
18
+ return deleted === 0 && total === 1
19
+ ? [...namesAndPaths, { name: key, path: fragmentSpreadChecklist[key].paths[0] as string }]
20
+ : namesAndPaths;
21
+ },
22
+ [],
23
+ );
24
+
25
+ const fragmentDefinitions = getFragmentDefinitions(ast) ?? {};
26
+
27
+ definitionsToFilter.forEach(({ name, path }) => {
28
+ const fragmentDefinition = fragmentDefinitions[name];
29
+ filterField(fragmentDefinition, fieldPathChecklist, fragmentSpreadChecklist, path, context);
30
+ });
31
+
32
+ const definitionsToDelete = keys(fragmentSpreadChecklist).reduce((names: string[], key) => {
33
+ const { deleted, total } = fragmentSpreadChecklist[key];
34
+ return deleted > 0 && deleted === total ? [...names, key] : names;
35
+ }, []);
36
+
37
+ return deleteFragmentDefinitions(ast, {
38
+ include: definitionsToDelete,
39
+ });
40
+ };
@@ -0,0 +1,28 @@
1
+ import { deleteFragmentSpreads } from "@graphql-box/helpers";
2
+ import { FieldNode, FragmentDefinitionNode } from "graphql";
3
+ import { isEmpty, keys } from "lodash";
4
+ import { FragmentSpreadFieldCounter } from "../defs";
5
+ import { FragmentSpreadCheckist } from "./createFragmentSpreadChecklist";
6
+
7
+ export default (
8
+ field: FieldNode | FragmentDefinitionNode,
9
+ fragmentSpreadFieldCounter: FragmentSpreadFieldCounter,
10
+ fragmentSpreadChecklist: FragmentSpreadCheckist,
11
+ ancestorRequestFieldPath: string,
12
+ ) => {
13
+ if (isEmpty(fragmentSpreadFieldCounter)) {
14
+ return;
15
+ }
16
+
17
+ keys(fragmentSpreadFieldCounter).forEach(key => {
18
+ fragmentSpreadChecklist[key].total += 1;
19
+ fragmentSpreadChecklist[key].paths.push(ancestorRequestFieldPath);
20
+
21
+ const { hasData, total } = fragmentSpreadFieldCounter[key];
22
+
23
+ if (hasData === total) {
24
+ deleteFragmentSpreads(field, key);
25
+ fragmentSpreadChecklist[key].deleted += 1;
26
+ }
27
+ });
28
+ };
@@ -0,0 +1,31 @@
1
+ import { TYPE_NAME_KEY } from "@graphql-box/core";
2
+ import { deleteChildFields, getChildFields, getName } from "@graphql-box/helpers";
3
+ import { FieldNode, FragmentDefinitionNode } from "graphql";
4
+ import { CacheManagerContext } from "../defs";
5
+
6
+ export default (field: FieldNode | FragmentDefinitionNode, { fragmentDefinitions, typeIDKey }: CacheManagerContext) => {
7
+ const fieldsAndTypeNames = getChildFields(field, { fragmentDefinitions });
8
+
9
+ if (!fieldsAndTypeNames || fieldsAndTypeNames.length > 3) {
10
+ return false;
11
+ }
12
+
13
+ const fieldNames = fieldsAndTypeNames.map(({ fieldNode }) => getName(fieldNode) as FieldNode["name"]["value"]);
14
+
15
+ if (fieldNames.length === 2 && fieldNames.every(name => name === typeIDKey || name === TYPE_NAME_KEY)) {
16
+ deleteChildFields(
17
+ field,
18
+ fieldsAndTypeNames.map(({ fieldNode }) => fieldNode),
19
+ );
20
+
21
+ return true;
22
+ }
23
+
24
+ if ((fieldNames.length === 1 && fieldNames[0] === typeIDKey) || fieldNames[0] === TYPE_NAME_KEY) {
25
+ const { fieldNode } = fieldsAndTypeNames[0];
26
+ deleteChildFields(field, fieldNode);
27
+ return true;
28
+ }
29
+
30
+ return false;
31
+ };
@@ -0,0 +1,29 @@
1
+ import { deleteInlineFragments, getChildFields, getInlineFragments, getName } from "@graphql-box/helpers";
2
+ import { FieldNode, FragmentDefinitionNode } from "graphql";
3
+ import { CacheManagerContext } from "..";
4
+
5
+ export default (field: FieldNode | FragmentDefinitionNode, { fragmentDefinitions, typeIDKey }: CacheManagerContext) => {
6
+ const inlineFragments = getInlineFragments(field);
7
+ let filtered = false;
8
+
9
+ inlineFragments.forEach(fragment => {
10
+ const fieldsAndTypeNames = getChildFields(fragment, { fragmentDefinitions });
11
+
12
+ if (!fieldsAndTypeNames || !fieldsAndTypeNames.length) {
13
+ deleteInlineFragments(field, fragment);
14
+ filtered = true;
15
+ return;
16
+ }
17
+
18
+ if (fieldsAndTypeNames.length === 1) {
19
+ const { fieldNode } = fieldsAndTypeNames[0];
20
+
21
+ if (getName(fieldNode) === typeIDKey) {
22
+ deleteInlineFragments(field, fragment);
23
+ filtered = true;
24
+ }
25
+ }
26
+ });
27
+
28
+ return filtered;
29
+ };
@@ -0,0 +1,30 @@
1
+ import { PlainObjectMap } from "@graphql-box/core";
2
+ import { getName, resolveFragments } from "@graphql-box/helpers";
3
+ import { FieldNode, SelectionNode } from "graphql";
4
+ import { keys } from "lodash";
5
+ import { CacheManagerContext, KeysAndPaths } from "../defs";
6
+ import { buildFieldKeysAndPaths } from "./buildKeysAndPaths";
7
+
8
+ export default (
9
+ fieldData: PlainObjectMap,
10
+ selectionNodes: readonly SelectionNode[],
11
+ ancestorKeysAndPaths: KeysAndPaths,
12
+ context: CacheManagerContext,
13
+ ) => {
14
+ const fieldAndTypeName = resolveFragments(selectionNodes, context.fragmentDefinitions);
15
+
16
+ return keys(fieldData).reduce((acc: PlainObjectMap, key) => {
17
+ const match = fieldAndTypeName.find(({ fieldNode }) => (getName(fieldNode) as FieldNode["name"]["value"]) === key);
18
+
19
+ if (match) {
20
+ const { requestFieldPath } = buildFieldKeysAndPaths(match.fieldNode, ancestorKeysAndPaths, context);
21
+ const fieldTypeInfo = context.fieldTypeMap.get(requestFieldPath);
22
+
23
+ if (!fieldTypeInfo?.hasArguments && !fieldTypeInfo?.hasDirectives) {
24
+ acc[key] = fieldData[key];
25
+ }
26
+ }
27
+
28
+ return acc;
29
+ }, {});
30
+ };
@@ -0,0 +1,38 @@
1
+ import { RequestData } from "@graphql-box/core";
2
+ import { deleteChildFields, getChildFields, getOperationDefinitions } from "@graphql-box/helpers";
3
+ import { CacheManagerContext, CachedResponseData } from "../defs";
4
+ import { buildFieldKeysAndPaths } from "./buildKeysAndPaths";
5
+ import createFragmentSpreadChecklist from "./createFragmentSpreadChecklist";
6
+ import filterField from "./filterField";
7
+ import filterFragmentDefinitions from "./filterFragmentDefinitions";
8
+
9
+ export default ({ ast }: RequestData, { fieldPathChecklist }: CachedResponseData, context: CacheManagerContext) => {
10
+ const queryNode = getOperationDefinitions(ast, context.operation)[0];
11
+ const { fragmentDefinitions } = context;
12
+ const fieldsAndTypeNames = getChildFields(queryNode, { fragmentDefinitions });
13
+
14
+ if (!fieldsAndTypeNames) {
15
+ return ast;
16
+ }
17
+
18
+ const fragmentSpreadChecklist = createFragmentSpreadChecklist(ast);
19
+
20
+ for (let i = fieldsAndTypeNames.length - 1; i >= 0; i -= 1) {
21
+ const { fieldNode } = fieldsAndTypeNames[i];
22
+
23
+ const { requestFieldPath } = buildFieldKeysAndPaths(
24
+ fieldNode,
25
+ {
26
+ requestFieldPath: context.operation,
27
+ },
28
+ context,
29
+ );
30
+
31
+ if (filterField(fieldNode, fieldPathChecklist, fragmentSpreadChecklist, requestFieldPath, context)) {
32
+ deleteChildFields(queryNode, fieldNode);
33
+ }
34
+ }
35
+
36
+ context.queryFiltered = true;
37
+ return filterFragmentDefinitions(ast, fieldPathChecklist, fragmentSpreadChecklist, context);
38
+ };
@@ -0,0 +1,9 @@
1
+ import { RawResponseDataWithMaybeCacheMetadata } from "@graphql-box/core";
2
+ import { set } from "lodash";
3
+
4
+ export default ({ data, path, ...rest }: RawResponseDataWithMaybeCacheMetadata) => {
5
+ return {
6
+ ...rest,
7
+ data: set({}, path as (string | number)[], data),
8
+ };
9
+ };
@@ -0,0 +1,11 @@
1
+ import { FieldTypeInfo } from "@graphql-box/core";
2
+ import { isPlainObject } from "lodash";
3
+
4
+ export const getValidTypeIDValue = (
5
+ requestFieldPathData: any,
6
+ { typeIDValue }: FieldTypeInfo,
7
+ typeIDKey: string,
8
+ ): string | number | undefined => {
9
+ const requestFieldPathDataIDValue = isPlainObject(requestFieldPathData) ? requestFieldPathData[typeIDKey] : undefined;
10
+ return typeIDValue || requestFieldPathDataIDValue;
11
+ };