@aws-amplify/api-graphql 4.0.1-api-v6-models.9351bcf.0 → 4.0.1-api-v6-models.891fe0d.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.
Files changed (95) hide show
  1. package/internals/server/package.json +8 -0
  2. package/lib/GraphQLAPI.d.ts +1 -1
  3. package/lib/GraphQLAPI.js +23 -28
  4. package/lib/Providers/AWSAppSyncRealTimeProvider/index.js +467 -582
  5. package/lib/index.js +1 -1
  6. package/lib/internals/APIClient.d.ts +16 -1
  7. package/lib/internals/APIClient.js +232 -206
  8. package/lib/internals/InternalGraphQLAPI.d.ts +1 -1
  9. package/lib/internals/InternalGraphQLAPI.js +205 -247
  10. package/lib/internals/generateClient.js +14 -13
  11. package/lib/internals/generateModelsProperty.js +19 -312
  12. package/lib/internals/operations/get.d.ts +2 -0
  13. package/lib/internals/operations/get.js +59 -0
  14. package/lib/internals/operations/list.d.ts +2 -0
  15. package/lib/internals/operations/list.js +71 -0
  16. package/lib/internals/operations/observeQuery.d.ts +2 -0
  17. package/lib/internals/operations/observeQuery.js +119 -0
  18. package/lib/internals/operations/subscription.d.ts +1 -0
  19. package/lib/internals/operations/subscription.js +27 -0
  20. package/lib/internals/server/generateClient.d.ts +11 -0
  21. package/lib/internals/server/generateClient.js +30 -0
  22. package/lib/internals/server/generateModelsProperty.d.ts +3 -0
  23. package/lib/internals/server/generateModelsProperty.js +45 -0
  24. package/lib/internals/server/index.d.ts +1 -0
  25. package/lib/internals/server/index.js +7 -0
  26. package/lib/internals/v6.js +3 -3
  27. package/lib/tsconfig.tsbuildinfo +1 -1
  28. package/lib/types/index.d.ts +36 -4
  29. package/lib/utils/ConnectionStateMonitor.js +51 -64
  30. package/lib/utils/ReachabilityMonitor/index.js +2 -2
  31. package/lib/utils/ReachabilityMonitor/index.native.js +4 -6
  32. package/lib/utils/ReconnectionMonitor.js +20 -24
  33. package/lib/utils/errors/APIError.js +7 -11
  34. package/lib/utils/errors/assertValidationError.js +4 -4
  35. package/lib/utils/errors/validation.js +5 -6
  36. package/lib/utils/findIndexByFields.js +4 -9
  37. package/lib/utils/resolveConfig.js +9 -10
  38. package/lib/utils/resolveLibraryOptions.js +4 -5
  39. package/lib/utils/resolveOwnerFields.js +10 -33
  40. package/lib/utils/resolvePKFields.js +2 -3
  41. package/lib-esm/GraphQLAPI.d.ts +1 -1
  42. package/lib-esm/GraphQLAPI.js +23 -29
  43. package/lib-esm/Providers/AWSAppSyncRealTimeProvider/index.js +459 -575
  44. package/lib-esm/Providers/constants.js +10 -10
  45. package/lib-esm/internals/APIClient.d.ts +16 -1
  46. package/lib-esm/internals/APIClient.js +230 -205
  47. package/lib-esm/internals/InternalGraphQLAPI.d.ts +1 -1
  48. package/lib-esm/internals/InternalGraphQLAPI.js +201 -244
  49. package/lib-esm/internals/generateClient.js +11 -10
  50. package/lib-esm/internals/generateModelsProperty.js +19 -312
  51. package/lib-esm/internals/operations/get.d.ts +2 -0
  52. package/lib-esm/internals/operations/get.js +55 -0
  53. package/lib-esm/internals/operations/list.d.ts +2 -0
  54. package/lib-esm/internals/operations/list.js +67 -0
  55. package/lib-esm/internals/operations/observeQuery.d.ts +2 -0
  56. package/lib-esm/internals/operations/observeQuery.js +115 -0
  57. package/lib-esm/internals/operations/subscription.d.ts +1 -0
  58. package/lib-esm/internals/operations/subscription.js +23 -0
  59. package/lib-esm/internals/server/generateClient.d.ts +11 -0
  60. package/lib-esm/internals/server/generateClient.js +26 -0
  61. package/lib-esm/internals/server/generateModelsProperty.d.ts +3 -0
  62. package/lib-esm/internals/server/generateModelsProperty.js +41 -0
  63. package/lib-esm/internals/server/index.d.ts +1 -0
  64. package/lib-esm/internals/server/index.js +3 -0
  65. package/lib-esm/internals/v6.js +1 -1
  66. package/lib-esm/tsconfig.tsbuildinfo +1 -1
  67. package/lib-esm/types/index.d.ts +36 -4
  68. package/lib-esm/types/index.js +3 -3
  69. package/lib-esm/utils/ConnectionStateMonitor.js +49 -63
  70. package/lib-esm/utils/ReachabilityMonitor/index.js +1 -1
  71. package/lib-esm/utils/ReachabilityMonitor/index.native.js +1 -3
  72. package/lib-esm/utils/ReconnectionMonitor.js +19 -24
  73. package/lib-esm/utils/errors/APIError.js +6 -11
  74. package/lib-esm/utils/errors/assertValidationError.js +2 -2
  75. package/lib-esm/utils/errors/validation.js +5 -6
  76. package/lib-esm/utils/findIndexByFields.js +4 -9
  77. package/lib-esm/utils/resolveConfig.js +8 -9
  78. package/lib-esm/utils/resolveLibraryOptions.js +4 -5
  79. package/lib-esm/utils/resolveOwnerFields.js +10 -33
  80. package/lib-esm/utils/resolvePKFields.js +2 -3
  81. package/package.json +8 -7
  82. package/src/GraphQLAPI.ts +6 -2
  83. package/src/Providers/AWSAppSyncRealTimeProvider/index.ts +6 -5
  84. package/src/internals/APIClient.ts +122 -35
  85. package/src/internals/InternalGraphQLAPI.ts +35 -10
  86. package/src/internals/generateClient.ts +0 -1
  87. package/src/internals/generateModelsProperty.ts +27 -340
  88. package/src/internals/operations/get.ts +121 -0
  89. package/src/internals/operations/list.ts +111 -0
  90. package/src/internals/operations/observeQuery.ts +140 -0
  91. package/src/internals/operations/subscription.ts +59 -0
  92. package/src/internals/server/generateClient.ts +45 -0
  93. package/src/internals/server/generateModelsProperty.ts +70 -0
  94. package/src/internals/server/index.ts +4 -0
  95. package/src/types/index.ts +65 -9
@@ -2,6 +2,8 @@
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { resolveOwnerFields } from '../utils/resolveOwnerFields';
4
4
  import { GraphQLAuthMode } from '@aws-amplify/core/internals/utils';
5
+ import { V6Client, __authMode, __authToken } from '../types';
6
+ import { AmplifyServer } from '@aws-amplify/core/internals/adapter-core';
5
7
 
6
8
  type ListArgs = { selectionSet?: string[]; filter?: {} };
7
9
 
@@ -49,7 +51,8 @@ export function initializeModel(
49
51
  result: any[],
50
52
  modelIntrospection: any,
51
53
  authMode: GraphQLAuthMode | undefined,
52
- authToken: string | undefined
54
+ authToken: string | undefined,
55
+ context = false
53
56
  ): any[] {
54
57
  const introModel = modelIntrospection.models[modelName];
55
58
  const introModelFields = introModel.fields;
@@ -91,21 +94,45 @@ export function initializeModel(
91
94
  {}
92
95
  );
93
96
 
94
- initializedRelationalFields[field] = (options?: LazyLoadOptions) => {
95
- if (record[targetNames[0]]) {
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
- );
106
- }
107
- return undefined;
108
- };
97
+ if (context) {
98
+ initializedRelationalFields[field] = (
99
+ contextSpec: AmplifyServer.ContextSpec,
100
+ options?: LazyLoadOptions
101
+ ) => {
102
+ if (record[targetNames[0]]) {
103
+ return client.models[relatedModelName].get(
104
+ contextSpec,
105
+ {
106
+ [relatedModelPKFieldName]: record[targetNames[0]],
107
+ ...sortKeyValues,
108
+ },
109
+ {
110
+ authMode: options?.authMode || authMode,
111
+ authToken: options?.authToken || authToken,
112
+ }
113
+ );
114
+ }
115
+ return undefined;
116
+ };
117
+ } else {
118
+ initializedRelationalFields[field] = (
119
+ options?: LazyLoadOptions
120
+ ) => {
121
+ if (record[targetNames[0]]) {
122
+ return client.models[relatedModelName].get(
123
+ {
124
+ [relatedModelPKFieldName]: record[targetNames[0]],
125
+ ...sortKeyValues,
126
+ },
127
+ {
128
+ authMode: options?.authMode || authMode,
129
+ authToken: options?.authToken || authToken,
130
+ }
131
+ );
132
+ }
133
+ return undefined;
134
+ };
135
+ }
109
136
 
110
137
  break;
111
138
  case connectionType.HAS_MANY:
@@ -125,6 +152,61 @@ export function initializeModel(
125
152
  return { [field]: { eq: record[parentSK[idx - 1]] } };
126
153
  });
127
154
 
155
+ if (context) {
156
+ initializedRelationalFields[field] = (
157
+ contextSpec: AmplifyServer.ContextSpec,
158
+ options?: LazyLoadOptions
159
+ ) => {
160
+ if (record[parentPk]) {
161
+ return client.models[relatedModelName].list(contextSpec, {
162
+ filter: { and: hasManyFilter },
163
+ authMode: options?.authMode || authMode,
164
+ authToken: options?.authToken || authToken,
165
+ });
166
+ }
167
+ return [];
168
+ };
169
+ } else {
170
+ initializedRelationalFields[field] = (
171
+ options?: LazyLoadOptions
172
+ ) => {
173
+ if (record[parentPk]) {
174
+ return client.models[relatedModelName].list({
175
+ filter: { and: hasManyFilter },
176
+ authMode: options?.authMode || authMode,
177
+ authToken: options?.authToken || authToken,
178
+ });
179
+ }
180
+ return [];
181
+ };
182
+ }
183
+
184
+ break;
185
+ }
186
+
187
+ const hasManyFilter = connectionFields.map((field, idx) => {
188
+ if (idx === 0) {
189
+ return { [field]: { eq: record[parentPk] } };
190
+ }
191
+
192
+ return { [field]: { eq: record[parentSK[idx - 1]] } };
193
+ });
194
+
195
+ if (context) {
196
+ initializedRelationalFields[field] = (
197
+ contextSpec: AmplifyServer.ContextSpec,
198
+ options?: LazyLoadOptions
199
+ ) => {
200
+ if (record[parentPk]) {
201
+ return client.models[relatedModelName].list(contextSpec, {
202
+ filter: { and: hasManyFilter },
203
+ authMode: options?.authMode || authMode,
204
+ authToken: options?.authToken || authToken,
205
+ });
206
+ }
207
+ return [];
208
+ };
209
+ } else {
128
210
  initializedRelationalFields[field] = (
129
211
  options?: LazyLoadOptions
130
212
  ) => {
@@ -137,27 +219,8 @@ export function initializeModel(
137
219
  }
138
220
  return [];
139
221
  };
140
- break;
141
222
  }
142
223
 
143
- const hasManyFilter = connectionFields.map((field, idx) => {
144
- if (idx === 0) {
145
- return { [field]: { eq: record[parentPk] } };
146
- }
147
-
148
- return { [field]: { eq: record[parentSK[idx - 1]] } };
149
- });
150
-
151
- initializedRelationalFields[field] = (options?: LazyLoadOptions) => {
152
- if (record[parentPk]) {
153
- return client.models[relatedModelName].list({
154
- filter: { and: hasManyFilter },
155
- authMode: options?.authMode || authMode,
156
- authToken: options?.authToken || authToken,
157
- });
158
- }
159
- return [];
160
- };
161
224
  break;
162
225
  default:
163
226
  break;
@@ -622,3 +685,27 @@ export function normalizeMutationInput(
622
685
 
623
686
  return normalized;
624
687
  }
688
+
689
+ type AuthModeParams = {
690
+ authMode?: GraphQLAuthMode;
691
+ authToken?: string;
692
+ };
693
+
694
+ /**
695
+ * Produces a parameter object that can contains auth mode/token overrides
696
+ * only if present in either `options` (first) or configured on the `client`
697
+ * as a fallback.
698
+ *
699
+ * @param client Configured client from `generateClient`
700
+ * @param options Args/Options obect from call site.
701
+ * @returns
702
+ */
703
+ export function authModeParams(
704
+ client: V6Client,
705
+ options: AuthModeParams = {}
706
+ ): AuthModeParams {
707
+ return {
708
+ authMode: options.authMode || client[__authMode],
709
+ authToken: options.authToken || client[__authToken],
710
+ };
711
+ }
@@ -45,6 +45,10 @@ export const graphqlOperation = (
45
45
  authToken,
46
46
  });
47
47
 
48
+ const isAmplifyInstance = (amplify): amplify is AmplifyClassV6 => {
49
+ return typeof amplify !== 'function';
50
+ };
51
+
48
52
  /**
49
53
  * Export Cloud Logic APIs
50
54
  */
@@ -163,7 +167,9 @@ export class InternalGraphQLAPIClass {
163
167
  * @returns An Observable if the query is a subscription query, else a promise of the graphql result.
164
168
  */
165
169
  graphql<T = any>(
166
- amplify: AmplifyClassV6,
170
+ amplify:
171
+ | AmplifyClassV6
172
+ | ((fn: (amplify: any) => Promise<any>) => Promise<AmplifyClassV6>),
167
173
  { query: paramQuery, variables = {}, authMode, authToken }: GraphQLOptions,
168
174
  additionalHeaders?: { [key: string]: string },
169
175
  customUserAgentDetails?: CustomUserAgentDetails
@@ -190,13 +196,32 @@ export class InternalGraphQLAPIClass {
190
196
  case 'query':
191
197
  case 'mutation':
192
198
  const abortController = new AbortController();
193
- const responsePromise = this._graphql<T>(
194
- amplify,
195
- { query, variables, authMode },
196
- headers,
197
- abortController,
198
- customUserAgentDetails
199
- );
199
+
200
+ let responsePromise: Promise<GraphQLResult<T>>;
201
+
202
+ if (isAmplifyInstance(amplify)) {
203
+ responsePromise = this._graphql<T>(
204
+ amplify,
205
+ { query, variables, authMode },
206
+ headers,
207
+ abortController,
208
+ customUserAgentDetails
209
+ );
210
+ } else {
211
+ const wrapper = amplifyInstance =>
212
+ this._graphql<T>(
213
+ amplifyInstance,
214
+ { query, variables, authMode },
215
+ headers,
216
+ abortController,
217
+ customUserAgentDetails
218
+ );
219
+
220
+ responsePromise = amplify(wrapper) as unknown as Promise<
221
+ GraphQLResult<T>
222
+ >;
223
+ }
224
+
200
225
  this._api.updateRequestToBeCancellable(
201
226
  responsePromise,
202
227
  abortController
@@ -204,7 +229,7 @@ export class InternalGraphQLAPIClass {
204
229
  return responsePromise;
205
230
  case 'subscription':
206
231
  return this._graphqlSubscribe(
207
- amplify,
232
+ amplify as AmplifyClassV6,
208
233
  { query, variables, authMode },
209
234
  headers,
210
235
  customUserAgentDetails
@@ -321,7 +346,7 @@ export class InternalGraphQLAPIClass {
321
346
  // If the exception is because user intentionally
322
347
  // cancelled the request, do not modify the exception
323
348
  // so that clients can identify the exception correctly.
324
- if (this._api.isCancelErrorREST(err)) {
349
+ if (this.isCancelError(err)) {
325
350
  throw err;
326
351
  }
327
352
 
@@ -1,6 +1,5 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
- import { AmplifyClassV6 } from '@aws-amplify/core';
4
3
  import { graphql, cancel, isCancelError } from './v6';
5
4
  import { generateModelsProperty } from './generateModelsProperty';
6
5
  import { V6Client, __amplify, __authMode, __authToken } from '../types';
@@ -1,48 +1,14 @@
1
1
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
2
  // SPDX-License-Identifier: Apache-2.0
3
3
  import { ModelTypes } from '@aws-amplify/amplify-api-next-types-alpha';
4
- import { GraphQLAuthMode } from '@aws-amplify/core/internals/utils';
5
- import {
6
- initializeModel,
7
- generateGraphQLDocument,
8
- buildGraphQLVariables,
9
- graphQLOperationsInfo,
10
- ModelOperation,
11
- flattenItems,
12
- } from './APIClient';
4
+ import { graphQLOperationsInfo, ModelOperation } from './APIClient';
13
5
  import { ClientGenerationParams } from './types';
14
- import {
15
- V6Client,
16
- GraphqlSubscriptionResult,
17
- __authMode,
18
- __authToken,
19
- } from '../types';
20
- import { findIndexByFields, resolvePKFields } from '../utils';
21
- import { Observable, map } from 'rxjs';
6
+ import { V6Client, __authMode, __authToken } from '../types';
22
7
 
23
- type AuthModeParams = {
24
- authMode?: GraphQLAuthMode;
25
- authToken?: string;
26
- };
27
-
28
- /**
29
- * Produces a parameter object that can contains auth mode/token overrides
30
- * only if present in either `options` (first) or configured on the `client`
31
- * as a fallback.
32
- *
33
- * @param client Configured client from `generateClient`
34
- * @param options Args/Options obect from call site.
35
- * @returns
36
- */
37
- function authModeParams(
38
- client: V6Client,
39
- options: AuthModeParams = {}
40
- ): AuthModeParams {
41
- return {
42
- authMode: options.authMode || client[__authMode],
43
- authToken: options.authToken || client[__authToken],
44
- };
45
- }
8
+ import { listFactory } from './operations/list';
9
+ import { getFactory } from './operations/get';
10
+ import { subscriptionFactory } from './operations/subscription';
11
+ import { observeQueryFactory } from './operations/observeQuery';
46
12
 
47
13
  export function generateModelsProperty<T extends Record<any, any> = never>(
48
14
  client: V6Client,
@@ -56,8 +22,8 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
56
22
  return {} as any;
57
23
  }
58
24
 
59
- // TODO: refactor this to use separate methods for each CRUDL.
60
- // Doesn't make sense to gen the methods dynamically given the different args and return values
25
+ const SUBSCRIPTION_OPS = ['ONCREATE', 'ONUPDATE', 'ONDELETE'];
26
+
61
27
  for (const model of Object.values(modelIntrospection.models)) {
62
28
  const { name } = model as any;
63
29
 
@@ -68,306 +34,27 @@ export function generateModelsProperty<T extends Record<any, any> = never>(
68
34
  const operation = key as ModelOperation;
69
35
 
70
36
  if (operation === 'LIST') {
71
- models[name][operationPrefix] = async (args?: any) => {
72
- const query = generateGraphQLDocument(
73
- modelIntrospection.models,
74
- name,
75
- 'LIST',
76
- args
77
- );
78
- const variables = buildGraphQLVariables(
79
- model,
80
- 'LIST',
81
- args,
82
- modelIntrospection
83
- );
84
-
85
- try {
86
- const auth = authModeParams(client, args);
87
-
88
- const { data, extensions } = (await client.graphql({
89
- ...auth,
90
- query,
91
- variables,
92
- })) as any;
93
-
94
- // flatten response
95
- if (data !== undefined) {
96
- const [key] = Object.keys(data);
97
-
98
- if (data[key].items) {
99
- const flattenedResult = flattenItems(data)[key];
100
-
101
- // don't init if custom selection set
102
- if (args?.selectionSet) {
103
- return {
104
- data: flattenedResult,
105
- nextToken: data[key].nextToken,
106
- extensions,
107
- };
108
- } else {
109
- const initialized = initializeModel(
110
- client,
111
- name,
112
- flattenedResult,
113
- modelIntrospection,
114
- auth.authMode,
115
- auth.authToken
116
- );
117
-
118
- return {
119
- data: initialized,
120
- nextToken: data[key].nextToken,
121
- extensions,
122
- };
123
- }
124
- }
125
-
126
- return {
127
- data: data[key],
128
- nextToken: data[key].nextToken,
129
- extensions,
130
- };
131
- }
132
- } catch (error) {
133
- if (error.errors) {
134
- // graphql errors pass through
135
- return error as any;
136
- } else {
137
- // non-graphql errors re re-thrown
138
- throw error;
139
- }
140
- }
141
- };
142
- } else if (['ONCREATE', 'ONUPDATE', 'ONDELETE'].includes(operation)) {
143
- models[name][operationPrefix] = (args?: any) => {
144
- const query = generateGraphQLDocument(
145
- modelIntrospection.models,
146
- name,
147
- operation
148
- );
149
- const variables = buildGraphQLVariables(
150
- model,
151
- operation,
152
- args,
153
- modelIntrospection
154
- );
155
-
156
- const auth = authModeParams(client, args);
157
-
158
- const observable = client.graphql({
159
- ...auth,
160
- query,
161
- variables,
162
- }) as GraphqlSubscriptionResult<object>;
163
-
164
- return observable.pipe(
165
- map(value => {
166
- const [key] = Object.keys(value.data);
167
- const [initialized] = initializeModel(
168
- client,
169
- name,
170
- [value.data[key]],
171
- modelIntrospection,
172
- auth.authMode,
173
- auth.authToken
174
- );
175
- return initialized;
176
- })
177
- );
178
- };
37
+ models[name][operationPrefix] = listFactory(
38
+ client,
39
+ modelIntrospection,
40
+ model
41
+ );
42
+ } else if (SUBSCRIPTION_OPS.includes(operation)) {
43
+ models[name][operationPrefix] = subscriptionFactory(
44
+ client,
45
+ modelIntrospection,
46
+ model,
47
+ operation
48
+ );
179
49
  } else if (operation === 'OBSERVE_QUERY') {
180
- models[name][operationPrefix] = (arg?: any) =>
181
- new Observable(subscriber => {
182
- // what we'll be sending to our subscribers
183
- const items: object[] = [];
184
-
185
- // To enqueue subscription messages while we collect our initial
186
- // result set.
187
- const messageQueue = [] as {
188
- type: 'create' | 'update' | 'delete';
189
- item: object;
190
- }[];
191
-
192
- // operation to take when message(s) arrive.
193
- // this operation will be swapped out once initial "sync" is complete
194
- // to immediately ingest messsages.
195
- let receiveMessages = (...messages: typeof messageQueue) => {
196
- return messageQueue.push(...messages);
197
- };
198
-
199
- // start subscriptions
200
- const onCreateSub = models[name].onCreate(arg).subscribe({
201
- next(item) {
202
- receiveMessages({ item, type: 'create' });
203
- },
204
- error(error) {
205
- subscriber.error({ type: 'onCreate', error });
206
- },
207
- });
208
- const onUpdateSub = models[name].onUpdate(arg).subscribe({
209
- next(item) {
210
- receiveMessages({ item, type: 'update' });
211
- },
212
- error(error) {
213
- subscriber.error({ type: 'onUpdate', error });
214
- },
215
- });
216
- const onDeleteSub = models[name].onDelete(arg).subscribe({
217
- next(item) {
218
- receiveMessages({ item, type: 'delete' });
219
- },
220
- error(error) {
221
- subscriber.error({ type: 'onDelete', error });
222
- },
223
- });
224
-
225
- // consumes a list of messages and sends a snapshot
226
- function ingestMessages(messages: typeof messageQueue) {
227
- for (const message of messages) {
228
- const idx = findIndexByFields(
229
- message.item,
230
- items,
231
- pkFields as any
232
- );
233
- switch (message.type) {
234
- case 'create':
235
- if (idx < 0) items.push(message.item);
236
- break;
237
- case 'update':
238
- if (idx >= 0) items[idx] = message.item;
239
- break;
240
- case 'delete':
241
- if (idx >= 0) items.splice(idx, 1);
242
- break;
243
- default:
244
- console.error(
245
- 'Unrecognized message in observeQuery.',
246
- message
247
- );
248
- }
249
- }
250
- subscriber.next({
251
- items,
252
- isSynced: true,
253
- });
254
- }
255
-
256
- const pkFields = resolvePKFields(model);
257
-
258
- // initial results
259
- (async () => {
260
- let firstPage = true;
261
- let nextToken: string | null = null;
262
- while (!subscriber.closed && (firstPage || nextToken)) {
263
- firstPage = false;
264
-
265
- const {
266
- data: page,
267
- errors,
268
- nextToken: _nextToken,
269
- } = await models[name].list({ ...arg, nextToken });
270
- nextToken = _nextToken;
271
-
272
- items.push(...page);
273
-
274
- // if there are no more pages and no items we already know about
275
- // that need to be merged in from sub, we're "synced"
276
- const isSynced =
277
- messageQueue.length === 0 &&
278
- (nextToken === null || nextToken === undefined);
279
-
280
- subscriber.next({
281
- items,
282
- isSynced,
283
- });
284
-
285
- if (Array.isArray(errors)) {
286
- for (const error of errors) {
287
- subscriber.error(error);
288
- }
289
- }
290
- }
291
-
292
- // play through the queue
293
- if (messageQueue.length > 0) {
294
- ingestMessages(messageQueue);
295
- }
296
-
297
- // switch the queue to write directly to the items collection
298
- receiveMessages = (...messages: typeof messageQueue) => {
299
- ingestMessages(messages);
300
- return items.length;
301
- };
302
- })();
303
-
304
- // when subscriber unsubscribes, tear down internal subs
305
- return () => {
306
- // 1. tear down internal subs
307
- onCreateSub.unsubscribe();
308
- onUpdateSub.unsubscribe();
309
- onDeleteSub.unsubscribe();
310
-
311
- // 2. there is no need to explicitly stop paging. instead, we
312
- // just check `subscriber.closed` above before fetching each page.
313
- };
314
- });
50
+ models[name][operationPrefix] = observeQueryFactory(models, model);
315
51
  } else {
316
- models[name][operationPrefix] = async (arg?: any, options?: any) => {
317
- const query = generateGraphQLDocument(
318
- modelIntrospection.models,
319
- name,
320
- operation,
321
- options
322
- );
323
- const variables = buildGraphQLVariables(
324
- model,
325
- operation,
326
- arg,
327
- modelIntrospection
328
- );
329
-
330
- try {
331
- const auth = authModeParams(client, options);
332
- const { data, extensions } = (await client.graphql({
333
- ...auth,
334
- query,
335
- variables,
336
- })) as any;
337
-
338
- // flatten response
339
- if (data !== undefined) {
340
- const [key] = Object.keys(data);
341
- const flattenedResult = flattenItems(data)[key];
342
-
343
- if (options?.selectionSet) {
344
- return { data: flattenedResult, extensions };
345
- } else {
346
- // TODO: refactor to avoid destructuring here
347
- const [initialized] = initializeModel(
348
- client,
349
- name,
350
- [flattenedResult],
351
- modelIntrospection,
352
- auth.authMode,
353
- auth.authToken
354
- );
355
-
356
- return { data: initialized, extensions };
357
- }
358
- } else {
359
- return { data: null, extensions };
360
- }
361
- } catch (error) {
362
- if (error.errors) {
363
- // graphql errors pass through
364
- return error as any;
365
- } else {
366
- // non-graphql errors re re-thrown
367
- throw error;
368
- }
369
- }
370
- };
52
+ models[name][operationPrefix] = getFactory(
53
+ client,
54
+ modelIntrospection,
55
+ model,
56
+ operation
57
+ );
371
58
  }
372
59
  }
373
60
  );