@aws-amplify/api-graphql 4.0.29-unstable.f37faeb.0 → 4.0.29

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 (129) hide show
  1. package/dist/cjs/internals/generateClient.js +4 -14
  2. package/dist/cjs/internals/generateClient.js.map +1 -1
  3. package/dist/cjs/internals/server/generateClientWithAmplifyInstance.js +3 -8
  4. package/dist/cjs/internals/server/generateClientWithAmplifyInstance.js.map +1 -1
  5. package/dist/cjs/internals/v6.js +6 -3
  6. package/dist/cjs/internals/v6.js.map +1 -1
  7. package/dist/cjs/types/index.js +11 -1
  8. package/dist/cjs/types/index.js.map +1 -1
  9. package/dist/cjs/utils/index.js +1 -5
  10. package/dist/cjs/utils/index.js.map +1 -1
  11. package/dist/esm/GraphQLAPI.d.ts +1 -1
  12. package/dist/esm/Providers/AWSAppSyncRealTimeProvider/index.d.ts +1 -1
  13. package/dist/esm/index.mjs +1 -1
  14. package/dist/esm/internals/InternalGraphQLAPI.d.ts +1 -1
  15. package/dist/esm/internals/generateClient.mjs +5 -15
  16. package/dist/esm/internals/generateClient.mjs.map +1 -1
  17. package/dist/esm/internals/server/generateClientWithAmplifyInstance.mjs +4 -9
  18. package/dist/esm/internals/server/generateClientWithAmplifyInstance.mjs.map +1 -1
  19. package/dist/esm/internals/types.d.ts +1 -1
  20. package/dist/esm/internals/v6.d.ts +1 -1
  21. package/dist/esm/internals/v6.mjs +7 -4
  22. package/dist/esm/internals/v6.mjs.map +1 -1
  23. package/dist/esm/types/index.d.ts +10 -40
  24. package/dist/esm/types/index.mjs +10 -1
  25. package/dist/esm/types/index.mjs.map +1 -1
  26. package/dist/esm/utils/index.d.ts +0 -2
  27. package/dist/esm/utils/index.mjs +0 -2
  28. package/dist/esm/utils/index.mjs.map +1 -1
  29. package/package.json +5 -6
  30. package/src/GraphQLAPI.ts +1 -1
  31. package/src/Providers/AWSAppSyncRealTimeProvider/index.ts +4 -1
  32. package/src/internals/InternalGraphQLAPI.ts +4 -1
  33. package/src/internals/generateClient.ts +8 -36
  34. package/src/internals/server/generateClientWithAmplifyInstance.ts +6 -16
  35. package/src/internals/types.ts +1 -1
  36. package/src/internals/v6.ts +7 -7
  37. package/src/server/generateClient.ts +1 -1
  38. package/src/types/index.ts +36 -60
  39. package/src/utils/index.ts +0 -2
  40. package/dist/cjs/internals/APIClient.js +0 -733
  41. package/dist/cjs/internals/APIClient.js.map +0 -1
  42. package/dist/cjs/internals/clientUtils.js +0 -29
  43. package/dist/cjs/internals/clientUtils.js.map +0 -1
  44. package/dist/cjs/internals/generateCustomOperationsProperty.js +0 -50
  45. package/dist/cjs/internals/generateCustomOperationsProperty.js.map +0 -1
  46. package/dist/cjs/internals/operations/custom.js +0 -356
  47. package/dist/cjs/internals/operations/custom.js.map +0 -1
  48. package/dist/cjs/internals/operations/get.js +0 -62
  49. package/dist/cjs/internals/operations/get.js.map +0 -1
  50. package/dist/cjs/internals/operations/indexQuery.js +0 -75
  51. package/dist/cjs/internals/operations/indexQuery.js.map +0 -1
  52. package/dist/cjs/internals/operations/list.js +0 -74
  53. package/dist/cjs/internals/operations/list.js.map +0 -1
  54. package/dist/cjs/internals/operations/observeQuery.js +0 -121
  55. package/dist/cjs/internals/operations/observeQuery.js.map +0 -1
  56. package/dist/cjs/internals/operations/subscription.js +0 -31
  57. package/dist/cjs/internals/operations/subscription.js.map +0 -1
  58. package/dist/cjs/internals/server/generateModelsProperty.js +0 -53
  59. package/dist/cjs/internals/server/generateModelsProperty.js.map +0 -1
  60. package/dist/cjs/internals/utils/clientProperties/generateEnumsProperty.js +0 -21
  61. package/dist/cjs/internals/utils/clientProperties/generateEnumsProperty.js.map +0 -1
  62. package/dist/cjs/internals/utils/clientProperties/generateModelsProperty.js +0 -45
  63. package/dist/cjs/internals/utils/clientProperties/generateModelsProperty.js.map +0 -1
  64. package/dist/cjs/utils/findIndexByFields.js +0 -25
  65. package/dist/cjs/utils/findIndexByFields.js.map +0 -1
  66. package/dist/cjs/utils/resolveOwnerFields.js +0 -48
  67. package/dist/cjs/utils/resolveOwnerFields.js.map +0 -1
  68. package/dist/cjs/utils/resolvePKFields.js +0 -17
  69. package/dist/cjs/utils/resolvePKFields.js.map +0 -1
  70. package/dist/esm/internals/APIClient.d.ts +0 -126
  71. package/dist/esm/internals/APIClient.mjs +0 -721
  72. package/dist/esm/internals/APIClient.mjs.map +0 -1
  73. package/dist/esm/internals/clientUtils.d.ts +0 -6
  74. package/dist/esm/internals/clientUtils.mjs +0 -26
  75. package/dist/esm/internals/clientUtils.mjs.map +0 -1
  76. package/dist/esm/internals/generateCustomOperationsProperty.d.ts +0 -9
  77. package/dist/esm/internals/generateCustomOperationsProperty.mjs +0 -45
  78. package/dist/esm/internals/generateCustomOperationsProperty.mjs.map +0 -1
  79. package/dist/esm/internals/operations/custom.d.ts +0 -63
  80. package/dist/esm/internals/operations/custom.mjs +0 -354
  81. package/dist/esm/internals/operations/custom.mjs.map +0 -1
  82. package/dist/esm/internals/operations/get.d.ts +0 -5
  83. package/dist/esm/internals/operations/get.mjs +0 -60
  84. package/dist/esm/internals/operations/get.mjs.map +0 -1
  85. package/dist/esm/internals/operations/indexQuery.d.ts +0 -9
  86. package/dist/esm/internals/operations/indexQuery.mjs +0 -73
  87. package/dist/esm/internals/operations/indexQuery.mjs.map +0 -1
  88. package/dist/esm/internals/operations/list.d.ts +0 -4
  89. package/dist/esm/internals/operations/list.mjs +0 -72
  90. package/dist/esm/internals/operations/list.mjs.map +0 -1
  91. package/dist/esm/internals/operations/observeQuery.d.ts +0 -3
  92. package/dist/esm/internals/operations/observeQuery.mjs +0 -121
  93. package/dist/esm/internals/operations/observeQuery.mjs.map +0 -1
  94. package/dist/esm/internals/operations/subscription.d.ts +0 -3
  95. package/dist/esm/internals/operations/subscription.mjs +0 -29
  96. package/dist/esm/internals/operations/subscription.mjs.map +0 -1
  97. package/dist/esm/internals/server/generateModelsProperty.d.ts +0 -3
  98. package/dist/esm/internals/server/generateModelsProperty.mjs +0 -51
  99. package/dist/esm/internals/server/generateModelsProperty.mjs.map +0 -1
  100. package/dist/esm/internals/utils/clientProperties/generateEnumsProperty.d.ts +0 -3
  101. package/dist/esm/internals/utils/clientProperties/generateEnumsProperty.mjs +0 -18
  102. package/dist/esm/internals/utils/clientProperties/generateEnumsProperty.mjs.map +0 -1
  103. package/dist/esm/internals/utils/clientProperties/generateModelsProperty.d.ts +0 -4
  104. package/dist/esm/internals/utils/clientProperties/generateModelsProperty.mjs +0 -43
  105. package/dist/esm/internals/utils/clientProperties/generateModelsProperty.mjs.map +0 -1
  106. package/dist/esm/utils/findIndexByFields.d.ts +0 -9
  107. package/dist/esm/utils/findIndexByFields.mjs +0 -22
  108. package/dist/esm/utils/findIndexByFields.mjs.map +0 -1
  109. package/dist/esm/utils/resolveOwnerFields.d.ts +0 -12
  110. package/dist/esm/utils/resolveOwnerFields.mjs +0 -45
  111. package/dist/esm/utils/resolveOwnerFields.mjs.map +0 -1
  112. package/dist/esm/utils/resolvePKFields.d.ts +0 -13
  113. package/dist/esm/utils/resolvePKFields.mjs +0 -14
  114. package/dist/esm/utils/resolvePKFields.mjs.map +0 -1
  115. package/src/internals/APIClient.ts +0 -1076
  116. package/src/internals/clientUtils.ts +0 -37
  117. package/src/internals/generateCustomOperationsProperty.ts +0 -112
  118. package/src/internals/operations/custom.ts +0 -492
  119. package/src/internals/operations/get.ts +0 -140
  120. package/src/internals/operations/indexQuery.ts +0 -170
  121. package/src/internals/operations/list.ts +0 -135
  122. package/src/internals/operations/observeQuery.ts +0 -146
  123. package/src/internals/operations/subscription.ts +0 -75
  124. package/src/internals/server/generateModelsProperty.ts +0 -97
  125. package/src/internals/utils/clientProperties/generateEnumsProperty.ts +0 -34
  126. package/src/internals/utils/clientProperties/generateModelsProperty.ts +0 -81
  127. package/src/utils/findIndexByFields.ts +0 -31
  128. package/src/utils/resolveOwnerFields.ts +0 -77
  129. package/src/utils/resolvePKFields.ts +0 -23
@@ -1,1076 +0,0 @@
1
- // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- // SPDX-License-Identifier: Apache-2.0
3
- import {
4
- AssociationBelongsTo,
5
- AssociationHasOne,
6
- GraphQLAuthMode,
7
- ModelFieldType,
8
- ModelIntrospectionSchema,
9
- NonModelFieldType,
10
- SchemaModel,
11
- SchemaNonModel,
12
- } from '@aws-amplify/core/internals/utils';
13
- import { AmplifyServer } from '@aws-amplify/core/internals/adapter-core';
14
- import { CustomHeaders } from '@aws-amplify/data-schema-types';
15
-
16
- import {
17
- AuthModeParams,
18
- ClientWithModels,
19
- ListArgs,
20
- QueryArgs,
21
- V6Client,
22
- __authMode,
23
- __authToken,
24
- __headers,
25
- } from '../types';
26
- import { resolveOwnerFields } from '../utils/resolveOwnerFields';
27
-
28
- import type { IndexMeta } from './operations/indexQuery';
29
-
30
- interface LazyLoadOptions {
31
- authMode?: GraphQLAuthMode;
32
- authToken?: string | undefined;
33
- limit?: number | undefined;
34
- nextToken?: string | undefined | null;
35
- headers?: CustomHeaders | undefined;
36
- }
37
-
38
- const connectionType = {
39
- HAS_ONE: 'HAS_ONE',
40
- HAS_MANY: 'HAS_MANY',
41
- BELONGS_TO: 'BELONGS_TO',
42
- };
43
-
44
- /**
45
- *
46
- * @param GraphQL response object
47
- * @returns response object with `items` properties flattened
48
- */
49
- export const flattenItems = (obj: Record<string, any>): Record<string, any> => {
50
- const res: Record<string, any> = {};
51
-
52
- Object.entries(obj).forEach(([prop, value]) => {
53
- if (typeof value === 'object' && !Array.isArray(value) && value !== null) {
54
- if (value.items !== undefined) {
55
- res[prop] = value.items.map((item: Record<string, any>) =>
56
- flattenItems(item),
57
- );
58
-
59
- return;
60
- }
61
- res[prop] = flattenItems(value);
62
-
63
- return;
64
- }
65
-
66
- res[prop] = value;
67
- });
68
-
69
- return res;
70
- };
71
-
72
- // TODO: this should accept single result to support CRUD methods; create helper for array/list
73
- export function initializeModel(
74
- client: ClientWithModels,
75
- modelName: string,
76
- result: any[],
77
- modelIntrospection: ModelIntrospectionSchema,
78
- authMode: GraphQLAuthMode | undefined,
79
- authToken: string | undefined,
80
- context = false,
81
- ): any[] {
82
- const introModel = modelIntrospection.models[modelName];
83
- const introModelFields = introModel.fields;
84
-
85
- const modelFields: string[] = Object.entries(introModelFields)
86
- .filter(([_, field]: [string, any]) => field?.type?.model !== undefined)
87
- .map(([fieldName]) => fieldName);
88
-
89
- return result.map(record => {
90
- const initializedRelationalFields: Record<string, any> = {};
91
-
92
- for (const fieldName of modelFields) {
93
- const modelField = introModelFields[fieldName];
94
- const modelFieldType = modelField?.type as ModelFieldType;
95
-
96
- const relatedModelName = modelFieldType.model;
97
- const relatedModel = modelIntrospection.models[relatedModelName!];
98
-
99
- const relatedModelPKFieldName =
100
- relatedModel.primaryKeyInfo.primaryKeyFieldName;
101
-
102
- const relatedModelSKFieldNames =
103
- relatedModel.primaryKeyInfo.sortKeyFieldNames;
104
-
105
- const relationType = modelField.association?.connectionType;
106
-
107
- let connectionFields: string[] = [];
108
- if (
109
- modelField.association &&
110
- 'associatedWith' in modelField.association
111
- ) {
112
- connectionFields = modelField.association.associatedWith;
113
- }
114
-
115
- const targetNames: string[] = [];
116
- if (modelField.association && 'targetNames' in modelField.association) {
117
- targetNames.push(...modelField.association.targetNames);
118
- }
119
-
120
- switch (relationType) {
121
- case connectionType.HAS_ONE:
122
- case connectionType.BELONGS_TO: {
123
- const sortKeyValues = relatedModelSKFieldNames.reduce(
124
- // TODO(Eslint): is this implementation correct?
125
- // eslint-disable-next-line array-callback-return
126
- (acc: Record<string, any>, curVal) => {
127
- if (record[curVal]) {
128
- return (acc[curVal] = record[curVal]);
129
- }
130
- },
131
- {},
132
- );
133
-
134
- if (context) {
135
- initializedRelationalFields[fieldName] = (
136
- contextSpec: AmplifyServer.ContextSpec,
137
- options?: LazyLoadOptions,
138
- ) => {
139
- if (record[targetNames[0]]) {
140
- return (client as any).models[relatedModelName].get(
141
- contextSpec,
142
- {
143
- [relatedModelPKFieldName]: record[targetNames[0]],
144
- ...sortKeyValues,
145
- },
146
- {
147
- authMode: options?.authMode || authMode,
148
- authToken: options?.authToken || authToken,
149
- },
150
- );
151
- }
152
-
153
- return undefined;
154
- };
155
- } else {
156
- initializedRelationalFields[fieldName] = (
157
- options?: LazyLoadOptions,
158
- ) => {
159
- if (record[targetNames[0]]) {
160
- return (client as any).models[relatedModelName].get(
161
- {
162
- [relatedModelPKFieldName]: record[targetNames[0]],
163
- ...sortKeyValues,
164
- },
165
- {
166
- authMode: options?.authMode || authMode,
167
- authToken: options?.authToken || authToken,
168
- },
169
- );
170
- }
171
-
172
- return undefined;
173
- };
174
- }
175
-
176
- break;
177
- }
178
- case connectionType.HAS_MANY: {
179
- const parentPk = introModel.primaryKeyInfo.primaryKeyFieldName;
180
- const parentSK = introModel.primaryKeyInfo.sortKeyFieldNames;
181
-
182
- // M:N check - TODO: refactor
183
- const relatedModelField = relatedModel.fields[connectionFields[0]];
184
- const relatedModelFieldType =
185
- relatedModelField.type as ModelFieldType;
186
- if (relatedModelFieldType.model) {
187
- let relatedTargetNames: string[] = [];
188
- if (
189
- relatedModelField.association &&
190
- 'targetNames' in relatedModelField.association
191
- ) {
192
- relatedTargetNames = relatedModelField.association?.targetNames;
193
- }
194
-
195
- const hasManyFilter: Record<string, any> = relatedTargetNames.map(
196
- (field, idx) => {
197
- if (idx === 0) {
198
- return { [field]: { eq: record[parentPk] } };
199
- }
200
-
201
- return { [field]: { eq: record[parentSK[idx - 1]] } };
202
- },
203
- );
204
-
205
- if (context) {
206
- initializedRelationalFields[fieldName] = (
207
- contextSpec: AmplifyServer.ContextSpec,
208
- options?: LazyLoadOptions,
209
- ) => {
210
- if (record[parentPk]) {
211
- return (client as any).models[relatedModelName].list(
212
- contextSpec,
213
- {
214
- filter: { and: hasManyFilter },
215
- limit: options?.limit,
216
- nextToken: options?.nextToken,
217
- authMode: options?.authMode || authMode,
218
- authToken: options?.authToken || authToken,
219
- },
220
- );
221
- }
222
-
223
- return [];
224
- };
225
- } else {
226
- initializedRelationalFields[fieldName] = (
227
- options?: LazyLoadOptions,
228
- ) => {
229
- if (record[parentPk]) {
230
- return (client as any).models[relatedModelName].list({
231
- filter: { and: hasManyFilter },
232
- limit: options?.limit,
233
- nextToken: options?.nextToken,
234
- authMode: options?.authMode || authMode,
235
- authToken: options?.authToken || authToken,
236
- });
237
- }
238
-
239
- return [];
240
- };
241
- }
242
-
243
- break;
244
- }
245
-
246
- const hasManyFilter: Record<string, any> = connectionFields.map(
247
- (field, idx) => {
248
- if (idx === 0) {
249
- return { [field]: { eq: record[parentPk] } };
250
- }
251
-
252
- return { [field]: { eq: record[parentSK[idx - 1]] } };
253
- },
254
- );
255
-
256
- if (context) {
257
- initializedRelationalFields[fieldName] = (
258
- contextSpec: AmplifyServer.ContextSpec,
259
- options?: LazyLoadOptions,
260
- ) => {
261
- if (record[parentPk]) {
262
- return (client as any).models[relatedModelName].list(
263
- contextSpec,
264
- {
265
- filter: { and: hasManyFilter },
266
- limit: options?.limit,
267
- nextToken: options?.nextToken,
268
- authMode: options?.authMode || authMode,
269
- authToken: options?.authToken || authToken,
270
- },
271
- );
272
- }
273
-
274
- return [];
275
- };
276
- } else {
277
- initializedRelationalFields[fieldName] = (
278
- options?: LazyLoadOptions,
279
- ) => {
280
- if (record[parentPk]) {
281
- return (client as any).models[relatedModelName].list({
282
- filter: { and: hasManyFilter },
283
- limit: options?.limit,
284
- nextToken: options?.nextToken,
285
- authMode: options?.authMode || authMode,
286
- authToken: options?.authToken || authToken,
287
- });
288
- }
289
-
290
- return [];
291
- };
292
- }
293
-
294
- break;
295
- }
296
- default:
297
- break;
298
- }
299
- }
300
-
301
- return { ...record, ...initializedRelationalFields };
302
- });
303
- }
304
-
305
- export const graphQLOperationsInfo = {
306
- CREATE: { operationPrefix: 'create', usePlural: false },
307
- READ: { operationPrefix: 'get', usePlural: false },
308
- UPDATE: { operationPrefix: 'update', usePlural: false },
309
- DELETE: { operationPrefix: 'delete', usePlural: false },
310
- LIST: { operationPrefix: 'list', usePlural: true },
311
- INDEX_QUERY: { operationPrefix: '', usePlural: false },
312
- ONCREATE: { operationPrefix: 'onCreate', usePlural: false },
313
- ONUPDATE: { operationPrefix: 'onUpdate', usePlural: false },
314
- ONDELETE: { operationPrefix: 'onDelete', usePlural: false },
315
- OBSERVE_QUERY: { operationPrefix: 'observeQuery', usePlural: false },
316
- } as const;
317
- export type ModelOperation = keyof typeof graphQLOperationsInfo;
318
-
319
- const SELECTION_SET_WILDCARD = '*';
320
-
321
- export const getDefaultSelectionSetForNonModelWithIR = (
322
- nonModelDefinition: SchemaNonModel,
323
- modelIntrospection: ModelIntrospectionSchema,
324
- ): Record<string, unknown> => {
325
- const { fields } = nonModelDefinition;
326
- const mappedFields = Object.values(fields)
327
- .map(({ type, name }) => {
328
- if (typeof (type as { enum: string }).enum === 'string') {
329
- return [name, FIELD_IR];
330
- }
331
-
332
- if (typeof (type as NonModelFieldType).nonModel === 'string') {
333
- return [
334
- name,
335
- getDefaultSelectionSetForNonModelWithIR(
336
- modelIntrospection.nonModels[(type as NonModelFieldType).nonModel],
337
- modelIntrospection,
338
- ),
339
- ];
340
- }
341
-
342
- if (typeof type === 'string') {
343
- return [name, FIELD_IR];
344
- }
345
-
346
- return undefined;
347
- })
348
- .filter(
349
- (
350
- pair: (string | Record<string, unknown>)[] | undefined,
351
- ): pair is (string | Record<string, unknown>)[] => pair !== undefined,
352
- );
353
-
354
- return Object.fromEntries(mappedFields);
355
- };
356
-
357
- const getDefaultSelectionSetForModelWithIR = (
358
- modelDefinition: SchemaModel,
359
- modelIntrospection: ModelIntrospectionSchema,
360
- ): Record<string, unknown> => {
361
- const { fields } = modelDefinition;
362
- const mappedFields = Object.values(fields)
363
- .map(({ type, name }) => {
364
- if (
365
- typeof (type as { enum: string }).enum === 'string' ||
366
- typeof type === 'string'
367
- ) {
368
- return [name, FIELD_IR];
369
- }
370
-
371
- if (typeof (type as NonModelFieldType).nonModel === 'string') {
372
- return [
373
- name,
374
- getDefaultSelectionSetForNonModelWithIR(
375
- modelIntrospection.nonModels[(type as NonModelFieldType).nonModel],
376
- modelIntrospection,
377
- ),
378
- ];
379
- }
380
-
381
- return undefined;
382
- })
383
- .filter(
384
- (
385
- pair: (string | Record<string, unknown>)[] | undefined,
386
- ): pair is (string | Record<string, unknown>)[] => pair !== undefined,
387
- );
388
-
389
- const ownerFields = resolveOwnerFields(modelDefinition).map(field => [
390
- field,
391
- FIELD_IR,
392
- ]);
393
-
394
- return Object.fromEntries(mappedFields.concat(ownerFields));
395
- };
396
-
397
- function defaultSelectionSetForModel(modelDefinition: SchemaModel): string[] {
398
- // fields that are explicitly part of the graphql schema; not
399
- // inferred from owner auth rules.
400
- const { fields } = modelDefinition;
401
- const explicitFields = Object.values<any>(fields)
402
- // Default selection set omits model fields
403
- .map(({ type, name }) => {
404
- if (typeof type === 'string') return name;
405
-
406
- if (typeof type === 'object') {
407
- if (typeof type?.enum === 'string') {
408
- return name;
409
- } else if (typeof type?.nonModel === 'string') {
410
- return `${name}.${SELECTION_SET_WILDCARD}`;
411
- }
412
- }
413
-
414
- return undefined;
415
- })
416
- .filter(Boolean);
417
-
418
- // fields used for owner auth rules that may or may not also
419
- // be explicit on the model.
420
- const ownerFields = resolveOwnerFields(modelDefinition);
421
-
422
- return Array.from(new Set(explicitFields.concat(ownerFields)));
423
- }
424
-
425
- const FIELD_IR = '';
426
-
427
- /**
428
- * Generates nested Custom Selection Set IR from path
429
- *
430
- * @param modelDefinitions
431
- * @param modelName
432
- * @param selectionSet - array of object paths
433
- * @example
434
- * ### Given
435
- * `selectionSet = ['id', 'comments.post.id']`
436
- * ### Returns
437
- * ```ts
438
- * {
439
- * id: '',
440
- * comments: {
441
- * items: { post: { id: '' } }
442
- * }
443
- * }
444
- * ```
445
- */
446
- export function customSelectionSetToIR(
447
- modelIntrospection: ModelIntrospectionSchema,
448
- modelName: string,
449
- selectionSet: string[],
450
- ): Record<string, string | object> {
451
- const dotNotationToObject = (path: string, modelOrNonModelName: string) => {
452
- const [fieldName, ...rest] = path.split('.');
453
-
454
- const nested = rest[0];
455
- const modelOrNonModelDefinition =
456
- modelIntrospection.models[modelOrNonModelName] ??
457
- modelIntrospection.nonModels[modelOrNonModelName];
458
-
459
- const modelOrNonModelFields = modelOrNonModelDefinition?.fields;
460
- const relatedModel = (
461
- modelOrNonModelFields?.[fieldName]?.type as ModelFieldType
462
- )?.model;
463
-
464
- const relatedModelDefinition = modelIntrospection.models[relatedModel];
465
- const relatedNonModel = (
466
- modelOrNonModelFields?.[fieldName]?.type as NonModelFieldType
467
- )?.nonModel;
468
- const relatedNonModelDefinition =
469
- modelIntrospection.nonModels[relatedNonModel];
470
-
471
- const isModelOrNonModelOrFieldType = relatedModelDefinition
472
- ? 'model'
473
- : relatedNonModelDefinition
474
- ? 'nonModel'
475
- : 'field';
476
-
477
- if (isModelOrNonModelOrFieldType === 'nonModel') {
478
- let result: Record<string, any> = {};
479
-
480
- if (!nested) {
481
- throw Error(
482
- `${fieldName} must declare a wildcard (*) or a field of custom type ${relatedNonModel}`,
483
- );
484
- }
485
-
486
- if (nested === SELECTION_SET_WILDCARD) {
487
- result = {
488
- [fieldName]: getDefaultSelectionSetForNonModelWithIR(
489
- relatedNonModelDefinition,
490
- modelIntrospection,
491
- ),
492
- };
493
- } else {
494
- result = {
495
- [fieldName]: dotNotationToObject(rest.join('.'), relatedNonModel),
496
- };
497
- }
498
-
499
- return result;
500
- } else if (isModelOrNonModelOrFieldType === 'model') {
501
- let result: Record<string, any> = {};
502
-
503
- if (!nested) {
504
- throw Error(
505
- `${fieldName} must declare a wildcard (*) or a field of model ${relatedModel}`,
506
- );
507
- }
508
-
509
- if (nested === SELECTION_SET_WILDCARD) {
510
- const nestedRelatedModelDefinition =
511
- modelIntrospection.models[relatedModel];
512
-
513
- result = {
514
- [fieldName]: getDefaultSelectionSetForModelWithIR(
515
- nestedRelatedModelDefinition,
516
- modelIntrospection,
517
- ),
518
- };
519
- } else {
520
- result = {
521
- [fieldName]: dotNotationToObject(rest.join('.'), relatedModel),
522
- };
523
- }
524
-
525
- if (modelOrNonModelFields[fieldName]?.isArray) {
526
- result = {
527
- [fieldName]: {
528
- items: result[fieldName],
529
- },
530
- };
531
- }
532
-
533
- return result;
534
- } else {
535
- const modelField = modelOrNonModelFields?.[fieldName];
536
-
537
- const nonModelDefinition =
538
- modelIntrospection.nonModels[modelOrNonModelName];
539
- const nonModelField = nonModelDefinition?.fields?.[fieldName];
540
-
541
- if (!nonModelDefinition) {
542
- const isOwnerField = resolveOwnerFields(
543
- modelOrNonModelDefinition,
544
- ).includes(fieldName);
545
-
546
- if (!modelField && !isOwnerField) {
547
- throw Error(
548
- `${fieldName} is not a field of model ${modelOrNonModelName}`,
549
- );
550
- }
551
- } else {
552
- if (!nonModelField) {
553
- throw Error(
554
- `${fieldName} is not a field of custom type ${modelOrNonModelName}`,
555
- );
556
- }
557
- }
558
-
559
- return { [fieldName]: FIELD_IR };
560
- }
561
- };
562
-
563
- return selectionSet.reduce(
564
- (resultObj, path) =>
565
- deepMergeSelectionSetObjects(
566
- dotNotationToObject(path, modelName),
567
- resultObj,
568
- ),
569
- {} as Record<string, any>,
570
- );
571
- }
572
-
573
- /**
574
- * Stringifies selection set IR
575
- * * @example
576
- * ### Given
577
- * ```ts
578
- * {
579
- * id: '',
580
- * comments: {
581
- * items: { post: { id: '' } }
582
- * }
583
- * }
584
- * ```
585
- * ### Returns
586
- * `'id comments { items { post { id } } }'`
587
- */
588
- export function selectionSetIRToString(
589
- obj: Record<string, string | any>,
590
- ): string {
591
- const res: string[] = [];
592
-
593
- Object.entries(obj).forEach(([fieldName, value]) => {
594
- if (value === FIELD_IR) {
595
- res.push(fieldName);
596
- } else if (typeof value === 'object' && value !== null) {
597
- if (value?.items) {
598
- res.push(
599
- fieldName,
600
- '{',
601
- 'items',
602
- '{',
603
- selectionSetIRToString(value.items),
604
- '}',
605
- '}',
606
- );
607
- } else {
608
- res.push(fieldName, '{', selectionSetIRToString(value), '}');
609
- }
610
- }
611
- });
612
-
613
- return res.join(' ');
614
- }
615
-
616
- /**
617
- * Recursively merges selection set objects from `source` onto `target`.
618
- *
619
- * `target` will be updated. `source` will be left alone.
620
- *
621
- * @param source The object to merge into target.
622
- * @param target The object to be mutated.
623
- */
624
- function deepMergeSelectionSetObjects<T extends Record<string, any>>(
625
- source: T,
626
- target: T,
627
- ) {
628
- const isObject = (obj: any) => obj && typeof obj === 'object';
629
-
630
- for (const key in source) {
631
- // This verification avoids 'Prototype Pollution' issue
632
- if (!Object.prototype.hasOwnProperty.call(source, key)) continue;
633
-
634
- if (
635
- Object.prototype.hasOwnProperty.call(target, key) &&
636
- isObject(target[key])
637
- ) {
638
- deepMergeSelectionSetObjects(source[key], target[key]);
639
- } else {
640
- target[key] = source[key];
641
- }
642
- }
643
-
644
- return target;
645
- }
646
-
647
- export function generateSelectionSet(
648
- modelIntrospection: ModelIntrospectionSchema,
649
- modelName: string,
650
- selectionSet?: string[],
651
- ) {
652
- const modelDefinition = modelIntrospection.models[modelName];
653
-
654
- const selSetIr = customSelectionSetToIR(
655
- modelIntrospection,
656
- modelName,
657
- selectionSet ?? defaultSelectionSetForModel(modelDefinition),
658
- );
659
- const selSetString = selectionSetIRToString(selSetIr);
660
-
661
- return selSetString;
662
- }
663
-
664
- export function generateGraphQLDocument(
665
- modelIntrospection: ModelIntrospectionSchema,
666
- modelName: string,
667
- modelOperation: ModelOperation,
668
- listArgs?: ListArgs | QueryArgs,
669
- indexMeta?: IndexMeta,
670
- ): string {
671
- const modelDefinition = modelIntrospection.models[modelName];
672
-
673
- const {
674
- name,
675
- pluralName,
676
- fields,
677
- primaryKeyInfo: {
678
- isCustomPrimaryKey,
679
- primaryKeyFieldName,
680
- sortKeyFieldNames,
681
- },
682
- } = modelDefinition;
683
-
684
- const { operationPrefix, usePlural } = graphQLOperationsInfo[modelOperation];
685
-
686
- const { selectionSet } = listArgs || {};
687
-
688
- let graphQLFieldName;
689
- let indexQueryArgs: Record<string, string>;
690
-
691
- if (operationPrefix) {
692
- graphQLFieldName = `${operationPrefix}${usePlural ? pluralName : name}`;
693
- } else if (indexMeta) {
694
- const { queryField, pk, sk = [] } = indexMeta;
695
- graphQLFieldName = queryField;
696
-
697
- const skQueryArgs = sk.reduce((acc: Record<string, any>, fieldName) => {
698
- const fieldType = fields[fieldName].type;
699
- acc[fieldName] = `Model${fieldType}KeyConditionInput`;
700
-
701
- return acc;
702
- }, {});
703
-
704
- indexQueryArgs = {
705
- [pk]: `${fields[pk].type}!`,
706
- ...skQueryArgs,
707
- };
708
- } else {
709
- throw new Error(
710
- 'Error generating GraphQL Document - invalid operation name',
711
- );
712
- }
713
-
714
- let graphQLOperationType: 'mutation' | 'query' | 'subscription' | undefined;
715
- let graphQLSelectionSet: string | undefined;
716
- let graphQLArguments: Record<string, any> | undefined;
717
-
718
- const selectionSetFields = generateSelectionSet(
719
- modelIntrospection,
720
- modelName,
721
- selectionSet as ListArgs['selectionSet'],
722
- );
723
-
724
- // default PK args for get and list operations
725
- // modified below for CPK
726
- const getPkArgs = {
727
- [primaryKeyFieldName]: `${fields[primaryKeyFieldName].type}!`,
728
- };
729
- const listPkArgs = {};
730
-
731
- const generateSkArgs = (op: 'get' | 'list') => {
732
- return sortKeyFieldNames.reduce(
733
- (acc: Record<string, any>, fieldName: string) => {
734
- const fieldType = fields[fieldName].type;
735
-
736
- if (op === 'get') {
737
- acc[fieldName] = `${fieldType}!`;
738
- } else if (op === 'list') {
739
- acc[fieldName] = `Model${fieldType}KeyConditionInput`;
740
- }
741
-
742
- return acc;
743
- },
744
- {},
745
- );
746
- };
747
-
748
- if (isCustomPrimaryKey) {
749
- Object.assign(getPkArgs, generateSkArgs('get'));
750
-
751
- Object.assign(
752
- listPkArgs,
753
- {
754
- // PK is only included in list query field args in the generated GQL
755
- // when explicitly specifying PK with .identifier(['fieldName']) or @primaryKey in the schema definition
756
- [primaryKeyFieldName]: `${fields[primaryKeyFieldName].type}`, // PK is always a nullable arg for list (no `!` after the type)
757
- sortDirection: 'ModelSortDirection',
758
- },
759
- generateSkArgs('list'),
760
- );
761
- }
762
-
763
- switch (modelOperation) {
764
- case 'CREATE':
765
- case 'UPDATE':
766
- case 'DELETE':
767
- graphQLArguments ??
768
- (graphQLArguments = {
769
- input: `${
770
- operationPrefix.charAt(0).toLocaleUpperCase() +
771
- operationPrefix.slice(1)
772
- }${name}Input!`,
773
- });
774
- graphQLOperationType ?? (graphQLOperationType = 'mutation');
775
- // TODO(Eslint): this this case clause correct without the break statement?
776
- // eslint-disable-next-line no-fallthrough
777
- case 'READ':
778
- graphQLArguments ?? (graphQLArguments = getPkArgs);
779
- graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
780
- // TODO(Eslint): this this case clause correct without the break statement?
781
- // eslint-disable-next-line no-fallthrough
782
- case 'LIST':
783
- graphQLArguments ??
784
- (graphQLArguments = {
785
- ...listPkArgs,
786
- filter: `Model${name}FilterInput`,
787
- limit: 'Int',
788
- nextToken: 'String',
789
- });
790
- graphQLOperationType ?? (graphQLOperationType = 'query');
791
- graphQLSelectionSet ??
792
- (graphQLSelectionSet = `items { ${selectionSetFields} } nextToken __typename`);
793
- // TODO(Eslint): this this case clause correct without the break statement?
794
- // eslint-disable-next-line no-fallthrough
795
- case 'INDEX_QUERY':
796
- graphQLArguments ??
797
- (graphQLArguments = {
798
- ...indexQueryArgs!,
799
- filter: `Model${name}FilterInput`,
800
- sortDirection: 'ModelSortDirection',
801
- limit: 'Int',
802
- nextToken: 'String',
803
- });
804
- graphQLOperationType ?? (graphQLOperationType = 'query');
805
- graphQLSelectionSet ??
806
- (graphQLSelectionSet = `items { ${selectionSetFields} } nextToken __typename`);
807
- // TODO(Eslint): this this case clause correct without the break statement?
808
- // eslint-disable-next-line no-fallthrough
809
- case 'ONCREATE':
810
- case 'ONUPDATE':
811
- case 'ONDELETE':
812
- graphQLArguments ??
813
- (graphQLArguments = {
814
- filter: `ModelSubscription${name}FilterInput`,
815
- });
816
- graphQLOperationType ?? (graphQLOperationType = 'subscription');
817
- graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
818
- break;
819
- case 'OBSERVE_QUERY':
820
- default:
821
- throw new Error(
822
- 'Internal error: Attempted to generate graphql document for observeQuery. Please report this error.',
823
- );
824
- }
825
-
826
- const graphQLDocument = `${graphQLOperationType}${
827
- graphQLArguments
828
- ? `(${Object.entries(graphQLArguments).map(
829
- ([fieldName, type]) => `$${fieldName}: ${type}`,
830
- )})`
831
- : ''
832
- } { ${graphQLFieldName}${
833
- graphQLArguments
834
- ? `(${Object.keys(graphQLArguments).map(
835
- fieldName => `${fieldName}: $${fieldName}`,
836
- )})`
837
- : ''
838
- } { ${graphQLSelectionSet} } }`;
839
-
840
- return graphQLDocument;
841
- }
842
-
843
- export function buildGraphQLVariables(
844
- modelDefinition: SchemaModel,
845
- operation: ModelOperation,
846
- arg: QueryArgs | undefined,
847
- modelIntrospection: ModelIntrospectionSchema,
848
- indexMeta?: IndexMeta,
849
- ): object {
850
- const {
851
- fields,
852
- primaryKeyInfo: {
853
- isCustomPrimaryKey,
854
- primaryKeyFieldName,
855
- sortKeyFieldNames,
856
- },
857
- } = modelDefinition;
858
-
859
- let variables: Record<string, any> = {};
860
-
861
- // TODO: process input
862
- switch (operation) {
863
- case 'CREATE':
864
- variables = {
865
- input: arg
866
- ? normalizeMutationInput(arg, modelDefinition, modelIntrospection)
867
- : {},
868
- };
869
- break;
870
- case 'UPDATE':
871
- // readonly fields are not updated
872
- variables = {
873
- input: arg
874
- ? Object.fromEntries(
875
- Object.entries(
876
- normalizeMutationInput(
877
- arg,
878
- modelDefinition,
879
- modelIntrospection,
880
- ),
881
- ).filter(([fieldName]) => {
882
- const { isReadOnly } = fields[fieldName];
883
-
884
- return !isReadOnly;
885
- }),
886
- )
887
- : {},
888
- };
889
- break;
890
- case 'READ':
891
- case 'DELETE':
892
- // only identifiers are sent
893
- if (arg) {
894
- variables = isCustomPrimaryKey
895
- ? [primaryKeyFieldName, ...sortKeyFieldNames].reduce(
896
- (acc: Record<string, any>, fieldName) => {
897
- acc[fieldName] = arg[fieldName];
898
-
899
- return acc;
900
- },
901
- {},
902
- )
903
- : { [primaryKeyFieldName]: arg[primaryKeyFieldName] };
904
- }
905
-
906
- if (operation === 'DELETE') {
907
- variables = { input: variables };
908
- }
909
- break;
910
- case 'LIST':
911
- if (arg?.filter) {
912
- variables.filter = arg.filter;
913
- }
914
- if (arg?.sortDirection) {
915
- variables.sortDirection = arg.sortDirection;
916
- variables[primaryKeyFieldName] = arg[primaryKeyFieldName];
917
- }
918
- if (arg?.nextToken) {
919
- variables.nextToken = arg.nextToken;
920
- }
921
- if (arg?.limit) {
922
- variables.limit = arg.limit;
923
- }
924
- break;
925
- case 'INDEX_QUERY': {
926
- const { pk, sk = [] } = indexMeta!;
927
-
928
- variables[pk] = arg![pk];
929
-
930
- for (const skField of sk) {
931
- variables[skField] = arg![skField];
932
- }
933
-
934
- if (arg?.filter) {
935
- variables.filter = arg.filter;
936
- }
937
-
938
- if (arg?.sortDirection) {
939
- variables.sortDirection = arg.sortDirection;
940
- }
941
-
942
- if (arg?.nextToken) {
943
- variables.nextToken = arg.nextToken;
944
- }
945
- if (arg?.limit) {
946
- variables.limit = arg.limit;
947
- }
948
- break;
949
- }
950
- case 'ONCREATE':
951
- case 'ONUPDATE':
952
- case 'ONDELETE':
953
- if (arg?.filter) {
954
- variables = { filter: arg.filter };
955
- }
956
- break;
957
- case 'OBSERVE_QUERY':
958
- throw new Error(
959
- 'Internal error: Attempted to build variables for observeQuery. Please report this error.',
960
- );
961
- break;
962
- default: {
963
- const exhaustiveCheck: never = operation;
964
- throw new Error(`Unhandled operation case: ${exhaustiveCheck}`);
965
- }
966
- }
967
-
968
- return variables;
969
- }
970
-
971
- /**
972
- * Iterates over mutation input values and resolves any model inputs to their corresponding join fields/values
973
- *
974
- * @example
975
- * ### Usage
976
- * ```ts
977
- * const result = normalizeMutationInput({ post: post }, model, modelDefinition);
978
- * ```
979
- * ### Result
980
- * ```ts
981
- * { postId: "abc123" }
982
- * ```
983
- *
984
- */
985
- export function normalizeMutationInput(
986
- mutationInput: QueryArgs,
987
- model: SchemaModel,
988
- modelIntrospection: ModelIntrospectionSchema,
989
- ): QueryArgs {
990
- const { fields } = model;
991
-
992
- const normalized: Record<string, unknown> = {};
993
-
994
- Object.entries(mutationInput).forEach(([inputFieldName, inputValue]) => {
995
- const fieldType = fields[inputFieldName]?.type as ModelFieldType;
996
- const relatedModelName = fieldType?.model;
997
-
998
- if (relatedModelName) {
999
- const association = fields[inputFieldName]?.association;
1000
- const relatedModelDef = modelIntrospection.models[relatedModelName];
1001
- const relatedModelPkInfo = relatedModelDef.primaryKeyInfo;
1002
-
1003
- if (association?.connectionType === connectionType.HAS_ONE) {
1004
- const associationHasOne = association as AssociationHasOne;
1005
- associationHasOne.targetNames.forEach((targetName, idx) => {
1006
- const associatedFieldName = associationHasOne.associatedWith[idx];
1007
- normalized[targetName] = (inputValue as Record<string, unknown>)[
1008
- associatedFieldName
1009
- ];
1010
- });
1011
- }
1012
-
1013
- if (association?.connectionType === connectionType.BELONGS_TO) {
1014
- const associationBelongsTo = association as AssociationBelongsTo;
1015
- associationBelongsTo.targetNames.forEach((targetName, idx) => {
1016
- if (idx === 0) {
1017
- const associatedFieldName = relatedModelPkInfo.primaryKeyFieldName;
1018
- normalized[targetName] = (inputValue as Record<string, unknown>)[
1019
- associatedFieldName
1020
- ];
1021
- } else {
1022
- const associatedFieldName =
1023
- relatedModelPkInfo.sortKeyFieldNames[idx - 1];
1024
- normalized[targetName] = (inputValue as Record<string, unknown>)[
1025
- associatedFieldName
1026
- ];
1027
- }
1028
- });
1029
- }
1030
- } else {
1031
- normalized[inputFieldName] = inputValue;
1032
- }
1033
- });
1034
-
1035
- return normalized;
1036
- }
1037
-
1038
- /**
1039
- * Produces a parameter object that can contains auth mode/token overrides
1040
- * only if present in either `options` (first) or configured on the `client`
1041
- * as a fallback.
1042
- *
1043
- * @param client Configured client from `generateClient`
1044
- * @param options Args/Options object from call site.
1045
- * @returns
1046
- */
1047
- export function authModeParams(
1048
- client: ClientWithModels,
1049
- options: AuthModeParams = {},
1050
- ): AuthModeParams {
1051
- return {
1052
- authMode: options.authMode || client[__authMode],
1053
- authToken: options.authToken || client[__authToken],
1054
- };
1055
- }
1056
-
1057
- /**
1058
- * Retrieves custom headers from either the client or request options.
1059
- * @param client V6Client | V6ClientSSRRequest | V6ClientSSRCookies - for extracting client headers
1060
- * @param requestHeaders {@link CustomHeaders} - request headers
1061
- * @returns custom headers as {@link CustomHeaders}
1062
- */
1063
- export function getCustomHeaders(
1064
- client: V6Client | ClientWithModels,
1065
- requestHeaders?: CustomHeaders,
1066
- ): CustomHeaders {
1067
- let headers: CustomHeaders = client[__headers] || {};
1068
-
1069
- // Individual request headers will take precedence over client headers.
1070
- // We intentionally do *not* merge client and request headers.
1071
- if (requestHeaders) {
1072
- headers = requestHeaders;
1073
- }
1074
-
1075
- return headers;
1076
- }