@aws-amplify/api 5.4.6-api-v6.2fd20b7.0 → 5.4.6-api-v6-models.5d6fe9b.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/API.ts CHANGED
@@ -11,7 +11,14 @@ import { graphql as v6graphql } from '@aws-amplify/api-graphql/internals';
11
11
  import { Amplify, ConsoleLogger as Logger } from '@aws-amplify/core';
12
12
  import Observable from 'zen-observable-ts';
13
13
  import { InternalAPIClass } from './internals/InternalAPI';
14
- import type { ModelTypes } from '@aws-amplify/types-package-alpha';
14
+ import {
15
+ initializeModel,
16
+ generateGraphQLDocument,
17
+ buildGraphQLVariables,
18
+ graphQLOperationsInfo,
19
+ ModelOperation,
20
+ } from './APIClient';
21
+ import type { ModelTypes } from '@aws-amplify/amplify-api-next-types-alpha';
15
22
 
16
23
  const logger = new Logger('API');
17
24
  /**
@@ -62,6 +69,8 @@ export class APIClass extends InternalAPIClass {
62
69
  models: {},
63
70
  };
64
71
 
72
+ // TODO: refactor this to use separate methods for each CRUDL.
73
+ // Doesn't make sense to gen the methods dynamically given the different args and return values
65
74
  for (const model of Object.values(modelIntrospection.models)) {
66
75
  const { name } = model as any;
67
76
 
@@ -71,29 +80,99 @@ export class APIClass extends InternalAPIClass {
71
80
  ([key, { operationPrefix }]) => {
72
81
  const operation = key as ModelOperation;
73
82
 
74
- // e.g. clients.models.Todo.update
75
- client.models[name][operationPrefix] = async (arg?: any) => {
76
- const query = generateGraphQLDocument(model, operation);
77
- const variables = buildGraphQLVariables(model, operation, arg);
78
-
79
- const res = (await this.graphql({
80
- query,
81
- variables,
82
- })) as any;
83
-
84
- // flatten response
85
- if (res.data !== undefined) {
86
- const [key] = Object.keys(res.data);
87
-
88
- if (res.data[key].items) {
89
- return res.data[key].items;
83
+ if (operation === 'LIST') {
84
+ client.models[name][operationPrefix] = async (args?: any) => {
85
+ const query = generateGraphQLDocument(
86
+ modelIntrospection.models,
87
+ name,
88
+ 'LIST',
89
+ args
90
+ );
91
+ const variables = buildGraphQLVariables(
92
+ model,
93
+ 'LIST',
94
+ args,
95
+ modelIntrospection
96
+ );
97
+
98
+ console.log('API list', query, variables);
99
+
100
+ const res = (await this.graphql({
101
+ query,
102
+ variables,
103
+ })) as any;
104
+
105
+ // flatten response
106
+ if (res.data !== undefined) {
107
+ const [key] = Object.keys(res.data);
108
+
109
+ if (res.data[key].items) {
110
+ const flattenedResult = res.data[key].items;
111
+
112
+ // don't init if custom selection set
113
+ if (args?.selectionSet) {
114
+ return flattenedResult;
115
+ } else {
116
+ const initialized = initializeModel(
117
+ client,
118
+ name,
119
+ flattenedResult,
120
+ modelIntrospection
121
+ );
122
+
123
+ console.log('initialized', initialized);
124
+
125
+ return initialized;
126
+ }
127
+ }
128
+
129
+ return res.data[key];
90
130
  }
91
131
 
92
- return res.data[key];
93
- }
132
+ return res as any;
133
+ };
134
+ } else {
135
+ client.models[name][operationPrefix] = async (
136
+ arg?: any,
137
+ options?: any
138
+ ) => {
139
+ const query = generateGraphQLDocument(
140
+ modelIntrospection.models,
141
+ name,
142
+ operation
143
+ );
144
+ const variables = buildGraphQLVariables(
145
+ model,
146
+ operation,
147
+ arg,
148
+ modelIntrospection
149
+ );
150
+
151
+ console.log(`API ${operationPrefix}`, query, variables);
152
+
153
+ const res = (await this.graphql({
154
+ query,
155
+ variables,
156
+ })) as any;
157
+
158
+ // flatten response
159
+ if (res.data !== undefined) {
160
+ const [key] = Object.keys(res.data);
161
+
162
+ // TODO: refactor to avoid destructuring here
163
+ const [initialized] = initializeModel(
164
+ client,
165
+ name,
166
+ [res.data[key]],
167
+ modelIntrospection
168
+ );
169
+
170
+ return initialized;
171
+ }
94
172
 
95
- return res;
96
- };
173
+ return res;
174
+ };
175
+ }
97
176
  }
98
177
  );
99
178
  }
@@ -102,170 +181,10 @@ export class APIClass extends InternalAPIClass {
102
181
  }
103
182
  }
104
183
 
105
- const graphQLOperationsInfo = {
106
- CREATE: { operationPrefix: 'create' as const, usePlural: false },
107
- READ: { operationPrefix: 'get' as const, usePlural: false },
108
- UPDATE: { operationPrefix: 'update' as const, usePlural: false },
109
- DELETE: { operationPrefix: 'delete' as const, usePlural: false },
110
- LIST: { operationPrefix: 'list' as const, usePlural: true },
111
- };
112
- type ModelOperation = keyof typeof graphQLOperationsInfo;
113
- type OperationPrefix =
114
- (typeof graphQLOperationsInfo)[ModelOperation]['operationPrefix'];
115
-
116
- const graphQLDocumentsCache = new Map<string, Map<ModelOperation, string>>();
117
-
118
- function generateGraphQLDocument(
119
- modelDefinition: any,
120
- modelOperation: ModelOperation
121
- ): string {
122
- const {
123
- name,
124
- pluralName,
125
- fields,
126
- primaryKeyInfo: {
127
- isCustomPrimaryKey,
128
- primaryKeyFieldName,
129
- sortKeyFieldNames,
130
- },
131
- } = modelDefinition;
132
- const { operationPrefix, usePlural } = graphQLOperationsInfo[modelOperation];
133
-
134
- const fromCache = graphQLDocumentsCache.get(name)?.get(modelOperation);
135
-
136
- if (fromCache !== undefined) {
137
- return fromCache;
138
- }
139
-
140
- if (!graphQLDocumentsCache.has(name)) {
141
- graphQLDocumentsCache.set(name, new Map());
142
- }
143
-
144
- const graphQLFieldName = `${operationPrefix}${usePlural ? pluralName : name}`;
145
- let graphQLOperationType: 'mutation' | 'query' | undefined;
146
- let graphQLSelectionSet: string | undefined;
147
- let graphQLArguments: Record<string, any> | undefined;
148
-
149
- const selectionSetFields = Object.values<any>(fields)
150
- .map(({ type, name }) => typeof type === 'string' && name) // Only scalars for now
151
- .filter(Boolean)
152
- .join(' ');
153
-
154
- switch (modelOperation) {
155
- case 'CREATE':
156
- case 'UPDATE':
157
- case 'DELETE':
158
- graphQLArguments ??
159
- (graphQLArguments = {
160
- input: `${
161
- operationPrefix.charAt(0).toLocaleUpperCase() +
162
- operationPrefix.slice(1)
163
- }${name}Input!`,
164
- });
165
- graphQLOperationType ?? (graphQLOperationType = 'mutation');
166
- case 'READ':
167
- graphQLArguments ??
168
- (graphQLArguments = isCustomPrimaryKey
169
- ? [primaryKeyFieldName, ...sortKeyFieldNames].reduce(
170
- (acc, fieldName) => {
171
- acc[fieldName] = fields[fieldName].type;
172
-
173
- return acc;
174
- },
175
- {}
176
- )
177
- : {
178
- [primaryKeyFieldName]: `${fields[primaryKeyFieldName].type}!`,
179
- });
180
- graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
181
- case 'LIST':
182
- graphQLOperationType ?? (graphQLOperationType = 'query');
183
- graphQLSelectionSet ??
184
- (graphQLSelectionSet = `items { ${selectionSetFields} }`);
185
- }
186
-
187
- const graphQLDocument = `${graphQLOperationType}${
188
- graphQLArguments
189
- ? `(${Object.entries(graphQLArguments).map(
190
- ([fieldName, type]) => `\$${fieldName}: ${type}`
191
- )})`
192
- : ''
193
- } { ${graphQLFieldName}${
194
- graphQLArguments
195
- ? `(${Object.keys(graphQLArguments).map(
196
- fieldName => `${fieldName}: \$${fieldName}`
197
- )})`
198
- : ''
199
- } { ${graphQLSelectionSet} } }`;
200
-
201
- graphQLDocumentsCache.get(name)?.set(modelOperation, graphQLDocument);
202
-
203
- return graphQLDocument;
204
- }
205
-
206
- function buildGraphQLVariables(
207
- modelDefinition: any,
208
- operation: ModelOperation,
209
- arg: any
210
- ): object {
211
- const {
212
- fields,
213
- primaryKeyInfo: {
214
- isCustomPrimaryKey,
215
- primaryKeyFieldName,
216
- sortKeyFieldNames,
217
- },
218
- } = modelDefinition;
219
-
220
- let variables = {};
221
-
222
- switch (operation) {
223
- case 'CREATE':
224
- variables = { input: arg };
225
- break;
226
- case 'UPDATE':
227
- // readonly fields are not updated
228
- variables = {
229
- input: Object.fromEntries(
230
- Object.entries(arg).filter(([fieldName]) => {
231
- const { isReadOnly } = fields[fieldName];
232
-
233
- return !isReadOnly;
234
- })
235
- ),
236
- };
237
- break;
238
- case 'READ':
239
- case 'DELETE':
240
- // only identifiers are sent
241
- variables = isCustomPrimaryKey
242
- ? [primaryKeyFieldName, ...sortKeyFieldNames].reduce(
243
- (acc, fieldName) => {
244
- acc[fieldName] = arg[fieldName];
245
-
246
- return acc;
247
- },
248
- {}
249
- )
250
- : { [primaryKeyFieldName]: arg[primaryKeyFieldName] };
251
-
252
- if (operation === 'DELETE') {
253
- variables = { input: variables };
254
- }
255
- break;
256
- case 'LIST':
257
- break;
258
- default:
259
- const exhaustiveCheck: never = operation;
260
- throw new Error(`Unhandled operation case: ${exhaustiveCheck}`);
261
- }
262
-
263
- return variables;
264
- }
265
-
266
184
  type FilteredKeys<T> = {
267
185
  [P in keyof T]: T[P] extends never ? never : P;
268
186
  }[keyof T];
187
+
269
188
  type ExcludeNeverFields<O> = {
270
189
  [K in FilteredKeys<O>]: O[K];
271
190
  };