@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.
@@ -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
+ }
@@ -1,2 +1,4 @@
1
1
  export { resolveConfig } from './resolveConfig';
2
2
  export { resolveLibraryOptions } from './resolveLibraryOptions';
3
+ export { resolvePKFields } from './resolvePKFields';
4
+ export { findIndexByFields } from './findIndexByFields';
@@ -2,3 +2,5 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  export { resolveConfig } from './resolveConfig';
4
4
  export { resolveLibraryOptions } from './resolveLibraryOptions';
5
+ export { resolvePKFields } from './resolvePKFields';
6
+ export { findIndexByFields } from './findIndexByFields';
@@ -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.9493d4d.0+9493d4d",
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.9493d4d.0+9493d4d",
56
- "@aws-amplify/auth": "6.0.1-api-v6-models.9493d4d.0+9493d4d",
57
- "@aws-amplify/core": "6.0.1-api-v6-models.9493d4d.0+9493d4d",
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": "9493d4d9a9fb9bfa104c0cf56e5a1d3154daa088"
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
- [relatedModelPKFieldName]: record[targetNames[0]],
90
- ...sortKeyValues,
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 { data, nextToken, extensions } = (await client.graphql({
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] = (arg?: any, options?: any) => {
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
- arg,
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
- return value.data[key];
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
+ }
@@ -3,3 +3,5 @@
3
3
 
4
4
  export { resolveConfig } from './resolveConfig';
5
5
  export { resolveLibraryOptions } from './resolveLibraryOptions';
6
+ export { resolvePKFields } from './resolvePKFields';
7
+ export { findIndexByFields } from './findIndexByFields';
@@ -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
+ }