@aws-amplify/data-schema 0.16.1 → 0.17.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/dist/cjs/runtime/internals/operations/custom.js +33 -5
- package/dist/cjs/runtime/internals/operations/custom.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/get.js +36 -6
- package/dist/cjs/runtime/internals/operations/get.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/indexQuery.js +39 -11
- package/dist/cjs/runtime/internals/operations/indexQuery.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/list.js +50 -6
- package/dist/cjs/runtime/internals/operations/list.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/utils.js +42 -0
- package/dist/cjs/runtime/internals/operations/utils.js.map +1 -0
- package/dist/esm/Authorization.d.ts +2 -2
- package/dist/esm/MappedTypes/CustomOperations.d.ts +4 -4
- package/dist/esm/MappedTypes/ResolveFieldProperties.d.ts +2 -2
- package/dist/esm/ModelRelationalField.d.ts +1 -1
- package/dist/esm/runtime/internals/operations/custom.mjs +33 -5
- package/dist/esm/runtime/internals/operations/custom.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/get.mjs +36 -6
- package/dist/esm/runtime/internals/operations/get.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/indexQuery.mjs +39 -11
- package/dist/esm/runtime/internals/operations/indexQuery.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/list.mjs +50 -6
- package/dist/esm/runtime/internals/operations/list.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/utils.d.ts +8 -0
- package/dist/esm/runtime/internals/operations/utils.mjs +38 -0
- package/dist/esm/runtime/internals/operations/utils.mjs.map +1 -0
- package/dist/meta/cjs.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/MappedTypes/CustomOperations.ts +23 -22
- package/src/MappedTypes/ResolveFieldProperties.ts +2 -2
- package/src/runtime/internals/operations/custom.ts +44 -5
- package/src/runtime/internals/operations/get.ts +47 -7
- package/src/runtime/internals/operations/indexQuery.ts +43 -11
- package/src/runtime/internals/operations/list.ts +63 -7
- package/src/runtime/internals/operations/utils.ts +35 -0
package/package.json
CHANGED
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
import type { ModelField } from '../ModelField';
|
|
8
8
|
import type { RefType, RefTypeParamShape } from '../RefType';
|
|
9
9
|
import type {
|
|
10
|
-
|
|
10
|
+
ResolveFieldRequirements,
|
|
11
11
|
ResolveRefsOfCustomType,
|
|
12
12
|
ResolveRefValueArrayTraits,
|
|
13
13
|
} from './ResolveFieldProperties';
|
|
@@ -66,7 +66,7 @@ export type CustomOpShapes<Schema extends GenericModelSchema<any>> = {
|
|
|
66
66
|
export type CustomOpArguments<Shape extends CustomOperationParamShape> =
|
|
67
67
|
Shape['arguments'] extends null
|
|
68
68
|
? never
|
|
69
|
-
: {
|
|
69
|
+
: ResolveFieldRequirements<{
|
|
70
70
|
[FieldName in keyof Shape['arguments']]: Shape['arguments'][FieldName] extends ModelField<
|
|
71
71
|
infer R,
|
|
72
72
|
any,
|
|
@@ -74,7 +74,7 @@ export type CustomOpArguments<Shape extends CustomOperationParamShape> =
|
|
|
74
74
|
>
|
|
75
75
|
? R
|
|
76
76
|
: never;
|
|
77
|
-
}
|
|
77
|
+
}>;
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
80
|
* Computes the return type from the `returnType` of a custom operation shape.
|
|
@@ -106,12 +106,12 @@ export type CustomOpReturnType<
|
|
|
106
106
|
? R
|
|
107
107
|
: Shape['returnType'] extends CustomType<infer R>
|
|
108
108
|
?
|
|
109
|
-
|
|
|
109
|
+
| ResolveFieldRequirements<
|
|
110
110
|
FieldTypesOfCustomType<{
|
|
111
111
|
thisCustomType: R['fields'];
|
|
112
112
|
}>['thisCustomType']
|
|
113
113
|
> // The inline `.customType()` with a custom operation doesn't have
|
|
114
|
-
|
|
114
|
+
// `.required()` modifier, hence it's nullable
|
|
115
115
|
| null
|
|
116
116
|
: never;
|
|
117
117
|
|
|
@@ -237,20 +237,21 @@ export type CustomOperationHandlerTypes<
|
|
|
237
237
|
*
|
|
238
238
|
* (Custom handlers should not return lazy loaded fields -- they're *lazy loaded*.)
|
|
239
239
|
*/
|
|
240
|
-
type LambdaReturnType<T> =
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
T,
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
240
|
+
type LambdaReturnType<T> =
|
|
241
|
+
T extends Record<string, any>
|
|
242
|
+
? {
|
|
243
|
+
// Return type can include `null | undefined`, which we can't meaningfully
|
|
244
|
+
// map over.
|
|
245
|
+
[K in keyof Exclude<T, null | undefined> as Exclude<
|
|
246
|
+
T,
|
|
247
|
+
null | undefined
|
|
248
|
+
>[K] extends (...args: any) => any
|
|
249
|
+
? never
|
|
250
|
+
: K]: Exclude<T, null | undefined>[K];
|
|
251
|
+
}
|
|
252
|
+
:
|
|
253
|
+
| T
|
|
254
|
+
// If the original return type allowed null | undefined, mix them back into
|
|
255
|
+
// the final return type
|
|
256
|
+
| (null extends T ? null : never)
|
|
257
|
+
| (undefined extends T ? undefined : never);
|
|
@@ -138,10 +138,10 @@ export type ResolveRefsOfCustomType<
|
|
|
138
138
|
? ResolveRef<NonModelTypes, R>
|
|
139
139
|
: T[Prop];
|
|
140
140
|
} extends infer Resolved
|
|
141
|
-
?
|
|
141
|
+
? ResolveFieldRequirements<Resolved>
|
|
142
142
|
: never;
|
|
143
143
|
|
|
144
|
-
export type
|
|
144
|
+
export type ResolveFieldRequirements<Resolved> = Intersection<
|
|
145
145
|
ExtractNullableFieldsToOptionalFields<Resolved>,
|
|
146
146
|
ExtractNonNullableFieldsToRequiredFields<Resolved>
|
|
147
147
|
>;
|
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
selectionSetIRToString,
|
|
28
28
|
} from '../APIClient';
|
|
29
29
|
|
|
30
|
+
import { handleSingularGraphQlError } from './utils';
|
|
31
|
+
|
|
30
32
|
type CustomOperationOptions = AuthModeParams & ListArgs;
|
|
31
33
|
|
|
32
34
|
// these are the 4 possible sets of arguments custom operations methods can receive
|
|
@@ -417,12 +419,49 @@ async function _op(
|
|
|
417
419
|
return { data: null, extensions };
|
|
418
420
|
}
|
|
419
421
|
} catch (error: any) {
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
422
|
+
/**
|
|
423
|
+
* The `data` type returned by `error` here could be:
|
|
424
|
+
* 1) `null`
|
|
425
|
+
* 2) an empty object
|
|
426
|
+
* 3) "populated" but with a `null` value `{ getPost: null }`
|
|
427
|
+
* 4) an actual record `{ getPost: { id: '1', title: 'Hello, World!' } }`
|
|
428
|
+
*/
|
|
429
|
+
const { data, errors } = error;
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* `data` is not `null`, and is not an empty object:
|
|
433
|
+
*/
|
|
434
|
+
if (data && Object.keys(data).length !== 0 && errors) {
|
|
435
|
+
const [key] = Object.keys(data);
|
|
436
|
+
const flattenedResult = flattenItems(data)[key];
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* `flattenedResult` could be `null` here (e.g. `data: { getPost: null }`)
|
|
440
|
+
* if `flattenedResult`, result is an actual record:
|
|
441
|
+
*/
|
|
442
|
+
if (flattenedResult) {
|
|
443
|
+
// TODO: custom selection set. current selection set is default selection set only
|
|
444
|
+
// custom selection set requires data-schema-type + runtime updates above.
|
|
445
|
+
const [initialized] = returnTypeModelName
|
|
446
|
+
? initializeModel(
|
|
447
|
+
client,
|
|
448
|
+
returnTypeModelName,
|
|
449
|
+
[flattenedResult],
|
|
450
|
+
modelIntrospection,
|
|
451
|
+
auth.authMode,
|
|
452
|
+
auth.authToken,
|
|
453
|
+
!!context,
|
|
454
|
+
)
|
|
455
|
+
: [flattenedResult];
|
|
456
|
+
|
|
457
|
+
return { data: initialized, errors };
|
|
458
|
+
} else {
|
|
459
|
+
// was `data: { getPost: null }`)
|
|
460
|
+
return handleSingularGraphQlError(error);
|
|
461
|
+
}
|
|
423
462
|
} else {
|
|
424
|
-
//
|
|
425
|
-
|
|
463
|
+
// `data` is `null`:
|
|
464
|
+
return handleSingularGraphQlError(error);
|
|
426
465
|
}
|
|
427
466
|
}
|
|
428
467
|
}
|
|
@@ -25,6 +25,8 @@ import {
|
|
|
25
25
|
initializeModel,
|
|
26
26
|
} from '../APIClient';
|
|
27
27
|
|
|
28
|
+
import { handleSingularGraphQlError } from './utils';
|
|
29
|
+
|
|
28
30
|
export function getFactory(
|
|
29
31
|
client: BaseClient,
|
|
30
32
|
modelIntrospection: ModelIntrospectionSchema,
|
|
@@ -90,9 +92,9 @@ async function _get(
|
|
|
90
92
|
modelIntrospection,
|
|
91
93
|
);
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
const auth = authModeParams(client, getInternals, options);
|
|
95
|
+
const auth = authModeParams(client, getInternals, options);
|
|
95
96
|
|
|
97
|
+
try {
|
|
96
98
|
const headers = getCustomHeaders(client, getInternals, options?.headers);
|
|
97
99
|
|
|
98
100
|
const { data, extensions } = context
|
|
@@ -139,12 +141,50 @@ async function _get(
|
|
|
139
141
|
return { data: null, extensions };
|
|
140
142
|
}
|
|
141
143
|
} catch (error: any) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
144
|
+
/**
|
|
145
|
+
* The `data` type returned by `error` here could be:
|
|
146
|
+
* 1) `null`
|
|
147
|
+
* 2) an empty object
|
|
148
|
+
* 3) "populated" but with a `null` value `{ getPost: null }`
|
|
149
|
+
* 4) an actual record `{ getPost: { id: '1', title: 'Hello, World!' } }`
|
|
150
|
+
*/
|
|
151
|
+
const { data, errors } = error;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* `data` is not `null`, and is not an empty object:
|
|
155
|
+
*/
|
|
156
|
+
if (data && Object.keys(data).length !== 0 && errors) {
|
|
157
|
+
const [key] = Object.keys(data);
|
|
158
|
+
const flattenedResult = flattenItems(data)[key];
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* `flattenedResult` could be `null` here (e.g. `data: { getPost: null }`)
|
|
162
|
+
* if `flattenedResult`, result is an actual record:
|
|
163
|
+
*/
|
|
164
|
+
if (flattenedResult) {
|
|
165
|
+
if (options?.selectionSet) {
|
|
166
|
+
return { data: flattenedResult, errors };
|
|
167
|
+
} else {
|
|
168
|
+
// TODO: refactor to avoid destructuring here
|
|
169
|
+
const [initialized] = initializeModel(
|
|
170
|
+
client,
|
|
171
|
+
name,
|
|
172
|
+
[flattenedResult],
|
|
173
|
+
modelIntrospection,
|
|
174
|
+
auth.authMode,
|
|
175
|
+
auth.authToken,
|
|
176
|
+
!!context,
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
return { data: initialized, errors };
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
// was `data: { getPost: null }`)
|
|
183
|
+
return handleSingularGraphQlError(error);
|
|
184
|
+
}
|
|
145
185
|
} else {
|
|
146
|
-
//
|
|
147
|
-
|
|
186
|
+
// `data` is `null`:
|
|
187
|
+
return handleSingularGraphQlError(error);
|
|
148
188
|
}
|
|
149
189
|
}
|
|
150
190
|
}
|
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
initializeModel,
|
|
22
22
|
} from '../APIClient';
|
|
23
23
|
|
|
24
|
+
import { handleListGraphQlError } from './utils';
|
|
25
|
+
|
|
24
26
|
export interface IndexMeta {
|
|
25
27
|
queryField: string;
|
|
26
28
|
pk: string;
|
|
@@ -97,16 +99,6 @@ function processGraphQlResponse(
|
|
|
97
99
|
};
|
|
98
100
|
}
|
|
99
101
|
|
|
100
|
-
function handleGraphQlError(error: any) {
|
|
101
|
-
if (error.errors) {
|
|
102
|
-
// graphql errors pass through
|
|
103
|
-
return error as any;
|
|
104
|
-
} else {
|
|
105
|
-
// non-graphql errors re re-thrown
|
|
106
|
-
throw error;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
102
|
async function _indexQuery(
|
|
111
103
|
client: BaseClient,
|
|
112
104
|
modelIntrospection: ModelIntrospectionSchema,
|
|
@@ -173,6 +165,46 @@ async function _indexQuery(
|
|
|
173
165
|
);
|
|
174
166
|
}
|
|
175
167
|
} catch (error: any) {
|
|
176
|
-
|
|
168
|
+
/**
|
|
169
|
+
* The `data` type returned by `error` here could be:
|
|
170
|
+
* 1) `null`
|
|
171
|
+
* 2) an empty object
|
|
172
|
+
* 3) "populated" but with a `null` value:
|
|
173
|
+
* `data: { listByExampleId: null }`
|
|
174
|
+
* 4) an actual record:
|
|
175
|
+
* `data: { listByExampleId: items: [{ id: '1', ...etc } }]`
|
|
176
|
+
*/
|
|
177
|
+
const { data, errors } = error;
|
|
178
|
+
|
|
179
|
+
// `data` is not `null`, and is not an empty object:
|
|
180
|
+
if (data !== undefined && Object.keys(data).length !== 0 && errors) {
|
|
181
|
+
const [key] = Object.keys(data);
|
|
182
|
+
|
|
183
|
+
if (data[key]?.items) {
|
|
184
|
+
const flattenedResult = flattenItems(data)[key];
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check exists since `flattenedResult` could be `null`.
|
|
188
|
+
* if `flattenedResult` exists, result is an actual record.
|
|
189
|
+
*/
|
|
190
|
+
if (flattenedResult) {
|
|
191
|
+
return {
|
|
192
|
+
data: args?.selectionSet
|
|
193
|
+
? flattenedResult
|
|
194
|
+
: modelInitializer(flattenedResult),
|
|
195
|
+
nextToken: data[key]?.nextToken,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// response is of type `data: { listByExampleId: null }`
|
|
201
|
+
return {
|
|
202
|
+
data: data[key],
|
|
203
|
+
nextToken: data[key]?.nextToken,
|
|
204
|
+
};
|
|
205
|
+
} else {
|
|
206
|
+
// `data` is `null` or an empty object:
|
|
207
|
+
return handleListGraphQlError(error);
|
|
208
|
+
}
|
|
177
209
|
}
|
|
178
210
|
}
|
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
initializeModel,
|
|
23
23
|
} from '../APIClient';
|
|
24
24
|
|
|
25
|
+
import { handleListGraphQlError } from './utils';
|
|
26
|
+
|
|
25
27
|
export function listFactory(
|
|
26
28
|
client: BaseClient,
|
|
27
29
|
modelIntrospection: ModelIntrospectionSchema,
|
|
@@ -68,9 +70,9 @@ async function _list(
|
|
|
68
70
|
modelIntrospection,
|
|
69
71
|
);
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
const auth = authModeParams(client, getInternals, args);
|
|
73
|
+
const auth = authModeParams(client, getInternals, args);
|
|
73
74
|
|
|
75
|
+
try {
|
|
74
76
|
const headers = getCustomHeaders(client, getInternals, args?.headers);
|
|
75
77
|
|
|
76
78
|
const { data, extensions } = contextSpec
|
|
@@ -132,12 +134,66 @@ async function _list(
|
|
|
132
134
|
};
|
|
133
135
|
}
|
|
134
136
|
} catch (error: any) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
/**
|
|
138
|
+
* The `data` type returned by `error` here could be:
|
|
139
|
+
* 1) `null`
|
|
140
|
+
* 2) an empty object
|
|
141
|
+
* 3) "populated" but with a `null` value `data: { listPosts: null }`
|
|
142
|
+
* 4) actual records `data: { listPosts: items: [{ id: '1', ...etc }] }`
|
|
143
|
+
*/
|
|
144
|
+
const { data, errors } = error;
|
|
145
|
+
|
|
146
|
+
// `data` is not `null`, and is not an empty object:
|
|
147
|
+
if (data !== undefined && Object.keys(data).length !== 0 && errors) {
|
|
148
|
+
const [key] = Object.keys(data);
|
|
149
|
+
|
|
150
|
+
if (data[key]?.items) {
|
|
151
|
+
const flattenedResult = flattenItems(data)[key];
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check exists since `flattenedResult` could be `null`.
|
|
155
|
+
* if `flattenedResult` exists, result is an actual record.
|
|
156
|
+
*/
|
|
157
|
+
if (flattenedResult) {
|
|
158
|
+
// don't init if custom selection set
|
|
159
|
+
if (args?.selectionSet) {
|
|
160
|
+
return {
|
|
161
|
+
data: flattenedResult,
|
|
162
|
+
nextToken: data[key]?.nextToken,
|
|
163
|
+
errors,
|
|
164
|
+
};
|
|
165
|
+
} else {
|
|
166
|
+
const initialized = initializeModel(
|
|
167
|
+
client,
|
|
168
|
+
name,
|
|
169
|
+
flattenedResult,
|
|
170
|
+
modelIntrospection,
|
|
171
|
+
auth.authMode,
|
|
172
|
+
auth.authToken,
|
|
173
|
+
!!contextSpec,
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// data is full record w/out selection set:
|
|
177
|
+
return {
|
|
178
|
+
data: initialized,
|
|
179
|
+
nextToken: data[key]?.nextToken,
|
|
180
|
+
errors,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
data: data[key],
|
|
187
|
+
nextToken: data[key]?.nextToken,
|
|
188
|
+
errors,
|
|
189
|
+
};
|
|
190
|
+
} else {
|
|
191
|
+
// response is of type `data: { getPost: null }`)
|
|
192
|
+
return handleListGraphQlError(error);
|
|
193
|
+
}
|
|
138
194
|
} else {
|
|
139
|
-
//
|
|
140
|
-
|
|
195
|
+
// `data` is `null` or an empty object:
|
|
196
|
+
return handleListGraphQlError(error);
|
|
141
197
|
}
|
|
142
198
|
}
|
|
143
199
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
// import { GraphQLFormattedError } from '@aws-amplify/data-schema-types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Handle errors for list return types (list and index query operations)
|
|
7
|
+
*/
|
|
8
|
+
export function handleListGraphQlError(error: any) {
|
|
9
|
+
if (error?.errors) {
|
|
10
|
+
// graphql errors pass through
|
|
11
|
+
return {
|
|
12
|
+
...error,
|
|
13
|
+
data: [],
|
|
14
|
+
} as any;
|
|
15
|
+
} else {
|
|
16
|
+
// non-graphql errors are re-thrown
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Handle errors for singular return types (create, get, update, delete operations)
|
|
23
|
+
*/
|
|
24
|
+
export function handleSingularGraphQlError(error: any) {
|
|
25
|
+
if (error.errors) {
|
|
26
|
+
// graphql errors pass through
|
|
27
|
+
return {
|
|
28
|
+
...error,
|
|
29
|
+
data: null,
|
|
30
|
+
} as any;
|
|
31
|
+
} else {
|
|
32
|
+
// non-graphql errors are re-thrown
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|