@aws-amplify/api-graphql 4.0.1 → 4.0.2-unstable.b778a9e.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 (110) hide show
  1. package/dist/cjs/internals/APIClient.js +503 -0
  2. package/dist/cjs/internals/APIClient.js.map +1 -0
  3. package/dist/cjs/internals/InternalGraphQLAPI.js +1 -1
  4. package/dist/cjs/internals/InternalGraphQLAPI.js.map +1 -1
  5. package/dist/cjs/internals/generateClient.js +33 -0
  6. package/dist/cjs/internals/generateClient.js.map +1 -0
  7. package/dist/cjs/internals/generateModelsProperty.js +43 -0
  8. package/dist/cjs/internals/generateModelsProperty.js.map +1 -0
  9. package/dist/cjs/internals/index.js +3 -1
  10. package/dist/cjs/internals/index.js.map +1 -1
  11. package/dist/cjs/internals/operations/get.js +61 -0
  12. package/dist/cjs/internals/operations/get.js.map +1 -0
  13. package/dist/cjs/internals/operations/list.js +73 -0
  14. package/dist/cjs/internals/operations/list.js.map +1 -0
  15. package/dist/cjs/internals/operations/observeQuery.js +121 -0
  16. package/dist/cjs/internals/operations/observeQuery.js.map +1 -0
  17. package/dist/cjs/internals/operations/subscription.js +29 -0
  18. package/dist/cjs/internals/operations/subscription.js.map +1 -0
  19. package/dist/cjs/internals/server/generateClient.js +32 -0
  20. package/dist/cjs/internals/server/generateClient.js.map +1 -0
  21. package/dist/cjs/internals/server/generateModelsProperty.js +47 -0
  22. package/dist/cjs/internals/server/generateModelsProperty.js.map +1 -0
  23. package/dist/cjs/internals/server/index.js +9 -0
  24. package/dist/cjs/internals/server/index.js.map +1 -0
  25. package/dist/cjs/internals/types.js +4 -0
  26. package/dist/cjs/internals/types.js.map +1 -0
  27. package/dist/cjs/types/index.js +3 -1
  28. package/dist/cjs/types/index.js.map +1 -1
  29. package/dist/cjs/utils/findIndexByFields.js +25 -0
  30. package/dist/cjs/utils/findIndexByFields.js.map +1 -0
  31. package/dist/cjs/utils/index.js +5 -1
  32. package/dist/cjs/utils/index.js.map +1 -1
  33. package/dist/cjs/utils/resolveOwnerFields.js +42 -0
  34. package/dist/cjs/utils/resolveOwnerFields.js.map +1 -0
  35. package/dist/cjs/utils/resolvePKFields.js +17 -0
  36. package/dist/cjs/utils/resolvePKFields.js.map +1 -0
  37. package/dist/esm/index.mjs +1 -1
  38. package/dist/esm/internals/APIClient.d.ts +121 -0
  39. package/dist/esm/internals/APIClient.mjs +493 -0
  40. package/dist/esm/internals/APIClient.mjs.map +1 -0
  41. package/dist/esm/internals/InternalGraphQLAPI.mjs +1 -1
  42. package/dist/esm/internals/InternalGraphQLAPI.mjs.map +1 -1
  43. package/dist/esm/internals/generateClient.d.ts +12 -0
  44. package/dist/esm/internals/generateClient.mjs +31 -0
  45. package/dist/esm/internals/generateClient.mjs.map +1 -0
  46. package/dist/esm/internals/generateModelsProperty.d.ts +4 -0
  47. package/dist/esm/internals/generateModelsProperty.mjs +41 -0
  48. package/dist/esm/internals/generateModelsProperty.mjs.map +1 -0
  49. package/dist/esm/internals/index.d.ts +1 -0
  50. package/dist/esm/internals/index.mjs +1 -0
  51. package/dist/esm/internals/index.mjs.map +1 -1
  52. package/dist/esm/internals/operations/get.d.ts +2 -0
  53. package/dist/esm/internals/operations/get.mjs +59 -0
  54. package/dist/esm/internals/operations/get.mjs.map +1 -0
  55. package/dist/esm/internals/operations/list.d.ts +2 -0
  56. package/dist/esm/internals/operations/list.mjs +71 -0
  57. package/dist/esm/internals/operations/list.mjs.map +1 -0
  58. package/dist/esm/internals/operations/observeQuery.d.ts +2 -0
  59. package/dist/esm/internals/operations/observeQuery.mjs +122 -0
  60. package/dist/esm/internals/operations/observeQuery.mjs.map +1 -0
  61. package/dist/esm/internals/operations/subscription.d.ts +1 -0
  62. package/dist/esm/internals/operations/subscription.mjs +27 -0
  63. package/dist/esm/internals/operations/subscription.mjs.map +1 -0
  64. package/dist/esm/internals/server/generateClient.d.ts +11 -0
  65. package/dist/esm/internals/server/generateClient.mjs +34 -0
  66. package/dist/esm/internals/server/generateClient.mjs.map +1 -0
  67. package/dist/esm/internals/server/generateModelsProperty.d.ts +3 -0
  68. package/dist/esm/internals/server/generateModelsProperty.mjs +45 -0
  69. package/dist/esm/internals/server/generateModelsProperty.mjs.map +1 -0
  70. package/dist/esm/internals/server/index.d.ts +1 -0
  71. package/dist/esm/internals/server/index.mjs +2 -0
  72. package/dist/esm/internals/server/index.mjs.map +1 -0
  73. package/dist/esm/internals/types.d.ts +17 -0
  74. package/dist/esm/internals/types.mjs +2 -0
  75. package/dist/esm/internals/types.mjs.map +1 -0
  76. package/dist/esm/types/index.d.ts +22 -2
  77. package/dist/esm/types/index.mjs +3 -1
  78. package/dist/esm/types/index.mjs.map +1 -1
  79. package/dist/esm/utils/findIndexByFields.d.ts +9 -0
  80. package/dist/esm/utils/findIndexByFields.mjs +22 -0
  81. package/dist/esm/utils/findIndexByFields.mjs.map +1 -0
  82. package/dist/esm/utils/index.d.ts +2 -0
  83. package/dist/esm/utils/index.mjs +2 -0
  84. package/dist/esm/utils/index.mjs.map +1 -1
  85. package/dist/esm/utils/resolveOwnerFields.d.ts +12 -0
  86. package/dist/esm/utils/resolveOwnerFields.mjs +39 -0
  87. package/dist/esm/utils/resolveOwnerFields.mjs.map +1 -0
  88. package/dist/esm/utils/resolvePKFields.d.ts +13 -0
  89. package/dist/esm/utils/resolvePKFields.mjs +14 -0
  90. package/dist/esm/utils/resolvePKFields.mjs.map +1 -0
  91. package/internals/server/package.json +8 -0
  92. package/package.json +15 -9
  93. package/src/internals/APIClient.ts +724 -0
  94. package/src/internals/InternalGraphQLAPI.ts +1 -1
  95. package/src/internals/generateClient.ts +33 -0
  96. package/src/internals/generateModelsProperty.ts +70 -0
  97. package/src/internals/index.ts +1 -0
  98. package/src/internals/operations/get.ts +121 -0
  99. package/src/internals/operations/list.ts +111 -0
  100. package/src/internals/operations/observeQuery.ts +140 -0
  101. package/src/internals/operations/subscription.ts +59 -0
  102. package/src/internals/server/generateClient.ts +45 -0
  103. package/src/internals/server/generateModelsProperty.ts +70 -0
  104. package/src/internals/server/index.ts +4 -0
  105. package/src/internals/types.ts +21 -0
  106. package/src/types/index.ts +28 -2
  107. package/src/utils/findIndexByFields.ts +29 -0
  108. package/src/utils/index.ts +2 -0
  109. package/src/utils/resolveOwnerFields.ts +65 -0
  110. package/src/utils/resolvePKFields.ts +22 -0
@@ -0,0 +1,724 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { resolveOwnerFields } from '../utils/resolveOwnerFields';
4
+ import { GraphQLAuthMode } from '@aws-amplify/core/internals/utils';
5
+ import { V6Client, __authMode, __authToken } from '../types';
6
+ import { AmplifyServer } from '@aws-amplify/core/internals/adapter-core';
7
+
8
+ type ListArgs = { selectionSet?: string[]; filter?: {} };
9
+
10
+ type LazyLoadOptions = {
11
+ authMode?: GraphQLAuthMode;
12
+ authToken?: string | undefined;
13
+ limit?: number | undefined;
14
+ nextToken?: string | undefined | null;
15
+ };
16
+
17
+ const connectionType = {
18
+ HAS_ONE: 'HAS_ONE',
19
+ HAS_MANY: 'HAS_MANY',
20
+ BELONGS_TO: 'BELONGS_TO',
21
+ };
22
+
23
+ /**
24
+ *
25
+ * @param GraphQL response object
26
+ * @returns response object with `items` properties flattened
27
+ */
28
+ export const flattenItems = (obj: Record<string, any>): Record<string, any> => {
29
+ const res: Record<string, any> = {};
30
+
31
+ Object.entries(obj).forEach(([prop, value]) => {
32
+ if (typeof value === 'object' && value !== null) {
33
+ if (value.items !== undefined) {
34
+ res[prop] = value.items.map((item: Record<string, any>) =>
35
+ flattenItems(item)
36
+ );
37
+ return;
38
+ }
39
+ res[prop] = flattenItems(value);
40
+ return;
41
+ }
42
+
43
+ res[prop] = value;
44
+ });
45
+
46
+ return res;
47
+ };
48
+
49
+ // TODO: this should accept single result to support CRUD methods; create helper for array/list
50
+ export function initializeModel(
51
+ client: any,
52
+ modelName: string,
53
+ result: any[],
54
+ modelIntrospection: any,
55
+ authMode: GraphQLAuthMode | undefined,
56
+ authToken: string | undefined,
57
+ context = false
58
+ ): any[] {
59
+ const introModel = modelIntrospection.models[modelName];
60
+ const introModelFields = introModel.fields;
61
+
62
+ const modelFields: string[] = Object.entries(introModelFields)
63
+ .filter(([_, field]: [string, any]) => field?.type?.model !== undefined)
64
+ .map(([fieldName]) => fieldName);
65
+
66
+ return result.map(record => {
67
+ const initializedRelationalFields = {};
68
+
69
+ for (const field of modelFields) {
70
+ const relatedModelName = introModelFields[field].type.model;
71
+
72
+ const relatedModel = modelIntrospection.models[relatedModelName];
73
+
74
+ const relatedModelPKFieldName =
75
+ relatedModel.primaryKeyInfo.primaryKeyFieldName;
76
+
77
+ const relatedModelSKFieldNames =
78
+ relatedModel.primaryKeyInfo.sortKeyFieldNames;
79
+
80
+ const relationType = introModelFields[field].association.connectionType;
81
+ const connectionFields =
82
+ introModelFields[field].association.associatedWith;
83
+
84
+ const targetNames =
85
+ introModelFields[field].association?.targetNames || [];
86
+
87
+ switch (relationType) {
88
+ case connectionType.HAS_ONE:
89
+ case connectionType.BELONGS_TO:
90
+ const sortKeyValues = relatedModelSKFieldNames.reduce(
91
+ (acc, curVal) => {
92
+ if (record[curVal]) {
93
+ return (acc[curVal] = record[curVal]);
94
+ }
95
+ },
96
+ {}
97
+ );
98
+
99
+ if (context) {
100
+ initializedRelationalFields[field] = (
101
+ contextSpec: AmplifyServer.ContextSpec,
102
+ options?: LazyLoadOptions
103
+ ) => {
104
+ if (record[targetNames[0]]) {
105
+ return client.models[relatedModelName].get(
106
+ contextSpec,
107
+ {
108
+ [relatedModelPKFieldName]: record[targetNames[0]],
109
+ ...sortKeyValues,
110
+ },
111
+ {
112
+ authMode: options?.authMode || authMode,
113
+ authToken: options?.authToken || authToken,
114
+ }
115
+ );
116
+ }
117
+ return undefined;
118
+ };
119
+ } else {
120
+ initializedRelationalFields[field] = (
121
+ options?: LazyLoadOptions
122
+ ) => {
123
+ if (record[targetNames[0]]) {
124
+ return client.models[relatedModelName].get(
125
+ {
126
+ [relatedModelPKFieldName]: record[targetNames[0]],
127
+ ...sortKeyValues,
128
+ },
129
+ {
130
+ authMode: options?.authMode || authMode,
131
+ authToken: options?.authToken || authToken,
132
+ }
133
+ );
134
+ }
135
+ return undefined;
136
+ };
137
+ }
138
+
139
+ break;
140
+ case connectionType.HAS_MANY:
141
+ const parentPk = introModel.primaryKeyInfo.primaryKeyFieldName;
142
+ const parentSK = introModel.primaryKeyInfo.sortKeyFieldNames;
143
+
144
+ // M:N check - TODO: refactor
145
+ if (relatedModel.fields[connectionFields[0]]?.type.model) {
146
+ const relatedTargetNames =
147
+ relatedModel.fields[connectionFields[0]].association.targetNames;
148
+
149
+ const hasManyFilter = relatedTargetNames.map((field, idx) => {
150
+ if (idx === 0) {
151
+ return { [field]: { eq: record[parentPk] } };
152
+ }
153
+
154
+ return { [field]: { eq: record[parentSK[idx - 1]] } };
155
+ });
156
+
157
+ if (context) {
158
+ initializedRelationalFields[field] = (
159
+ contextSpec: AmplifyServer.ContextSpec,
160
+ options?: LazyLoadOptions
161
+ ) => {
162
+ if (record[parentPk]) {
163
+ return client.models[relatedModelName].list(contextSpec, {
164
+ filter: { and: hasManyFilter },
165
+ limit: options?.limit,
166
+ nextToken: options?.nextToken,
167
+ authMode: options?.authMode || authMode,
168
+ authToken: options?.authToken || authToken,
169
+ });
170
+ }
171
+ return [];
172
+ };
173
+ } else {
174
+ initializedRelationalFields[field] = (
175
+ options?: LazyLoadOptions
176
+ ) => {
177
+ if (record[parentPk]) {
178
+ return client.models[relatedModelName].list({
179
+ filter: { and: hasManyFilter },
180
+ limit: options?.limit,
181
+ nextToken: options?.nextToken,
182
+ authMode: options?.authMode || authMode,
183
+ authToken: options?.authToken || authToken,
184
+ });
185
+ }
186
+ return [];
187
+ };
188
+ }
189
+
190
+ break;
191
+ }
192
+
193
+ const hasManyFilter = connectionFields.map((field, idx) => {
194
+ if (idx === 0) {
195
+ return { [field]: { eq: record[parentPk] } };
196
+ }
197
+
198
+ return { [field]: { eq: record[parentSK[idx - 1]] } };
199
+ });
200
+
201
+ if (context) {
202
+ initializedRelationalFields[field] = (
203
+ contextSpec: AmplifyServer.ContextSpec,
204
+ options?: LazyLoadOptions
205
+ ) => {
206
+ if (record[parentPk]) {
207
+ return client.models[relatedModelName].list(contextSpec, {
208
+ filter: { and: hasManyFilter },
209
+ limit: options?.limit,
210
+ nextToken: options?.nextToken,
211
+ authMode: options?.authMode || authMode,
212
+ authToken: options?.authToken || authToken,
213
+ });
214
+ }
215
+ return [];
216
+ };
217
+ } else {
218
+ initializedRelationalFields[field] = (
219
+ options?: LazyLoadOptions
220
+ ) => {
221
+ if (record[parentPk]) {
222
+ return client.models[relatedModelName].list({
223
+ filter: { and: hasManyFilter },
224
+ limit: options?.limit,
225
+ nextToken: options?.nextToken,
226
+ authMode: options?.authMode || authMode,
227
+ authToken: options?.authToken || authToken,
228
+ });
229
+ }
230
+ return [];
231
+ };
232
+ }
233
+
234
+ break;
235
+ default:
236
+ break;
237
+ }
238
+ }
239
+
240
+ return { ...record, ...initializedRelationalFields };
241
+ });
242
+ }
243
+
244
+ export const graphQLOperationsInfo = {
245
+ CREATE: { operationPrefix: 'create' as const, usePlural: false },
246
+ READ: { operationPrefix: 'get' as const, usePlural: false },
247
+ UPDATE: { operationPrefix: 'update' as const, usePlural: false },
248
+ DELETE: { operationPrefix: 'delete' as const, usePlural: false },
249
+ LIST: { operationPrefix: 'list' as const, usePlural: true },
250
+ ONCREATE: { operationPrefix: 'onCreate' as const, usePlural: false },
251
+ ONUPDATE: { operationPrefix: 'onUpdate' as const, usePlural: false },
252
+ ONDELETE: { operationPrefix: 'onDelete' as const, usePlural: false },
253
+ OBSERVE_QUERY: { operationPrefix: 'observeQuery' as const, usePlural: false },
254
+ };
255
+ export type ModelOperation = keyof typeof graphQLOperationsInfo;
256
+
257
+ type OperationPrefix =
258
+ (typeof graphQLOperationsInfo)[ModelOperation]['operationPrefix'];
259
+
260
+ const graphQLDocumentsCache = new Map<string, Map<ModelOperation, string>>();
261
+ const SELECTION_SET_WILDCARD = '*';
262
+
263
+ function defaultSelectionSetForModel(modelDefinition: any): string[] {
264
+ // fields that are explicitly part of the graphql schema; not
265
+ // inferred from owner auth rules.
266
+ const { fields } = modelDefinition;
267
+ const explicitFields = Object.values<any>(fields)
268
+ .map(({ type, name }) => typeof type === 'string' && name) // Default selection set omits model fields
269
+ .filter(Boolean);
270
+
271
+ // fields used for owner auth rules that may or may not also
272
+ // be explicit on the model.
273
+ const ownerFields = resolveOwnerFields(modelDefinition);
274
+
275
+ return Array.from(new Set(explicitFields.concat(ownerFields)));
276
+ }
277
+
278
+ const FIELD_IR = '';
279
+
280
+ /**
281
+ * Generates nested Custom Selection Set IR from path
282
+ *
283
+ * @param modelIntrospection
284
+ * @param modelName
285
+ * @param selectionSet - array of object paths
286
+ * @example
287
+ * ### Given
288
+ * `selectionSet = ['id', 'comments.post.id']`
289
+ * ### Returns
290
+ * ```ts
291
+ * {
292
+ * id: '',
293
+ * comments: {
294
+ * items: { post: { id: '' } }
295
+ * }
296
+ * }
297
+ * ```
298
+ */
299
+ export function customSelectionSetToIR(
300
+ modelIntrospection: any,
301
+ modelName: string,
302
+ selectionSet: string[]
303
+ ): Record<string, string | object> {
304
+ const modelDefinition = modelIntrospection[modelName];
305
+ const { fields: modelFields } = modelDefinition;
306
+
307
+ return selectionSet.reduce((resultObj, path) => {
308
+ const [fieldName, nested, ...rest] = path.split('.');
309
+
310
+ if (nested) {
311
+ const relatedModel = modelFields[fieldName]?.type?.model;
312
+
313
+ if (!relatedModel) {
314
+ // TODO: may need to change this to support custom types
315
+ throw Error(`${fieldName} is not a model field`);
316
+ }
317
+
318
+ const relatedModelDefinition = modelIntrospection[relatedModel];
319
+
320
+ const selectionSet =
321
+ nested === SELECTION_SET_WILDCARD
322
+ ? defaultSelectionSetIR(relatedModelDefinition)
323
+ : // if we have a path like 'field.anotherField' recursively build up selection set IR
324
+ customSelectionSetToIR(modelIntrospection, relatedModel, [
325
+ [nested, ...rest].join('.'),
326
+ ]);
327
+
328
+ if (modelFields[fieldName]?.isArray) {
329
+ const existing = resultObj[fieldName] || {
330
+ items: {},
331
+ };
332
+ const merged = { ...existing.items, ...selectionSet };
333
+
334
+ resultObj[fieldName] = { items: merged };
335
+ return resultObj;
336
+ }
337
+
338
+ const existingItems = resultObj[fieldName] || {};
339
+ const merged = { ...existingItems, ...selectionSet };
340
+
341
+ resultObj[fieldName] = merged;
342
+ return resultObj;
343
+ }
344
+
345
+ const exists = Boolean(modelFields[fieldName]);
346
+
347
+ if (!exists) {
348
+ throw Error(`${fieldName} is not a field of model ${modelName}`);
349
+ }
350
+
351
+ resultObj[fieldName] = FIELD_IR;
352
+ return resultObj;
353
+ }, {});
354
+ }
355
+
356
+ const defaultSelectionSetIR = relatedModelDefinition => {
357
+ const defaultSelectionSet = defaultSelectionSetForModel(
358
+ relatedModelDefinition
359
+ );
360
+
361
+ const reduced = defaultSelectionSet.reduce((acc, curVal) => {
362
+ acc[curVal] = FIELD_IR;
363
+ return acc;
364
+ }, {});
365
+
366
+ return reduced;
367
+ };
368
+
369
+ /**
370
+ * Stringifies selection set IR
371
+ * * @example
372
+ * ### Given
373
+ * ```ts
374
+ * {
375
+ * id: '',
376
+ * comments: {
377
+ * items: { post: { id: '' } }
378
+ * }
379
+ * }
380
+ * ```
381
+ * ### Returns
382
+ * `'id comments { items { post { id } } }'`
383
+ */
384
+ export function selectionSetIRToString(
385
+ obj: Record<string, string | any>
386
+ ): string {
387
+ const res: string[] = [];
388
+
389
+ Object.entries(obj).forEach(([fieldName, value]) => {
390
+ if (value === FIELD_IR) {
391
+ res.push(fieldName);
392
+ } else if (typeof value === 'object' && value !== null) {
393
+ if (value?.items) {
394
+ res.push(
395
+ fieldName,
396
+ '{',
397
+ 'items',
398
+ '{',
399
+ selectionSetIRToString(value.items),
400
+ '}',
401
+ '}'
402
+ );
403
+ } else {
404
+ res.push(fieldName, '{', selectionSetIRToString(value), '}');
405
+ }
406
+ }
407
+ });
408
+
409
+ return res.join(' ');
410
+ }
411
+
412
+ export function generateSelectionSet(
413
+ modelIntrospection: any,
414
+ modelName: string,
415
+ selectionSet?: string[]
416
+ ) {
417
+ const modelDefinition = modelIntrospection[modelName];
418
+
419
+ if (!selectionSet) {
420
+ return defaultSelectionSetForModel(modelDefinition).join(' ');
421
+ }
422
+
423
+ const selSetIr = customSelectionSetToIR(
424
+ modelIntrospection,
425
+ modelName,
426
+ selectionSet
427
+ );
428
+ const selSetString = selectionSetIRToString(selSetIr);
429
+
430
+ return selSetString;
431
+ }
432
+
433
+ export function generateGraphQLDocument(
434
+ modelIntrospection: any,
435
+ modelName: string,
436
+ modelOperation: ModelOperation,
437
+ listArgs?: ListArgs
438
+ ): string {
439
+ const modelDefinition = modelIntrospection[modelName];
440
+
441
+ const {
442
+ name,
443
+ pluralName,
444
+ fields,
445
+ primaryKeyInfo: {
446
+ isCustomPrimaryKey,
447
+ primaryKeyFieldName,
448
+ sortKeyFieldNames,
449
+ },
450
+ } = modelDefinition;
451
+
452
+ const { operationPrefix, usePlural } = graphQLOperationsInfo[modelOperation];
453
+
454
+ const { selectionSet } = listArgs || {};
455
+
456
+ const fromCache = graphQLDocumentsCache.get(name)?.get(modelOperation);
457
+
458
+ if (fromCache !== undefined) {
459
+ return fromCache;
460
+ }
461
+
462
+ if (!graphQLDocumentsCache.has(name)) {
463
+ graphQLDocumentsCache.set(name, new Map());
464
+ }
465
+
466
+ const graphQLFieldName = `${operationPrefix}${usePlural ? pluralName : name}`;
467
+ let graphQLOperationType: 'mutation' | 'query' | 'subscription' | undefined;
468
+ let graphQLSelectionSet: string | undefined;
469
+ let graphQLArguments: Record<string, any> | undefined;
470
+
471
+ const selectionSetFields = generateSelectionSet(
472
+ modelIntrospection,
473
+ modelName,
474
+ selectionSet
475
+ );
476
+
477
+ switch (modelOperation) {
478
+ case 'CREATE':
479
+ case 'UPDATE':
480
+ case 'DELETE':
481
+ graphQLArguments ??
482
+ (graphQLArguments = {
483
+ input: `${
484
+ operationPrefix.charAt(0).toLocaleUpperCase() +
485
+ operationPrefix.slice(1)
486
+ }${name}Input!`,
487
+ });
488
+ graphQLOperationType ?? (graphQLOperationType = 'mutation');
489
+ case 'READ':
490
+ graphQLArguments ??
491
+ (graphQLArguments = isCustomPrimaryKey
492
+ ? [primaryKeyFieldName, ...sortKeyFieldNames].reduce(
493
+ (acc, fieldName) => {
494
+ acc[fieldName] = fields[fieldName].type;
495
+
496
+ return acc;
497
+ },
498
+ {}
499
+ )
500
+ : {
501
+ [primaryKeyFieldName]: `${fields[primaryKeyFieldName].type}!`,
502
+ });
503
+ graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
504
+ case 'LIST':
505
+ graphQLArguments ??
506
+ (graphQLArguments = {
507
+ filter: `Model${name}FilterInput`,
508
+ limit: 'Int',
509
+ nextToken: 'String',
510
+ });
511
+ graphQLOperationType ?? (graphQLOperationType = 'query');
512
+ graphQLSelectionSet ??
513
+ (graphQLSelectionSet = `items { ${selectionSetFields} } nextToken __typename`);
514
+ case 'ONCREATE':
515
+ case 'ONUPDATE':
516
+ case 'ONDELETE':
517
+ graphQLArguments ??
518
+ (graphQLArguments = {
519
+ filter: `ModelSubscription${name}FilterInput`,
520
+ });
521
+ graphQLOperationType ?? (graphQLOperationType = 'subscription');
522
+ graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
523
+ break;
524
+ case 'OBSERVE_QUERY':
525
+ default:
526
+ throw new Error(
527
+ 'Internal error: Attempted to generate graphql document for observeQuery. Please report this error.'
528
+ );
529
+ }
530
+
531
+ const graphQLDocument = `${graphQLOperationType}${
532
+ graphQLArguments
533
+ ? `(${Object.entries(graphQLArguments).map(
534
+ ([fieldName, type]) => `\$${fieldName}: ${type}`
535
+ )})`
536
+ : ''
537
+ } { ${graphQLFieldName}${
538
+ graphQLArguments
539
+ ? `(${Object.keys(graphQLArguments).map(
540
+ fieldName => `${fieldName}: \$${fieldName}`
541
+ )})`
542
+ : ''
543
+ } { ${graphQLSelectionSet} } }`;
544
+
545
+ graphQLDocumentsCache.get(name)?.set(modelOperation, graphQLDocument);
546
+
547
+ return graphQLDocument;
548
+ }
549
+
550
+ export function buildGraphQLVariables(
551
+ modelDefinition: any,
552
+ operation: ModelOperation,
553
+ arg: any,
554
+ modelIntrospection
555
+ ): object {
556
+ const {
557
+ fields,
558
+ primaryKeyInfo: {
559
+ isCustomPrimaryKey,
560
+ primaryKeyFieldName,
561
+ sortKeyFieldNames,
562
+ },
563
+ } = modelDefinition;
564
+
565
+ let variables: Record<string, any> = {};
566
+
567
+ // TODO: process input
568
+ switch (operation) {
569
+ case 'CREATE':
570
+ variables = {
571
+ input: normalizeMutationInput(arg, modelDefinition, modelIntrospection),
572
+ };
573
+ break;
574
+ case 'UPDATE':
575
+ // readonly fields are not updated
576
+ variables = {
577
+ input: Object.fromEntries(
578
+ Object.entries(
579
+ normalizeMutationInput(arg, modelDefinition, modelIntrospection)
580
+ ).filter(([fieldName]) => {
581
+ const { isReadOnly } = fields[fieldName];
582
+
583
+ return !isReadOnly;
584
+ })
585
+ ),
586
+ };
587
+ break;
588
+ case 'READ':
589
+ case 'DELETE':
590
+ // only identifiers are sent
591
+ variables = isCustomPrimaryKey
592
+ ? [primaryKeyFieldName, ...sortKeyFieldNames].reduce(
593
+ (acc, fieldName) => {
594
+ acc[fieldName] = arg[fieldName];
595
+
596
+ return acc;
597
+ },
598
+ {}
599
+ )
600
+ : { [primaryKeyFieldName]: arg[primaryKeyFieldName] };
601
+
602
+ if (operation === 'DELETE') {
603
+ variables = { input: variables };
604
+ }
605
+ break;
606
+ case 'LIST':
607
+ if (arg?.filter) {
608
+ variables.filter = arg.filter;
609
+ }
610
+ if (arg?.nextToken) {
611
+ variables.nextToken = arg.nextToken;
612
+ }
613
+ if (arg?.limit) {
614
+ variables.limit = arg.limit;
615
+ }
616
+ break;
617
+ case 'ONCREATE':
618
+ case 'ONUPDATE':
619
+ case 'ONDELETE':
620
+ if (arg?.filter) {
621
+ variables = { filter: arg.filter };
622
+ }
623
+ break;
624
+ case 'OBSERVE_QUERY':
625
+ throw new Error(
626
+ 'Internal error: Attempted to build variables for observeQuery. Please report this error.'
627
+ );
628
+ break;
629
+ default:
630
+ const exhaustiveCheck: never = operation;
631
+ throw new Error(`Unhandled operation case: ${exhaustiveCheck}`);
632
+ }
633
+
634
+ return variables;
635
+ }
636
+
637
+ /**
638
+ * Iterates over mutation input values and resolves any model inputs to their corresponding join fields/values
639
+ *
640
+ * @example
641
+ * ### Usage
642
+ * ```ts
643
+ * const result = normalizeMutationInput({ post: post }, model, modelDefinition);
644
+ * ```
645
+ * ### Result
646
+ * ```ts
647
+ * { postId: "abc123" }
648
+ * ```
649
+ *
650
+ */
651
+ export function normalizeMutationInput(
652
+ mutationInput: any,
653
+ model: any,
654
+ modelDefinition: any
655
+ ): Record<string, unknown> {
656
+ const { fields } = model;
657
+
658
+ const normalized = {};
659
+
660
+ Object.entries(mutationInput).forEach(([inputFieldName, inputValue]) => {
661
+ const relatedModelName: string | undefined =
662
+ fields[inputFieldName]?.type?.model;
663
+
664
+ if (relatedModelName) {
665
+ const association = fields[inputFieldName]?.association;
666
+ const relatedModelDef = modelDefinition.models[relatedModelName];
667
+ const relatedModelPkInfo = relatedModelDef.primaryKeyInfo;
668
+
669
+ if (association.connectionType === connectionType.HAS_ONE) {
670
+ association.targetNames.forEach((targetName, idx) => {
671
+ const associatedFieldName = association.associatedWith[idx];
672
+ normalized[targetName] = (inputValue as Record<string, unknown>)[
673
+ associatedFieldName
674
+ ];
675
+ });
676
+ }
677
+
678
+ if (association.connectionType === connectionType.BELONGS_TO) {
679
+ association.targetNames.forEach((targetName, idx) => {
680
+ if (idx === 0) {
681
+ const associatedFieldName = relatedModelPkInfo.primaryKeyFieldName;
682
+ normalized[targetName] = (inputValue as Record<string, unknown>)[
683
+ associatedFieldName
684
+ ];
685
+ } else {
686
+ const associatedFieldName =
687
+ relatedModelPkInfo.sortKeyFieldNames[idx - 1];
688
+ normalized[targetName] = (inputValue as Record<string, unknown>)[
689
+ associatedFieldName
690
+ ];
691
+ }
692
+ });
693
+ }
694
+ } else {
695
+ normalized[inputFieldName] = inputValue;
696
+ }
697
+ });
698
+
699
+ return normalized;
700
+ }
701
+
702
+ type AuthModeParams = {
703
+ authMode?: GraphQLAuthMode;
704
+ authToken?: string;
705
+ };
706
+
707
+ /**
708
+ * Produces a parameter object that can contains auth mode/token overrides
709
+ * only if present in either `options` (first) or configured on the `client`
710
+ * as a fallback.
711
+ *
712
+ * @param client Configured client from `generateClient`
713
+ * @param options Args/Options obect from call site.
714
+ * @returns
715
+ */
716
+ export function authModeParams(
717
+ client: V6Client,
718
+ options: AuthModeParams = {}
719
+ ): AuthModeParams {
720
+ return {
721
+ authMode: options.authMode || client[__authMode],
722
+ authToken: options.authToken || client[__authToken],
723
+ };
724
+ }