@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/lib/API.d.ts +3 -3
- package/lib/API.js +67 -131
- package/lib/APIClient.d.ts +46 -0
- package/lib/APIClient.js +334 -0
- package/lib/index.js +6 -6
- package/lib/internals/InternalAPI.js +1 -1
- package/lib/internals/index.js +3 -3
- package/lib/tsconfig.build.tsbuildinfo +1 -0
- package/lib/types/index.js +4 -4
- package/lib-esm/API.d.ts +3 -3
- package/lib-esm/API.js +66 -131
- package/lib-esm/APIClient.d.ts +46 -0
- package/lib-esm/APIClient.js +327 -0
- package/lib-esm/index.js +0 -1
- package/lib-esm/internals/InternalAPI.js +0 -1
- package/lib-esm/internals/index.js +0 -1
- package/lib-esm/tsconfig.build.tsbuildinfo +1 -0
- package/lib-esm/types/index.js +0 -1
- package/package.json +13 -10
- package/src/API.ts +101 -182
- package/src/APIClient.ts +433 -0
- package/lib/.tsbuildinfo +0 -3
- package/lib/API.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/internals/InternalAPI.js.map +0 -1
- package/lib/internals/index.js.map +0 -1
- package/lib/types/index.js.map +0 -1
- package/lib-esm/.tsbuildinfo +0 -3
- package/lib-esm/API.js.map +0 -1
- package/lib-esm/index.js.map +0 -1
- package/lib-esm/internals/InternalAPI.js.map +0 -1
- package/lib-esm/internals/index.js.map +0 -1
- package/lib-esm/types/index.js.map +0 -1
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
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
|
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
|
-
|
|
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
|
};
|