@aws-amplify/data-schema 1.2.3 → 1.2.4
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/APIClient.js +85 -15
- package/dist/cjs/runtime/internals/APIClient.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/custom.js +10 -2
- package/dist/cjs/runtime/internals/operations/custom.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/get.js +2 -2
- package/dist/cjs/runtime/internals/operations/get.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/indexQuery.js +5 -4
- package/dist/cjs/runtime/internals/operations/indexQuery.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/list.js +2 -2
- package/dist/cjs/runtime/internals/operations/list.js.map +1 -1
- package/dist/cjs/runtime/internals/operations/subscription.js +1 -0
- package/dist/cjs/runtime/internals/operations/subscription.js.map +1 -1
- package/dist/esm/runtime/internals/APIClient.d.ts +41 -3
- package/dist/esm/runtime/internals/APIClient.mjs +85 -15
- package/dist/esm/runtime/internals/APIClient.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/custom.mjs +11 -3
- package/dist/esm/runtime/internals/operations/custom.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/get.mjs +2 -2
- package/dist/esm/runtime/internals/operations/get.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/indexQuery.mjs +5 -4
- package/dist/esm/runtime/internals/operations/indexQuery.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/list.mjs +2 -2
- package/dist/esm/runtime/internals/operations/list.mjs.map +1 -1
- package/dist/esm/runtime/internals/operations/subscription.mjs +1 -0
- package/dist/esm/runtime/internals/operations/subscription.mjs.map +1 -1
- package/dist/meta/cjs.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/runtime/internals/APIClient.ts +107 -21
- package/src/runtime/internals/operations/custom.ts +12 -3
- package/src/runtime/internals/operations/get.ts +2 -2
- package/src/runtime/internals/operations/indexQuery.ts +12 -2
- package/src/runtime/internals/operations/list.ts +8 -2
- package/src/runtime/internals/operations/subscription.ts +1 -0
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
GraphQLAuthMode,
|
|
12
12
|
ClientInternalsGetter,
|
|
13
13
|
ListArgs,
|
|
14
|
+
Field,
|
|
14
15
|
ModelFieldType,
|
|
15
16
|
ModelIntrospectionSchema,
|
|
16
17
|
NonModelFieldType,
|
|
@@ -72,32 +73,117 @@ const resolvedSkName = (sk: string[]): string => {
|
|
|
72
73
|
};
|
|
73
74
|
|
|
74
75
|
/**
|
|
76
|
+
* Crawls a model tree, starting with a given **individual** model instance record, looking
|
|
77
|
+
* for related hasMany children to extract from their `items` containers.
|
|
75
78
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
79
|
+
* E.g., if we have a record like this:
|
|
80
|
+
*
|
|
81
|
+
* ```js
|
|
82
|
+
* {
|
|
83
|
+
* id: 'some-id',
|
|
84
|
+
* children: {
|
|
85
|
+
* items: [
|
|
86
|
+
* { name: 'a' }
|
|
87
|
+
* { name: 'b' }
|
|
88
|
+
* { name: 'c' }
|
|
89
|
+
* ]
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* And if `children` refers to *an array of another model* (as opposed to a custom type),
|
|
95
|
+
* the `items` will be extracted. We do this because `items` is just the mechanism for nesting
|
|
96
|
+
* child records -- we don't want customers to have to dig the items out in application code.
|
|
97
|
+
* Ultimately, we return this "flattened" structure:
|
|
98
|
+
*
|
|
99
|
+
* ```js
|
|
100
|
+
* {
|
|
101
|
+
* id: 'some-id',
|
|
102
|
+
* children: [
|
|
103
|
+
* { name: 'a' }
|
|
104
|
+
* { name: 'b' }
|
|
105
|
+
* { name: 'c' }
|
|
106
|
+
* ]
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* Notably, an identical record could be the result of a nested custom type that contains an
|
|
111
|
+
* `items` property. This will *not* be flattened, because in that case the `items` property is
|
|
112
|
+
* actually part of the customer's schema. Similarly if a model contains an explicit `items` field.
|
|
113
|
+
*
|
|
114
|
+
* @param modelIntrospection Top-level model introspection schema.
|
|
115
|
+
* @param modelName The name of the model. Can be `undefined`. E.g., for customOperation return types.
|
|
116
|
+
* @param modelRecord The individual "model instance record" to normalize.
|
|
78
117
|
*/
|
|
79
|
-
export const flattenItems = (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
118
|
+
export const flattenItems = (
|
|
119
|
+
modelIntrospection: ModelIntrospectionSchema,
|
|
120
|
+
modelName: string | undefined,
|
|
121
|
+
modelRecord: Record<string, any>,
|
|
122
|
+
): Record<string, any> | null => {
|
|
123
|
+
if (!modelRecord) return null;
|
|
124
|
+
|
|
125
|
+
const mapped = {} as Record<string, any>;
|
|
126
|
+
for (const [fieldName, value] of Object.entries(modelRecord)) {
|
|
127
|
+
const fieldDef = modelName
|
|
128
|
+
? modelIntrospection.models[modelName]?.fields[fieldName]
|
|
129
|
+
: undefined;
|
|
130
|
+
const dvPair = { fieldDef, value };
|
|
131
|
+
if (isRelatedModelItemsArrayPair(dvPair)) {
|
|
132
|
+
mapped[fieldName] = dvPair.value.items.map((itemValue) =>
|
|
133
|
+
flattenItems(modelIntrospection, dvPair.fieldDef.type.model, itemValue),
|
|
134
|
+
);
|
|
135
|
+
} else if (isRelatedModelProperty(fieldDef)) {
|
|
136
|
+
mapped[fieldName] = flattenItems(
|
|
137
|
+
modelIntrospection,
|
|
138
|
+
fieldDef.type.model,
|
|
139
|
+
value,
|
|
140
|
+
);
|
|
141
|
+
} else {
|
|
142
|
+
mapped[fieldName] = value;
|
|
94
143
|
}
|
|
144
|
+
}
|
|
145
|
+
return mapped;
|
|
146
|
+
};
|
|
95
147
|
|
|
96
|
-
|
|
97
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Determines whether the given field definition and associated result value
|
|
150
|
+
* represent a related model array from a HasMany-type relationship.
|
|
151
|
+
*
|
|
152
|
+
* @param dv Pair of field definition and associated result value
|
|
153
|
+
* @returns
|
|
154
|
+
*/
|
|
155
|
+
function isRelatedModelItemsArrayPair(dv: {
|
|
156
|
+
fieldDef: Field | undefined;
|
|
157
|
+
value: any;
|
|
158
|
+
}): dv is {
|
|
159
|
+
fieldDef: Field & { type: ModelFieldType };
|
|
160
|
+
value: { items: Record<string, any>[] };
|
|
161
|
+
} {
|
|
162
|
+
return (
|
|
163
|
+
typeof dv.fieldDef?.type === 'object' &&
|
|
164
|
+
'model' in dv.fieldDef.type &&
|
|
165
|
+
typeof dv.fieldDef.type.model === 'string' &&
|
|
166
|
+
dv.fieldDef.isArray &&
|
|
167
|
+
Array.isArray(dv.value?.items)
|
|
168
|
+
);
|
|
169
|
+
}
|
|
98
170
|
|
|
99
|
-
|
|
100
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Determines whether the given field definition represents a relationship
|
|
173
|
+
* to another model.
|
|
174
|
+
*
|
|
175
|
+
* @param fieldDef
|
|
176
|
+
* @returns
|
|
177
|
+
*/
|
|
178
|
+
function isRelatedModelProperty(
|
|
179
|
+
fieldDef: Field | undefined,
|
|
180
|
+
): fieldDef is Field & { type: ModelFieldType } {
|
|
181
|
+
return (
|
|
182
|
+
typeof fieldDef?.type === 'object' &&
|
|
183
|
+
'model' in fieldDef.type &&
|
|
184
|
+
typeof fieldDef.type.model === 'string'
|
|
185
|
+
);
|
|
186
|
+
}
|
|
101
187
|
|
|
102
188
|
// TODO: this should accept single result to support CRUD methods; create helper for array/list
|
|
103
189
|
export function initializeModel(
|
|
@@ -20,7 +20,6 @@ import { map } from 'rxjs';
|
|
|
20
20
|
import {
|
|
21
21
|
authModeParams,
|
|
22
22
|
getDefaultSelectionSetForNonModelWithIR,
|
|
23
|
-
flattenItems,
|
|
24
23
|
generateSelectionSet,
|
|
25
24
|
getCustomHeaders,
|
|
26
25
|
initializeModel,
|
|
@@ -398,7 +397,12 @@ async function _op(
|
|
|
398
397
|
// flatten response
|
|
399
398
|
if (data) {
|
|
400
399
|
const [key] = Object.keys(data);
|
|
401
|
-
|
|
400
|
+
|
|
401
|
+
// TODO: when adding support for custom selection set, flattening will need
|
|
402
|
+
// to occur recursively. For now, it's expected that related models are not
|
|
403
|
+
// present in the result. Only FK's are present. Any related model properties
|
|
404
|
+
// should be replaced with lazy loaders under the current implementation.
|
|
405
|
+
const flattenedResult = data[key];
|
|
402
406
|
|
|
403
407
|
// TODO: custom selection set. current selection set is default selection set only
|
|
404
408
|
// custom selection set requires data-schema-type + runtime updates above.
|
|
@@ -433,7 +437,12 @@ async function _op(
|
|
|
433
437
|
*/
|
|
434
438
|
if (data && Object.keys(data).length !== 0 && errors) {
|
|
435
439
|
const [key] = Object.keys(data);
|
|
436
|
-
|
|
440
|
+
|
|
441
|
+
// TODO: when adding support for custom selection set, flattening will need
|
|
442
|
+
// to occur recursively. For now, it's expected that related models are not
|
|
443
|
+
// present in the result. Only FK's are present. Any related model properties
|
|
444
|
+
// should be replaced with lazy loaders under the current implementation.
|
|
445
|
+
const flattenedResult = data[key];
|
|
437
446
|
|
|
438
447
|
/**
|
|
439
448
|
* `flattenedResult` could be `null` here (e.g. `data: { getPost: null }`)
|
|
@@ -119,7 +119,7 @@ async function _get(
|
|
|
119
119
|
// flatten response
|
|
120
120
|
if (data) {
|
|
121
121
|
const [key] = Object.keys(data);
|
|
122
|
-
const flattenedResult = flattenItems(data
|
|
122
|
+
const flattenedResult = flattenItems(modelIntrospection, name, data[key]);
|
|
123
123
|
|
|
124
124
|
if (flattenedResult === null) {
|
|
125
125
|
return { data: null, extensions };
|
|
@@ -157,7 +157,7 @@ async function _get(
|
|
|
157
157
|
*/
|
|
158
158
|
if (data && Object.keys(data).length !== 0 && errors) {
|
|
159
159
|
const [key] = Object.keys(data);
|
|
160
|
-
const flattenedResult = flattenItems(data
|
|
160
|
+
const flattenedResult = flattenItems(modelIntrospection, name, data[key]);
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
163
|
* `flattenedResult` could be `null` here (e.g. `data: { getPost: null }`)
|
|
@@ -74,6 +74,8 @@ export function indexQueryFactory(
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
function processGraphQlResponse(
|
|
77
|
+
modelIntroSchema: ModelIntrospectionSchema,
|
|
78
|
+
modelName: string,
|
|
77
79
|
result: GraphQLResult,
|
|
78
80
|
selectionSet: undefined | string[],
|
|
79
81
|
modelInitializer: (flattenedResult: any[]) => any[],
|
|
@@ -83,7 +85,9 @@ function processGraphQlResponse(
|
|
|
83
85
|
const [key] = Object.keys(data);
|
|
84
86
|
|
|
85
87
|
if (data[key].items) {
|
|
86
|
-
const flattenedResult =
|
|
88
|
+
const flattenedResult = data[key].items.map((value: Record<string, any>) =>
|
|
89
|
+
flattenItems(modelIntroSchema, modelName, value),
|
|
90
|
+
);
|
|
87
91
|
|
|
88
92
|
return {
|
|
89
93
|
data: selectionSet ? flattenedResult : modelInitializer(flattenedResult),
|
|
@@ -92,6 +96,7 @@ function processGraphQlResponse(
|
|
|
92
96
|
};
|
|
93
97
|
}
|
|
94
98
|
|
|
99
|
+
// Index queries are always list queries. No `items`? No flattening needed.
|
|
95
100
|
return {
|
|
96
101
|
data: data[key],
|
|
97
102
|
nextToken: data[key].nextToken,
|
|
@@ -159,6 +164,8 @@ async function _indexQuery(
|
|
|
159
164
|
|
|
160
165
|
if (response.data !== undefined) {
|
|
161
166
|
return processGraphQlResponse(
|
|
167
|
+
modelIntrospection,
|
|
168
|
+
name,
|
|
162
169
|
response,
|
|
163
170
|
args?.selectionSet,
|
|
164
171
|
modelInitializer,
|
|
@@ -181,7 +188,10 @@ async function _indexQuery(
|
|
|
181
188
|
const [key] = Object.keys(data);
|
|
182
189
|
|
|
183
190
|
if (data[key]?.items) {
|
|
184
|
-
const flattenedResult =
|
|
191
|
+
const flattenedResult = data[key]?.items.map(
|
|
192
|
+
(value: Record<string, any>) =>
|
|
193
|
+
flattenItems(modelIntrospection, name, value),
|
|
194
|
+
);
|
|
185
195
|
|
|
186
196
|
/**
|
|
187
197
|
* Check exists since `flattenedResult` could be `null`.
|
|
@@ -99,7 +99,10 @@ async function _list(
|
|
|
99
99
|
const [key] = Object.keys(data);
|
|
100
100
|
|
|
101
101
|
if (data[key].items) {
|
|
102
|
-
const flattenedResult =
|
|
102
|
+
const flattenedResult = data[key].items.map(
|
|
103
|
+
(value: Record<string, any>) =>
|
|
104
|
+
flattenItems(modelIntrospection, name, value),
|
|
105
|
+
);
|
|
103
106
|
|
|
104
107
|
// don't init if custom selection set
|
|
105
108
|
if (args?.selectionSet) {
|
|
@@ -153,7 +156,10 @@ async function _list(
|
|
|
153
156
|
const [key] = Object.keys(data);
|
|
154
157
|
|
|
155
158
|
if (data[key]?.items) {
|
|
156
|
-
const flattenedResult =
|
|
159
|
+
const flattenedResult = data[key].items.map(
|
|
160
|
+
(value: Record<string, any>) =>
|
|
161
|
+
flattenItems(modelIntrospection, name, value),
|
|
162
|
+
);
|
|
157
163
|
|
|
158
164
|
/**
|
|
159
165
|
* Check exists since `flattenedResult` could be `null`.
|
|
@@ -59,6 +59,7 @@ export function subscriptionFactory(
|
|
|
59
59
|
return observable.pipe(
|
|
60
60
|
map((value) => {
|
|
61
61
|
const [key] = Object.keys(value.data);
|
|
62
|
+
// Will need flattening here if/when custom selection set support is added:
|
|
62
63
|
const data = (value.data as any)[key];
|
|
63
64
|
const [initialized] = initializeModel(
|
|
64
65
|
client,
|