@aws-amplify/api-graphql 4.0.1-api-v6-models.9493d4d.0 → 4.0.1-api-v6-models.01b2bb8.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.01b2bb8.0+01b2bb8",
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.01b2bb8.0+01b2bb8",
56
+ "@aws-amplify/auth": "6.0.1-api-v6-models.01b2bb8.0+01b2bb8",
57
+ "@aws-amplify/core": "6.0.1-api-v6-models.01b2bb8.0+01b2bb8",
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": "01b2bb8503ffd202c858da1ff6afeb7c008a4563"
130
130
  }
@@ -157,6 +157,7 @@ export const graphQLOperationsInfo = {
157
157
  ONCREATE: { operationPrefix: 'onCreate' as const, usePlural: false },
158
158
  ONUPDATE: { operationPrefix: 'onUpdate' as const, usePlural: false },
159
159
  ONDELETE: { operationPrefix: 'onDelete' as const, usePlural: false },
160
+ OBSERVE_QUERY: { operationPrefix: 'observeQuery' as const, usePlural: false },
160
161
  };
161
162
  export type ModelOperation = keyof typeof graphQLOperationsInfo;
162
163
 
@@ -411,10 +412,12 @@ export function generateGraphQLDocument(
411
412
  graphQLArguments ??
412
413
  (graphQLArguments = {
413
414
  filter: `Model${name}FilterInput`,
415
+ limit: 'Int',
416
+ nextToken: 'String',
414
417
  });
415
418
  graphQLOperationType ?? (graphQLOperationType = 'query');
416
419
  graphQLSelectionSet ??
417
- (graphQLSelectionSet = `items { ${selectionSetFields} }`);
420
+ (graphQLSelectionSet = `items { ${selectionSetFields} } nextToken __typename`);
418
421
  case 'ONCREATE':
419
422
  case 'ONUPDATE':
420
423
  case 'ONDELETE':
@@ -424,6 +427,12 @@ export function generateGraphQLDocument(
424
427
  });
425
428
  graphQLOperationType ?? (graphQLOperationType = 'subscription');
426
429
  graphQLSelectionSet ?? (graphQLSelectionSet = selectionSetFields);
430
+ break;
431
+ case 'OBSERVE_QUERY':
432
+ default:
433
+ throw new Error(
434
+ 'Internal error: Attempted to generate graphql document for observeQuery. Please report this error.'
435
+ );
427
436
  }
428
437
 
429
438
  const graphQLDocument = `${graphQLOperationType}${
@@ -460,7 +469,7 @@ export function buildGraphQLVariables(
460
469
  },
461
470
  } = modelDefinition;
462
471
 
463
- let variables = {};
472
+ let variables: Record<string, any> = {};
464
473
 
465
474
  // TODO: process input
466
475
  switch (operation) {
@@ -502,6 +511,13 @@ export function buildGraphQLVariables(
502
511
  }
503
512
  break;
504
513
  case 'LIST':
514
+ if (arg?.filter) {
515
+ variables.filter = arg.filter;
516
+ }
517
+ if (arg?.nextToken) {
518
+ variables.nextToken = arg.nextToken;
519
+ }
520
+ break;
505
521
  case 'ONCREATE':
506
522
  case 'ONUPDATE':
507
523
  case 'ONDELETE':
@@ -509,6 +525,11 @@ export function buildGraphQLVariables(
509
525
  variables = { filter: arg.filter };
510
526
  }
511
527
  break;
528
+ case 'OBSERVE_QUERY':
529
+ throw new Error(
530
+ 'Internal error: Attempted to build variables for observeQuery. Please report this error.'
531
+ );
532
+ break;
512
533
  default:
513
534
  const exhaustiveCheck: never = operation;
514
535
  throw new Error(`Unhandled operation case: ${exhaustiveCheck}`);
@@ -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,7 @@ 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 { data, extensions } = (await client.graphql({
56
57
  query,
57
58
  variables,
58
59
  })) as any;
@@ -68,7 +69,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
68
69
  if (args?.selectionSet) {
69
70
  return {
70
71
  data: flattenedResult,
71
- nextToken,
72
+ nextToken: data[key].nextToken,
72
73
  extensions,
73
74
  };
74
75
  } else {
@@ -81,7 +82,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
81
82
 
82
83
  return {
83
84
  data: initialized,
84
- nextToken,
85
+ nextToken: data[key].nextToken,
85
86
  extensions,
86
87
  };
87
88
  }
@@ -89,7 +90,7 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
89
90
 
90
91
  return {
91
92
  data: data[key],
92
- nextToken,
93
+ nextToken: data[key].nextToken,
93
94
  extensions,
94
95
  };
95
96
  }
@@ -129,6 +130,148 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
129
130
  })
130
131
  );
131
132
  };
133
+ } else if (operation === 'OBSERVE_QUERY') {
134
+ models[name][operationPrefix] = (arg?: any, options?: any) =>
135
+ new Observable(subscriber => {
136
+ // what we'll be sending to our subscribers
137
+ const items: object[] = [];
138
+
139
+ // To enqueue subscription messages while we collect our initial
140
+ // result set.
141
+ const messageQueue = [] as {
142
+ type: 'create' | 'update' | 'delete';
143
+ item: object;
144
+ }[];
145
+
146
+ // operation to take when message(s) arrive.
147
+ // this operation will be swapped out once initial "sync" is complete
148
+ // to immediately ingest messsages.
149
+ let receiveMessages = (...messages: typeof messageQueue) => {
150
+ return messageQueue.push(...messages);
151
+ };
152
+
153
+ // start subscriptions
154
+ const onCreateSub = models[name]
155
+ .onCreate(arg, options)
156
+ .subscribe({
157
+ next(item) {
158
+ receiveMessages({ item, type: 'create' });
159
+ },
160
+ error(error) {
161
+ subscriber.error({ type: 'onCreate', error });
162
+ },
163
+ });
164
+ const onUpdateSub = models[name]
165
+ .onUpdate(arg, options)
166
+ .subscribe({
167
+ next(item) {
168
+ receiveMessages({ item, type: 'update' });
169
+ },
170
+ error(error) {
171
+ subscriber.error({ type: 'onUpdate', error });
172
+ },
173
+ });
174
+ const onDeleteSub = models[name]
175
+ .onDelete(arg, options)
176
+ .subscribe({
177
+ next(item) {
178
+ receiveMessages({ item, type: 'delete' });
179
+ },
180
+ error(error) {
181
+ subscriber.error({ type: 'onDelete', error });
182
+ },
183
+ });
184
+
185
+ // consumes a list of messages and sends a snapshot
186
+ function ingestMessages(messages: typeof messageQueue) {
187
+ for (const message of messages) {
188
+ const idx = findIndexByFields(
189
+ message.item,
190
+ items,
191
+ pkFields as any
192
+ );
193
+ switch (message.type) {
194
+ case 'create':
195
+ if (idx < 0) items.push(message.item);
196
+ break;
197
+ case 'update':
198
+ if (idx >= 0) items[idx] = message.item;
199
+ break;
200
+ case 'delete':
201
+ if (idx >= 0) items.splice(idx, 1);
202
+ break;
203
+ default:
204
+ console.error(
205
+ 'Unrecognized message in observeQuery.',
206
+ message
207
+ );
208
+ }
209
+ }
210
+ subscriber.next({
211
+ items,
212
+ isSynced: true,
213
+ });
214
+ }
215
+
216
+ const pkFields = resolvePKFields(model);
217
+
218
+ // initial results
219
+ (async () => {
220
+ let firstPage = true;
221
+ let nextToken: string | null = null;
222
+ while (!subscriber.closed && (firstPage || nextToken)) {
223
+ firstPage = false;
224
+
225
+ const {
226
+ data: page,
227
+ errors,
228
+ nextToken: _nextToken,
229
+ } = await models[name].list({ ...arg, nextToken }, options);
230
+ nextToken = _nextToken;
231
+
232
+ items.push(...page);
233
+
234
+ // if there are no more pages and no items we already know about
235
+ // that need to be merged in from sub, we're "synced"
236
+ const isSynced =
237
+ messageQueue.length === 0 &&
238
+ (nextToken === null || nextToken === undefined);
239
+
240
+ subscriber.next({
241
+ items,
242
+ isSynced,
243
+ });
244
+
245
+ if (Array.isArray(errors)) {
246
+ for (const error of errors) {
247
+ subscriber.error(error);
248
+ }
249
+ }
250
+ }
251
+
252
+ // play through the queue
253
+ if (messageQueue.length > 0) {
254
+ ingestMessages(messageQueue);
255
+ }
256
+
257
+ // switch the queue to write directly to the items collection
258
+ receiveMessages = (...messages: typeof messageQueue) => {
259
+ ingestMessages(messages);
260
+ return items.length;
261
+ };
262
+ })();
263
+
264
+ // when subscriber unsubscribes, tear down internal subs
265
+ return () => {
266
+ // 1. tear down internal subs
267
+ onCreateSub.unsubscribe();
268
+ onUpdateSub.unsubscribe();
269
+ onDeleteSub.unsubscribe();
270
+
271
+ // 2. there is no need to explicitly stop paging. instead, we
272
+ // just check `subscriber.closed` above before fetching each page.
273
+ };
274
+ });
132
275
  } else {
133
276
  models[name][operationPrefix] = async (arg?: any, options?: any) => {
134
277
  const query = generateGraphQLDocument(
@@ -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
+ }