@aws-amplify/api-graphql 4.0.1-api-v6-models.9493d4d.0 → 4.0.1-api-v6-models.c1977f8.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/internals/APIClient.d.ts +6 -1
- package/lib/internals/APIClient.js +30 -6
- package/lib/internals/InternalGraphQLAPI.js +1 -1
- package/lib/internals/generateModelsProperty.js +176 -22
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/utils/findIndexByFields.d.ts +9 -0
- package/lib/utils/findIndexByFields.js +28 -0
- package/lib/utils/index.d.ts +2 -0
- package/lib/utils/index.js +5 -1
- package/lib/utils/resolvePKFields.d.ts +13 -0
- package/lib/utils/resolvePKFields.js +16 -0
- package/lib-esm/internals/APIClient.d.ts +6 -1
- package/lib-esm/internals/APIClient.js +30 -6
- package/lib-esm/internals/InternalGraphQLAPI.js +1 -1
- package/lib-esm/internals/generateModelsProperty.js +178 -24
- package/lib-esm/tsconfig.tsbuildinfo +1 -1
- package/lib-esm/utils/findIndexByFields.d.ts +9 -0
- package/lib-esm/utils/findIndexByFields.js +24 -0
- package/lib-esm/utils/index.d.ts +2 -0
- package/lib-esm/utils/index.js +2 -0
- package/lib-esm/utils/resolvePKFields.d.ts +13 -0
- package/lib-esm/utils/resolvePKFields.js +12 -0
- package/package.json +5 -5
- package/src/internals/APIClient.ts +51 -10
- package/src/internals/InternalGraphQLAPI.ts +1 -1
- package/src/internals/generateModelsProperty.ts +169 -9
- package/src/utils/findIndexByFields.ts +29 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/resolvePKFields.ts +22 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Iterates through a collection to find a matching item and returns the index.
|
|
3
|
+
*
|
|
4
|
+
* @param needle The item to search for
|
|
5
|
+
* @param haystack The collection to search
|
|
6
|
+
* @param keyFields The fields used to indicate a match
|
|
7
|
+
* @returns Index of `needle` in `haystack`, otherwise -1 if not found.
|
|
8
|
+
*/
|
|
9
|
+
export declare function findIndexByFields<T>(needle: T, haystack: T[], keyFields: Array<keyof T>): number;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Iterates through a collection to find a matching item and returns the index.
|
|
5
|
+
*
|
|
6
|
+
* @param needle The item to search for
|
|
7
|
+
* @param haystack The collection to search
|
|
8
|
+
* @param keyFields The fields used to indicate a match
|
|
9
|
+
* @returns Index of `needle` in `haystack`, otherwise -1 if not found.
|
|
10
|
+
*/
|
|
11
|
+
export function findIndexByFields(needle, haystack, keyFields) {
|
|
12
|
+
var searchObject = Object.fromEntries(keyFields.map(function (fieldName) { return [fieldName, needle[fieldName]]; }));
|
|
13
|
+
var _loop_1 = function (i) {
|
|
14
|
+
if (Object.keys(searchObject).every(function (k) { return searchObject[k] === haystack[i][k]; })) {
|
|
15
|
+
return { value: i };
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
for (var i = 0; i < haystack.length; i++) {
|
|
19
|
+
var state_1 = _loop_1(i);
|
|
20
|
+
if (typeof state_1 === "object")
|
|
21
|
+
return state_1.value;
|
|
22
|
+
}
|
|
23
|
+
return -1;
|
|
24
|
+
}
|
package/lib-esm/utils/index.d.ts
CHANGED
package/lib-esm/utils/index.js
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ResourcesConfig } from '@aws-amplify/core';
|
|
2
|
+
type GraphQLConfig = Exclude<ResourcesConfig['API'], undefined>['GraphQL'];
|
|
3
|
+
type ModelIntrospectionSchema = Exclude<Exclude<GraphQLConfig, undefined>['modelIntrospection'], undefined>;
|
|
4
|
+
type SchemaModel = ModelIntrospectionSchema['models'][string];
|
|
5
|
+
/**
|
|
6
|
+
* Given a SchemaModel from a ModelIntrospectionSchema, returns the primary key
|
|
7
|
+
* as an array of field names.
|
|
8
|
+
*
|
|
9
|
+
* @param model The model object
|
|
10
|
+
* @returns Array of field names
|
|
11
|
+
*/
|
|
12
|
+
export declare function resolvePKFields(model: SchemaModel): string[];
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { __read, __spreadArray } from "tslib";
|
|
2
|
+
/**
|
|
3
|
+
* Given a SchemaModel from a ModelIntrospectionSchema, returns the primary key
|
|
4
|
+
* as an array of field names.
|
|
5
|
+
*
|
|
6
|
+
* @param model The model object
|
|
7
|
+
* @returns Array of field names
|
|
8
|
+
*/
|
|
9
|
+
export function resolvePKFields(model) {
|
|
10
|
+
var _a = model.primaryKeyInfo, primaryKeyFieldName = _a.primaryKeyFieldName, sortKeyFieldNames = _a.sortKeyFieldNames;
|
|
11
|
+
return __spreadArray([primaryKeyFieldName], __read(sortKeyFieldNames), false);
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-amplify/api-graphql",
|
|
3
|
-
"version": "4.0.1-api-v6-models.
|
|
3
|
+
"version": "4.0.1-api-v6-models.c1977f8.0+c1977f8",
|
|
4
4
|
"description": "Api-graphql category of aws-amplify",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"module": "./lib-esm/index.js",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
],
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@aws-amplify/amplify-api-next-types-alpha": "^0.2.0",
|
|
55
|
-
"@aws-amplify/api-rest": "4.0.1-api-v6-models.
|
|
56
|
-
"@aws-amplify/auth": "6.0.1-api-v6-models.
|
|
57
|
-
"@aws-amplify/core": "6.0.1-api-v6-models.
|
|
55
|
+
"@aws-amplify/api-rest": "4.0.1-api-v6-models.c1977f8.0+c1977f8",
|
|
56
|
+
"@aws-amplify/auth": "6.0.1-api-v6-models.c1977f8.0+c1977f8",
|
|
57
|
+
"@aws-amplify/core": "6.0.1-api-v6-models.c1977f8.0+c1977f8",
|
|
58
58
|
"@aws-sdk/types": "3.387.0",
|
|
59
59
|
"graphql": "15.8.0",
|
|
60
60
|
"rxjs": "^7.8.1",
|
|
@@ -126,5 +126,5 @@
|
|
|
126
126
|
"<rootDir>/__tests__"
|
|
127
127
|
]
|
|
128
128
|
},
|
|
129
|
-
"gitHead": "
|
|
129
|
+
"gitHead": "c1977f8efaae41b693495a2d6c53c503d0038e95"
|
|
130
130
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
2
|
// SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
import { resolveOwnerFields } from '../utils/resolveOwnerFields';
|
|
4
|
+
import { GraphQLAuthMode } from '@aws-amplify/core/internals/utils';
|
|
4
5
|
|
|
5
6
|
type ListArgs = { selectionSet?: string[]; filter?: {} };
|
|
6
7
|
|
|
8
|
+
type LazyLoadOptions = {
|
|
9
|
+
authMode?: GraphQLAuthMode;
|
|
10
|
+
authToken?: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
|
|
7
13
|
const connectionType = {
|
|
8
14
|
HAS_ONE: 'HAS_ONE',
|
|
9
15
|
HAS_MANY: 'HAS_MANY',
|
|
@@ -41,7 +47,9 @@ export function initializeModel(
|
|
|
41
47
|
client: any,
|
|
42
48
|
modelName: string,
|
|
43
49
|
result: any[],
|
|
44
|
-
modelIntrospection: any
|
|
50
|
+
modelIntrospection: any,
|
|
51
|
+
authMode: GraphQLAuthMode,
|
|
52
|
+
authToken: string | undefined
|
|
45
53
|
): any[] {
|
|
46
54
|
const introModel = modelIntrospection.models[modelName];
|
|
47
55
|
const introModelFields = introModel.fields;
|
|
@@ -83,12 +91,18 @@ export function initializeModel(
|
|
|
83
91
|
{}
|
|
84
92
|
);
|
|
85
93
|
|
|
86
|
-
initializedRelationalFields[field] = () => {
|
|
94
|
+
initializedRelationalFields[field] = (options?: LazyLoadOptions) => {
|
|
87
95
|
if (record[targetNames[0]]) {
|
|
88
|
-
return client.models[relatedModelName].get(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
96
|
+
return client.models[relatedModelName].get(
|
|
97
|
+
{
|
|
98
|
+
[relatedModelPKFieldName]: record[targetNames[0]],
|
|
99
|
+
...sortKeyValues,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
authMode: options?.authMode || authMode,
|
|
103
|
+
authToken: options?.authToken || authToken,
|
|
104
|
+
}
|
|
105
|
+
);
|
|
92
106
|
}
|
|
93
107
|
return undefined;
|
|
94
108
|
};
|
|
@@ -111,10 +125,14 @@ export function initializeModel(
|
|
|
111
125
|
return { [field]: { eq: record[parentSK[idx - 1]] } };
|
|
112
126
|
});
|
|
113
127
|
|
|
114
|
-
initializedRelationalFields[field] = (
|
|
128
|
+
initializedRelationalFields[field] = (
|
|
129
|
+
options?: LazyLoadOptions
|
|
130
|
+
) => {
|
|
115
131
|
if (record[parentPk]) {
|
|
116
132
|
return client.models[relatedModelName].list({
|
|
117
133
|
filter: { and: hasManyFilter },
|
|
134
|
+
authMode: options?.authMode || authMode,
|
|
135
|
+
authToken: options?.authToken || authToken,
|
|
118
136
|
});
|
|
119
137
|
}
|
|
120
138
|
return [];
|
|
@@ -130,10 +148,12 @@ export function initializeModel(
|
|
|
130
148
|
return { [field]: { eq: record[parentSK[idx - 1]] } };
|
|
131
149
|
});
|
|
132
150
|
|
|
133
|
-
initializedRelationalFields[field] = () => {
|
|
151
|
+
initializedRelationalFields[field] = (options?: LazyLoadOptions) => {
|
|
134
152
|
if (record[parentPk]) {
|
|
135
153
|
return client.models[relatedModelName].list({
|
|
136
154
|
filter: { and: hasManyFilter },
|
|
155
|
+
authMode: options?.authMode || authMode,
|
|
156
|
+
authToken: options?.authToken || authToken,
|
|
137
157
|
});
|
|
138
158
|
}
|
|
139
159
|
return [];
|
|
@@ -157,6 +177,7 @@ export const graphQLOperationsInfo = {
|
|
|
157
177
|
ONCREATE: { operationPrefix: 'onCreate' as const, usePlural: false },
|
|
158
178
|
ONUPDATE: { operationPrefix: 'onUpdate' as const, usePlural: false },
|
|
159
179
|
ONDELETE: { operationPrefix: 'onDelete' as const, usePlural: false },
|
|
180
|
+
OBSERVE_QUERY: { operationPrefix: 'observeQuery' as const, usePlural: false },
|
|
160
181
|
};
|
|
161
182
|
export type ModelOperation = keyof typeof graphQLOperationsInfo;
|
|
162
183
|
|
|
@@ -411,10 +432,12 @@ export function generateGraphQLDocument(
|
|
|
411
432
|
graphQLArguments ??
|
|
412
433
|
(graphQLArguments = {
|
|
413
434
|
filter: `Model${name}FilterInput`,
|
|
435
|
+
limit: 'Int',
|
|
436
|
+
nextToken: 'String',
|
|
414
437
|
});
|
|
415
438
|
graphQLOperationType ?? (graphQLOperationType = 'query');
|
|
416
439
|
graphQLSelectionSet ??
|
|
417
|
-
(graphQLSelectionSet = `items { ${selectionSetFields} }`);
|
|
440
|
+
(graphQLSelectionSet = `items { ${selectionSetFields} } nextToken __typename`);
|
|
418
441
|
case 'ONCREATE':
|
|
419
442
|
case 'ONUPDATE':
|
|
420
443
|
case 'ONDELETE':
|
|
@@ -424,6 +447,12 @@ export function generateGraphQLDocument(
|
|
|
424
447
|
});
|
|
425
448
|
graphQLOperationType ?? (graphQLOperationType = 'subscription');
|
|
426
449
|
graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
|
|
450
|
+
break;
|
|
451
|
+
case 'OBSERVE_QUERY':
|
|
452
|
+
default:
|
|
453
|
+
throw new Error(
|
|
454
|
+
'Internal error: Attempted to generate graphql document for observeQuery. Please report this error.'
|
|
455
|
+
);
|
|
427
456
|
}
|
|
428
457
|
|
|
429
458
|
const graphQLDocument = `${graphQLOperationType}${
|
|
@@ -460,7 +489,7 @@ export function buildGraphQLVariables(
|
|
|
460
489
|
},
|
|
461
490
|
} = modelDefinition;
|
|
462
491
|
|
|
463
|
-
let variables = {};
|
|
492
|
+
let variables: Record<string, any> = {};
|
|
464
493
|
|
|
465
494
|
// TODO: process input
|
|
466
495
|
switch (operation) {
|
|
@@ -502,6 +531,13 @@ export function buildGraphQLVariables(
|
|
|
502
531
|
}
|
|
503
532
|
break;
|
|
504
533
|
case 'LIST':
|
|
534
|
+
if (arg?.filter) {
|
|
535
|
+
variables.filter = arg.filter;
|
|
536
|
+
}
|
|
537
|
+
if (arg?.nextToken) {
|
|
538
|
+
variables.nextToken = arg.nextToken;
|
|
539
|
+
}
|
|
540
|
+
break;
|
|
505
541
|
case 'ONCREATE':
|
|
506
542
|
case 'ONUPDATE':
|
|
507
543
|
case 'ONDELETE':
|
|
@@ -509,6 +545,11 @@ export function buildGraphQLVariables(
|
|
|
509
545
|
variables = { filter: arg.filter };
|
|
510
546
|
}
|
|
511
547
|
break;
|
|
548
|
+
case 'OBSERVE_QUERY':
|
|
549
|
+
throw new Error(
|
|
550
|
+
'Internal error: Attempted to build variables for observeQuery. Please report this error.'
|
|
551
|
+
);
|
|
552
|
+
break;
|
|
512
553
|
default:
|
|
513
554
|
const exhaustiveCheck: never = operation;
|
|
514
555
|
throw new Error(`Unhandled operation case: ${exhaustiveCheck}`);
|
|
@@ -375,7 +375,7 @@ export class InternalGraphQLAPIClass {
|
|
|
375
375
|
variables,
|
|
376
376
|
appSyncGraphqlEndpoint: config?.endpoint,
|
|
377
377
|
region: config?.region,
|
|
378
|
-
authenticationType: config?.defaultAuthMode,
|
|
378
|
+
authenticationType: authMode || config?.defaultAuthMode,
|
|
379
379
|
apiKey: config?.apiKey,
|
|
380
380
|
additionalHeaders,
|
|
381
381
|
},
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from './APIClient';
|
|
12
12
|
import { ClientGenerationParams } from './types';
|
|
13
13
|
import { V6Client, GraphqlSubscriptionResult } from '../types';
|
|
14
|
+
import { findIndexByFields, resolvePKFields } from '../utils';
|
|
14
15
|
import { Observable, map } from 'rxjs';
|
|
15
16
|
|
|
16
17
|
export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
@@ -52,7 +53,12 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
52
53
|
);
|
|
53
54
|
|
|
54
55
|
try {
|
|
55
|
-
const
|
|
56
|
+
const options: Record<string, any> = {};
|
|
57
|
+
if (args?.authMode) options.authMode = args?.authMode;
|
|
58
|
+
if (args?.authToken) options.authToken = args?.authToken;
|
|
59
|
+
|
|
60
|
+
const { data, extensions } = (await client.graphql({
|
|
61
|
+
...options,
|
|
56
62
|
query,
|
|
57
63
|
variables,
|
|
58
64
|
})) as any;
|
|
@@ -68,7 +74,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
68
74
|
if (args?.selectionSet) {
|
|
69
75
|
return {
|
|
70
76
|
data: flattenedResult,
|
|
71
|
-
nextToken,
|
|
77
|
+
nextToken: data[key].nextToken,
|
|
72
78
|
extensions,
|
|
73
79
|
};
|
|
74
80
|
} else {
|
|
@@ -76,12 +82,14 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
76
82
|
client,
|
|
77
83
|
name,
|
|
78
84
|
flattenedResult,
|
|
79
|
-
modelIntrospection
|
|
85
|
+
modelIntrospection,
|
|
86
|
+
options.authMode,
|
|
87
|
+
options.authToken
|
|
80
88
|
);
|
|
81
89
|
|
|
82
90
|
return {
|
|
83
91
|
data: initialized,
|
|
84
|
-
nextToken,
|
|
92
|
+
nextToken: data[key].nextToken,
|
|
85
93
|
extensions,
|
|
86
94
|
};
|
|
87
95
|
}
|
|
@@ -89,7 +97,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
89
97
|
|
|
90
98
|
return {
|
|
91
99
|
data: data[key],
|
|
92
|
-
nextToken,
|
|
100
|
+
nextToken: data[key].nextToken,
|
|
93
101
|
extensions,
|
|
94
102
|
};
|
|
95
103
|
}
|
|
@@ -104,7 +112,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
104
112
|
}
|
|
105
113
|
};
|
|
106
114
|
} else if (['ONCREATE', 'ONUPDATE', 'ONDELETE'].includes(operation)) {
|
|
107
|
-
models[name][operationPrefix] = (
|
|
115
|
+
models[name][operationPrefix] = (args?: any) => {
|
|
108
116
|
const query = generateGraphQLDocument(
|
|
109
117
|
modelIntrospection.models,
|
|
110
118
|
name,
|
|
@@ -113,11 +121,16 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
113
121
|
const variables = buildGraphQLVariables(
|
|
114
122
|
model,
|
|
115
123
|
operation,
|
|
116
|
-
|
|
124
|
+
args,
|
|
117
125
|
modelIntrospection
|
|
118
126
|
);
|
|
119
127
|
|
|
128
|
+
const options: Record<string, any> = {};
|
|
129
|
+
if (args?.authMode) options.authMode = args?.authMode;
|
|
130
|
+
if (args?.authToken) options.authToken = args?.authToken;
|
|
131
|
+
|
|
120
132
|
const observable = client.graphql({
|
|
133
|
+
...options,
|
|
121
134
|
query,
|
|
122
135
|
variables,
|
|
123
136
|
}) as GraphqlSubscriptionResult<object>;
|
|
@@ -125,10 +138,154 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
125
138
|
return observable.pipe(
|
|
126
139
|
map(value => {
|
|
127
140
|
const [key] = Object.keys(value.data);
|
|
128
|
-
|
|
141
|
+
const [initialized] = initializeModel(
|
|
142
|
+
client,
|
|
143
|
+
name,
|
|
144
|
+
[value.data[key]],
|
|
145
|
+
modelIntrospection,
|
|
146
|
+
options?.authMode,
|
|
147
|
+
options?.authToken
|
|
148
|
+
);
|
|
149
|
+
return initialized;
|
|
129
150
|
})
|
|
130
151
|
);
|
|
131
152
|
};
|
|
153
|
+
} else if (operation === 'OBSERVE_QUERY') {
|
|
154
|
+
models[name][operationPrefix] = (arg?: any) =>
|
|
155
|
+
new Observable(subscriber => {
|
|
156
|
+
// what we'll be sending to our subscribers
|
|
157
|
+
const items: object[] = [];
|
|
158
|
+
|
|
159
|
+
// To enqueue subscription messages while we collect our initial
|
|
160
|
+
// result set.
|
|
161
|
+
const messageQueue = [] as {
|
|
162
|
+
type: 'create' | 'update' | 'delete';
|
|
163
|
+
item: object;
|
|
164
|
+
}[];
|
|
165
|
+
|
|
166
|
+
// operation to take when message(s) arrive.
|
|
167
|
+
// this operation will be swapped out once initial "sync" is complete
|
|
168
|
+
// to immediately ingest messsages.
|
|
169
|
+
let receiveMessages = (...messages: typeof messageQueue) => {
|
|
170
|
+
return messageQueue.push(...messages);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// start subscriptions
|
|
174
|
+
const onCreateSub = models[name].onCreate(arg).subscribe({
|
|
175
|
+
next(item) {
|
|
176
|
+
receiveMessages({ item, type: 'create' });
|
|
177
|
+
},
|
|
178
|
+
error(error) {
|
|
179
|
+
subscriber.error({ type: 'onCreate', error });
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
const onUpdateSub = models[name].onUpdate(arg).subscribe({
|
|
183
|
+
next(item) {
|
|
184
|
+
receiveMessages({ item, type: 'update' });
|
|
185
|
+
},
|
|
186
|
+
error(error) {
|
|
187
|
+
subscriber.error({ type: 'onUpdate', error });
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
const onDeleteSub = models[name].onDelete(arg).subscribe({
|
|
191
|
+
next(item) {
|
|
192
|
+
receiveMessages({ item, type: 'delete' });
|
|
193
|
+
},
|
|
194
|
+
error(error) {
|
|
195
|
+
subscriber.error({ type: 'onDelete', error });
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// consumes a list of messages and sends a snapshot
|
|
200
|
+
function ingestMessages(messages: typeof messageQueue) {
|
|
201
|
+
for (const message of messages) {
|
|
202
|
+
const idx = findIndexByFields(
|
|
203
|
+
message.item,
|
|
204
|
+
items,
|
|
205
|
+
pkFields as any
|
|
206
|
+
);
|
|
207
|
+
switch (message.type) {
|
|
208
|
+
case 'create':
|
|
209
|
+
if (idx < 0) items.push(message.item);
|
|
210
|
+
break;
|
|
211
|
+
case 'update':
|
|
212
|
+
if (idx >= 0) items[idx] = message.item;
|
|
213
|
+
break;
|
|
214
|
+
case 'delete':
|
|
215
|
+
if (idx >= 0) items.splice(idx, 1);
|
|
216
|
+
break;
|
|
217
|
+
default:
|
|
218
|
+
console.error(
|
|
219
|
+
'Unrecognized message in observeQuery.',
|
|
220
|
+
message
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
subscriber.next({
|
|
225
|
+
items,
|
|
226
|
+
isSynced: true,
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const pkFields = resolvePKFields(model);
|
|
231
|
+
|
|
232
|
+
// initial results
|
|
233
|
+
(async () => {
|
|
234
|
+
let firstPage = true;
|
|
235
|
+
let nextToken: string | null = null;
|
|
236
|
+
while (!subscriber.closed && (firstPage || nextToken)) {
|
|
237
|
+
firstPage = false;
|
|
238
|
+
|
|
239
|
+
const {
|
|
240
|
+
data: page,
|
|
241
|
+
errors,
|
|
242
|
+
nextToken: _nextToken,
|
|
243
|
+
} = await models[name].list({ ...arg, nextToken });
|
|
244
|
+
nextToken = _nextToken;
|
|
245
|
+
|
|
246
|
+
items.push(...page);
|
|
247
|
+
|
|
248
|
+
// if there are no more pages and no items we already know about
|
|
249
|
+
// that need to be merged in from sub, we're "synced"
|
|
250
|
+
const isSynced =
|
|
251
|
+
messageQueue.length === 0 &&
|
|
252
|
+
(nextToken === null || nextToken === undefined);
|
|
253
|
+
|
|
254
|
+
subscriber.next({
|
|
255
|
+
items,
|
|
256
|
+
isSynced,
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
if (Array.isArray(errors)) {
|
|
260
|
+
for (const error of errors) {
|
|
261
|
+
subscriber.error(error);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// play through the queue
|
|
267
|
+
if (messageQueue.length > 0) {
|
|
268
|
+
ingestMessages(messageQueue);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// switch the queue to write directly to the items collection
|
|
272
|
+
receiveMessages = (...messages: typeof messageQueue) => {
|
|
273
|
+
ingestMessages(messages);
|
|
274
|
+
return items.length;
|
|
275
|
+
};
|
|
276
|
+
})();
|
|
277
|
+
|
|
278
|
+
// when subscriber unsubscribes, tear down internal subs
|
|
279
|
+
return () => {
|
|
280
|
+
// 1. tear down internal subs
|
|
281
|
+
onCreateSub.unsubscribe();
|
|
282
|
+
onUpdateSub.unsubscribe();
|
|
283
|
+
onDeleteSub.unsubscribe();
|
|
284
|
+
|
|
285
|
+
// 2. there is no need to explicitly stop paging. instead, we
|
|
286
|
+
// just check `subscriber.closed` above before fetching each page.
|
|
287
|
+
};
|
|
288
|
+
});
|
|
132
289
|
} else {
|
|
133
290
|
models[name][operationPrefix] = async (arg?: any, options?: any) => {
|
|
134
291
|
const query = generateGraphQLDocument(
|
|
@@ -146,6 +303,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
146
303
|
|
|
147
304
|
try {
|
|
148
305
|
const { data, extensions } = (await client.graphql({
|
|
306
|
+
...options,
|
|
149
307
|
query,
|
|
150
308
|
variables,
|
|
151
309
|
})) as any;
|
|
@@ -163,7 +321,9 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
|
|
|
163
321
|
client,
|
|
164
322
|
name,
|
|
165
323
|
[flattenedResult],
|
|
166
|
-
modelIntrospection
|
|
324
|
+
modelIntrospection,
|
|
325
|
+
options?.authMode,
|
|
326
|
+
options?.authToken
|
|
167
327
|
);
|
|
168
328
|
|
|
169
329
|
return { data: initialized, extensions };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
/**
|
|
4
|
+
* Iterates through a collection to find a matching item and returns the index.
|
|
5
|
+
*
|
|
6
|
+
* @param needle The item to search for
|
|
7
|
+
* @param haystack The collection to search
|
|
8
|
+
* @param keyFields The fields used to indicate a match
|
|
9
|
+
* @returns Index of `needle` in `haystack`, otherwise -1 if not found.
|
|
10
|
+
*/
|
|
11
|
+
export function findIndexByFields<T>(
|
|
12
|
+
needle: T,
|
|
13
|
+
haystack: T[],
|
|
14
|
+
keyFields: Array<keyof T>
|
|
15
|
+
): number {
|
|
16
|
+
const searchObject = Object.fromEntries(
|
|
17
|
+
keyFields.map(fieldName => [fieldName, needle[fieldName]])
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < haystack.length; i++) {
|
|
21
|
+
if (
|
|
22
|
+
Object.keys(searchObject).every(k => searchObject[k] === haystack[i][k])
|
|
23
|
+
) {
|
|
24
|
+
return i;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return -1;
|
|
29
|
+
}
|
package/src/utils/index.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import { ResourcesConfig } from '@aws-amplify/core';
|
|
4
|
+
|
|
5
|
+
type GraphQLConfig = Exclude<ResourcesConfig['API'], undefined>['GraphQL'];
|
|
6
|
+
type ModelIntrospectionSchema = Exclude<
|
|
7
|
+
Exclude<GraphQLConfig, undefined>['modelIntrospection'],
|
|
8
|
+
undefined
|
|
9
|
+
>;
|
|
10
|
+
type SchemaModel = ModelIntrospectionSchema['models'][string];
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Given a SchemaModel from a ModelIntrospectionSchema, returns the primary key
|
|
14
|
+
* as an array of field names.
|
|
15
|
+
*
|
|
16
|
+
* @param model The model object
|
|
17
|
+
* @returns Array of field names
|
|
18
|
+
*/
|
|
19
|
+
export function resolvePKFields(model: SchemaModel) {
|
|
20
|
+
const { primaryKeyFieldName, sortKeyFieldNames } = model.primaryKeyInfo;
|
|
21
|
+
return [primaryKeyFieldName, ...sortKeyFieldNames];
|
|
22
|
+
}
|