@constructive-io/graphql-codegen 2.23.3 → 2.24.1

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 (92) hide show
  1. package/README.md +147 -2
  2. package/cli/codegen/babel-ast.d.ts +53 -0
  3. package/cli/codegen/babel-ast.js +160 -0
  4. package/cli/codegen/barrel.d.ts +7 -2
  5. package/cli/codegen/barrel.js +193 -102
  6. package/cli/codegen/client.js +61 -0
  7. package/cli/codegen/custom-mutations.d.ts +2 -12
  8. package/cli/codegen/custom-mutations.js +116 -124
  9. package/cli/codegen/custom-queries.d.ts +2 -10
  10. package/cli/codegen/custom-queries.js +236 -335
  11. package/cli/codegen/gql-ast.js +22 -1
  12. package/cli/codegen/index.d.ts +3 -0
  13. package/cli/codegen/index.js +73 -3
  14. package/cli/codegen/invalidation.d.ts +20 -0
  15. package/cli/codegen/invalidation.js +327 -0
  16. package/cli/codegen/mutation-keys.d.ts +24 -0
  17. package/cli/codegen/mutation-keys.js +247 -0
  18. package/cli/codegen/mutations.d.ts +5 -19
  19. package/cli/codegen/mutations.js +385 -383
  20. package/cli/codegen/orm/barrel.d.ts +1 -1
  21. package/cli/codegen/orm/barrel.js +42 -10
  22. package/cli/codegen/orm/client-generator.d.ts +1 -19
  23. package/cli/codegen/orm/client-generator.js +108 -77
  24. package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  25. package/cli/codegen/orm/custom-ops-generator.js +192 -235
  26. package/cli/codegen/orm/input-types-generator.d.ts +13 -1
  27. package/cli/codegen/orm/input-types-generator.js +425 -147
  28. package/cli/codegen/orm/model-generator.d.ts +1 -19
  29. package/cli/codegen/orm/model-generator.js +229 -234
  30. package/cli/codegen/queries.d.ts +4 -12
  31. package/cli/codegen/queries.js +660 -390
  32. package/cli/codegen/query-keys.d.ts +15 -0
  33. package/cli/codegen/query-keys.js +477 -0
  34. package/cli/codegen/scalars.js +1 -0
  35. package/cli/codegen/schema-types-generator.d.ts +15 -10
  36. package/cli/codegen/schema-types-generator.js +87 -175
  37. package/cli/codegen/type-resolver.d.ts +1 -30
  38. package/cli/codegen/type-resolver.js +0 -53
  39. package/cli/codegen/types.d.ts +1 -1
  40. package/cli/codegen/types.js +76 -21
  41. package/cli/codegen/utils.d.ts +6 -0
  42. package/cli/codegen/utils.js +19 -0
  43. package/esm/cli/codegen/babel-ast.d.ts +53 -0
  44. package/esm/cli/codegen/babel-ast.js +111 -0
  45. package/esm/cli/codegen/barrel.d.ts +7 -2
  46. package/esm/cli/codegen/barrel.js +161 -103
  47. package/esm/cli/codegen/client.js +61 -0
  48. package/esm/cli/codegen/custom-mutations.d.ts +2 -12
  49. package/esm/cli/codegen/custom-mutations.js +83 -124
  50. package/esm/cli/codegen/custom-queries.d.ts +2 -10
  51. package/esm/cli/codegen/custom-queries.js +204 -336
  52. package/esm/cli/codegen/gql-ast.js +23 -2
  53. package/esm/cli/codegen/index.d.ts +3 -0
  54. package/esm/cli/codegen/index.js +69 -2
  55. package/esm/cli/codegen/invalidation.d.ts +20 -0
  56. package/esm/cli/codegen/invalidation.js +291 -0
  57. package/esm/cli/codegen/mutation-keys.d.ts +24 -0
  58. package/esm/cli/codegen/mutation-keys.js +211 -0
  59. package/esm/cli/codegen/mutations.d.ts +5 -19
  60. package/esm/cli/codegen/mutations.js +353 -384
  61. package/esm/cli/codegen/orm/barrel.d.ts +1 -1
  62. package/esm/cli/codegen/orm/barrel.js +10 -11
  63. package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
  64. package/esm/cli/codegen/orm/client-generator.js +76 -78
  65. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  66. package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
  67. package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
  68. package/esm/cli/codegen/orm/input-types-generator.js +393 -148
  69. package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
  70. package/esm/cli/codegen/orm/model-generator.js +197 -235
  71. package/esm/cli/codegen/queries.d.ts +4 -12
  72. package/esm/cli/codegen/queries.js +628 -391
  73. package/esm/cli/codegen/query-keys.d.ts +15 -0
  74. package/esm/cli/codegen/query-keys.js +441 -0
  75. package/esm/cli/codegen/scalars.js +1 -0
  76. package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
  77. package/esm/cli/codegen/schema-types-generator.js +54 -175
  78. package/esm/cli/codegen/type-resolver.d.ts +1 -30
  79. package/esm/cli/codegen/type-resolver.js +0 -49
  80. package/esm/cli/codegen/types.d.ts +1 -1
  81. package/esm/cli/codegen/types.js +44 -22
  82. package/esm/cli/codegen/utils.d.ts +6 -0
  83. package/esm/cli/codegen/utils.js +18 -0
  84. package/esm/types/config.d.ts +75 -0
  85. package/esm/types/config.js +18 -0
  86. package/package.json +6 -4
  87. package/types/config.d.ts +75 -0
  88. package/types/config.js +19 -1
  89. package/cli/codegen/ts-ast.d.ts +0 -124
  90. package/cli/codegen/ts-ast.js +0 -280
  91. package/esm/cli/codegen/ts-ast.d.ts +0 -124
  92. package/esm/cli/codegen/ts-ast.js +0 -260
package/README.md CHANGED
@@ -837,12 +837,12 @@ import { useCreateCarMutation, useCarsQuery } from './generated/hooks';
837
837
 
838
838
  function CreateCarWithInvalidation() {
839
839
  const queryClient = useQueryClient();
840
-
840
+
841
841
  const createCar = useCreateCarMutation({
842
842
  onSuccess: () => {
843
843
  // Invalidate all car queries to refetch
844
844
  queryClient.invalidateQueries({ queryKey: ['cars'] });
845
-
845
+
846
846
  // Or invalidate specific queries
847
847
  queryClient.invalidateQueries({ queryKey: ['cars', { first: 10 }] });
848
848
  },
@@ -852,6 +852,151 @@ function CreateCarWithInvalidation() {
852
852
  }
853
853
  ```
854
854
 
855
+ ### Centralized Query Keys
856
+
857
+ The codegen generates a centralized query key factory following the [lukemorales query-key-factory](https://tanstack.com/query/docs/framework/react/community/lukemorales-query-key-factory) pattern. This provides type-safe cache management with autocomplete support.
858
+
859
+ #### Generated Files
860
+
861
+ | File | Purpose |
862
+ |------|---------|
863
+ | `query-keys.ts` | Query key factories for all entities |
864
+ | `mutation-keys.ts` | Mutation key factories for tracking in-flight mutations |
865
+ | `invalidation.ts` | Type-safe cache invalidation helpers |
866
+
867
+ #### Using Query Keys
868
+
869
+ ```tsx
870
+ import { userKeys, invalidate } from './generated/hooks';
871
+ import { useQueryClient } from '@tanstack/react-query';
872
+
873
+ // Query key structure
874
+ userKeys.all // ['user']
875
+ userKeys.lists() // ['user', 'list']
876
+ userKeys.list({ first: 10 }) // ['user', 'list', { first: 10 }]
877
+ userKeys.details() // ['user', 'detail']
878
+ userKeys.detail('user-123') // ['user', 'detail', 'user-123']
879
+
880
+ // Granular cache invalidation
881
+ const queryClient = useQueryClient();
882
+
883
+ // Invalidate ALL user queries
884
+ queryClient.invalidateQueries({ queryKey: userKeys.all });
885
+
886
+ // Invalidate only list queries
887
+ queryClient.invalidateQueries({ queryKey: userKeys.lists() });
888
+
889
+ // Invalidate a specific user
890
+ queryClient.invalidateQueries({ queryKey: userKeys.detail(userId) });
891
+ ```
892
+
893
+ #### Invalidation Helpers
894
+
895
+ Type-safe invalidation utilities:
896
+
897
+ ```tsx
898
+ import { invalidate, remove } from './generated/hooks';
899
+
900
+ // Invalidate queries (triggers refetch)
901
+ invalidate.user.all(queryClient);
902
+ invalidate.user.lists(queryClient);
903
+ invalidate.user.detail(queryClient, userId);
904
+
905
+ // Remove from cache (for delete operations)
906
+ remove.user(queryClient, userId);
907
+ ```
908
+
909
+ #### Mutation Key Tracking
910
+
911
+ Track in-flight mutations with `useIsMutating`:
912
+
913
+ ```tsx
914
+ import { useIsMutating } from '@tanstack/react-query';
915
+ import { userMutationKeys } from './generated/hooks';
916
+
917
+ function UserList() {
918
+ // Check if any user mutations are in progress
919
+ const isMutating = useIsMutating({ mutationKey: userMutationKeys.all });
920
+
921
+ // Check if a specific user is being deleted
922
+ const isDeleting = useIsMutating({
923
+ mutationKey: userMutationKeys.delete(userId)
924
+ });
925
+
926
+ return (
927
+ <div>
928
+ {isMutating > 0 && <Spinner />}
929
+ <button disabled={isDeleting > 0}>Delete</button>
930
+ </div>
931
+ );
932
+ }
933
+ ```
934
+
935
+ #### Optimistic Updates with Query Keys
936
+
937
+ ```tsx
938
+ import { useCreateUserMutation, userKeys } from './generated/hooks';
939
+
940
+ const createUser = useCreateUserMutation({
941
+ onMutate: async (newUser) => {
942
+ // Cancel outgoing refetches
943
+ await queryClient.cancelQueries({ queryKey: userKeys.lists() });
944
+
945
+ // Snapshot previous value
946
+ const previous = queryClient.getQueryData(userKeys.list());
947
+
948
+ // Optimistically update cache
949
+ queryClient.setQueryData(userKeys.list(), (old) => ({
950
+ ...old,
951
+ users: {
952
+ ...old.users,
953
+ nodes: [...old.users.nodes, { id: 'temp', ...newUser.input.user }]
954
+ },
955
+ }));
956
+
957
+ return { previous };
958
+ },
959
+ onError: (err, variables, context) => {
960
+ // Rollback on error
961
+ queryClient.setQueryData(userKeys.list(), context.previous);
962
+ },
963
+ onSettled: () => {
964
+ // Refetch after mutation
965
+ queryClient.invalidateQueries({ queryKey: userKeys.lists() });
966
+ },
967
+ });
968
+ ```
969
+
970
+ #### Configuration
971
+
972
+ Query key generation is enabled by default. Configure in your config file:
973
+
974
+ ```typescript
975
+ // graphql-sdk.config.ts
976
+ export default defineConfig({
977
+ endpoint: 'https://api.example.com/graphql',
978
+
979
+ queryKeys: {
980
+ // Generate scope-aware keys (default: true)
981
+ generateScopedKeys: true,
982
+
983
+ // Generate mutation keys (default: true)
984
+ generateMutationKeys: true,
985
+
986
+ // Generate invalidation helpers (default: true)
987
+ generateCascadeHelpers: true,
988
+
989
+ // Define entity relationships for cascade invalidation
990
+ relationships: {
991
+ table: { parent: 'database', foreignKey: 'databaseId' },
992
+ field: { parent: 'table', foreignKey: 'tableId' },
993
+ },
994
+ },
995
+ });
996
+ ```
997
+
998
+ For detailed documentation on query key factory design and implementation, see [docs/QUERY-KEY-FACTORY.md](./docs/QUERY-KEY-FACTORY.md).
999
+
855
1000
  ### Prefetching
856
1001
 
857
1002
  ```tsx
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Babel AST utilities for code generation
3
+ *
4
+ * Provides minimal helper functions for building TypeScript AST nodes.
5
+ * Use raw t.* calls for most operations - only helpers that provide
6
+ * real value beyond simple wrapping are included here.
7
+ */
8
+ import generate from '@babel/generator';
9
+ import * as t from '@babel/types';
10
+ export { t, generate };
11
+ /**
12
+ * Generate code from an array of statements
13
+ */
14
+ export declare function generateCode(statements: t.Statement[]): string;
15
+ /**
16
+ * Create a block comment
17
+ */
18
+ export declare const commentBlock: (value: string) => t.CommentBlock;
19
+ /**
20
+ * Create a line comment
21
+ */
22
+ export declare const commentLine: (value: string) => t.CommentLine;
23
+ /**
24
+ * Add a leading JSDoc comment to a node
25
+ */
26
+ export declare function addJSDocComment<T extends t.Node>(node: T, lines: string[]): T;
27
+ /**
28
+ * Add a leading single-line comment to a node
29
+ */
30
+ export declare function addLineComment<T extends t.Node>(node: T, text: string): T;
31
+ /**
32
+ * Create an 'as const' assertion - common pattern worth abstracting
33
+ */
34
+ export declare function asConst(expression: t.Expression): t.TSAsExpression;
35
+ /**
36
+ * Create an array expression with 'as const' - very common pattern
37
+ */
38
+ export declare function constArray(elements: (t.Expression | t.SpreadElement)[]): t.TSAsExpression;
39
+ /**
40
+ * Create a typed parameter - saves boilerplate for type annotations
41
+ */
42
+ export declare function typedParam(name: string, typeAnnotation: t.TSType, optional?: boolean): t.Identifier;
43
+ /**
44
+ * Create keyof typeof expression - complex nested type operators
45
+ */
46
+ export declare function keyofTypeof(name: string): t.TSTypeOperator;
47
+ /**
48
+ * Create a call expression with TypeScript type parameters
49
+ *
50
+ * This is used to generate typed function calls like:
51
+ * execute<ResultType, VariablesType>(document, variables)
52
+ */
53
+ export declare function createTypedCallExpression(callee: t.Expression, args: (t.Expression | t.SpreadElement)[], typeParams: t.TSType[]): t.CallExpression;
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.commentLine = exports.commentBlock = exports.generate = exports.t = void 0;
40
+ exports.generateCode = generateCode;
41
+ exports.addJSDocComment = addJSDocComment;
42
+ exports.addLineComment = addLineComment;
43
+ exports.asConst = asConst;
44
+ exports.constArray = constArray;
45
+ exports.typedParam = typedParam;
46
+ exports.keyofTypeof = keyofTypeof;
47
+ exports.createTypedCallExpression = createTypedCallExpression;
48
+ /**
49
+ * Babel AST utilities for code generation
50
+ *
51
+ * Provides minimal helper functions for building TypeScript AST nodes.
52
+ * Use raw t.* calls for most operations - only helpers that provide
53
+ * real value beyond simple wrapping are included here.
54
+ */
55
+ const generator_1 = __importDefault(require("@babel/generator"));
56
+ exports.generate = generator_1.default;
57
+ const t = __importStar(require("@babel/types"));
58
+ exports.t = t;
59
+ /**
60
+ * Generate code from an array of statements
61
+ */
62
+ function generateCode(statements) {
63
+ const program = t.program(statements);
64
+ // @ts-ignore - Babel types mismatch
65
+ return (0, generator_1.default)(program).code;
66
+ }
67
+ /**
68
+ * Create a block comment
69
+ */
70
+ const commentBlock = (value) => {
71
+ return {
72
+ type: 'CommentBlock',
73
+ value,
74
+ start: null,
75
+ end: null,
76
+ loc: null,
77
+ };
78
+ };
79
+ exports.commentBlock = commentBlock;
80
+ /**
81
+ * Create a line comment
82
+ */
83
+ const commentLine = (value) => {
84
+ return {
85
+ type: 'CommentLine',
86
+ value,
87
+ start: null,
88
+ end: null,
89
+ loc: null,
90
+ };
91
+ };
92
+ exports.commentLine = commentLine;
93
+ /**
94
+ * Add a leading JSDoc comment to a node
95
+ */
96
+ function addJSDocComment(node, lines) {
97
+ const commentText = lines.length === 1
98
+ ? `* ${lines[0]} `
99
+ : `*\n${lines.map(line => ` * ${line}`).join('\n')}\n `;
100
+ if (!node.leadingComments) {
101
+ node.leadingComments = [];
102
+ }
103
+ node.leadingComments.push((0, exports.commentBlock)(commentText));
104
+ return node;
105
+ }
106
+ /**
107
+ * Add a leading single-line comment to a node
108
+ */
109
+ function addLineComment(node, text) {
110
+ if (!node.leadingComments) {
111
+ node.leadingComments = [];
112
+ }
113
+ node.leadingComments.push((0, exports.commentLine)(` ${text}`));
114
+ return node;
115
+ }
116
+ /**
117
+ * Create an 'as const' assertion - common pattern worth abstracting
118
+ */
119
+ function asConst(expression) {
120
+ return t.tsAsExpression(expression, t.tsTypeReference(t.identifier('const')));
121
+ }
122
+ /**
123
+ * Create an array expression with 'as const' - very common pattern
124
+ */
125
+ function constArray(elements) {
126
+ return asConst(t.arrayExpression(elements));
127
+ }
128
+ /**
129
+ * Create a typed parameter - saves boilerplate for type annotations
130
+ */
131
+ function typedParam(name, typeAnnotation, optional = false) {
132
+ const param = t.identifier(name);
133
+ param.typeAnnotation = t.tsTypeAnnotation(typeAnnotation);
134
+ param.optional = optional;
135
+ return param;
136
+ }
137
+ /**
138
+ * Create keyof typeof expression - complex nested type operators
139
+ */
140
+ function keyofTypeof(name) {
141
+ const typeofOp = t.tsTypeOperator(t.tsTypeReference(t.identifier(name)));
142
+ typeofOp.operator = 'typeof';
143
+ const keyofOp = t.tsTypeOperator(typeofOp);
144
+ keyofOp.operator = 'keyof';
145
+ return keyofOp;
146
+ }
147
+ /**
148
+ * Create a call expression with TypeScript type parameters
149
+ *
150
+ * This is used to generate typed function calls like:
151
+ * execute<ResultType, VariablesType>(document, variables)
152
+ */
153
+ function createTypedCallExpression(callee, args, typeParams) {
154
+ const call = t.callExpression(callee, args);
155
+ if (typeParams.length > 0) {
156
+ // @ts-ignore - Babel types support typeParameters on CallExpression for TS
157
+ call.typeParameters = t.tsTypeParameterInstantiation(typeParams);
158
+ }
159
+ return call;
160
+ }
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * Barrel file generators - creates index.ts files for exports
3
3
  *
4
- * Using simple string generation for barrel files since they're straightforward
5
- * and ts-morph has issues with insertText + addStatements combination.
4
+ * Using Babel AST for generating barrel (index.ts) files with re-exports.
6
5
  */
7
6
  import type { CleanTable } from '../../types/schema';
8
7
  /**
@@ -22,6 +21,12 @@ export declare function generateMutationsBarrel(tables: CleanTable[]): string;
22
21
  export interface MainBarrelOptions {
23
22
  hasSchemaTypes?: boolean;
24
23
  hasMutations?: boolean;
24
+ /** Whether query-keys.ts was generated */
25
+ hasQueryKeys?: boolean;
26
+ /** Whether mutation-keys.ts was generated */
27
+ hasMutationKeys?: boolean;
28
+ /** Whether invalidation.ts was generated */
29
+ hasInvalidation?: boolean;
25
30
  }
26
31
  export declare function generateMainBarrel(tables: CleanTable[], options?: MainBarrelOptions | boolean): string;
27
32
  /**