@aws-amplify/data-schema 0.16.2 → 0.17.1

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 (39) hide show
  1. package/dist/cjs/SchemaProcessor.js +6 -6
  2. package/dist/cjs/SchemaProcessor.js.map +1 -1
  3. package/dist/cjs/runtime/internals/operations/custom.js +33 -5
  4. package/dist/cjs/runtime/internals/operations/custom.js.map +1 -1
  5. package/dist/cjs/runtime/internals/operations/get.js +36 -6
  6. package/dist/cjs/runtime/internals/operations/get.js.map +1 -1
  7. package/dist/cjs/runtime/internals/operations/indexQuery.js +39 -11
  8. package/dist/cjs/runtime/internals/operations/indexQuery.js.map +1 -1
  9. package/dist/cjs/runtime/internals/operations/list.js +50 -6
  10. package/dist/cjs/runtime/internals/operations/list.js.map +1 -1
  11. package/dist/cjs/runtime/internals/operations/utils.js +42 -0
  12. package/dist/cjs/runtime/internals/operations/utils.js.map +1 -0
  13. package/dist/esm/Authorization.d.ts +2 -2
  14. package/dist/esm/MappedTypes/MapSecondaryIndexes.d.ts +2 -2
  15. package/dist/esm/ModelRelationalField.d.ts +1 -1
  16. package/dist/esm/SchemaProcessor.mjs +6 -6
  17. package/dist/esm/SchemaProcessor.mjs.map +1 -1
  18. package/dist/esm/runtime/client/index.d.ts +20 -21
  19. package/dist/esm/runtime/internals/operations/custom.mjs +33 -5
  20. package/dist/esm/runtime/internals/operations/custom.mjs.map +1 -1
  21. package/dist/esm/runtime/internals/operations/get.mjs +36 -6
  22. package/dist/esm/runtime/internals/operations/get.mjs.map +1 -1
  23. package/dist/esm/runtime/internals/operations/indexQuery.mjs +39 -11
  24. package/dist/esm/runtime/internals/operations/indexQuery.mjs.map +1 -1
  25. package/dist/esm/runtime/internals/operations/list.mjs +50 -6
  26. package/dist/esm/runtime/internals/operations/list.mjs.map +1 -1
  27. package/dist/esm/runtime/internals/operations/utils.d.ts +8 -0
  28. package/dist/esm/runtime/internals/operations/utils.mjs +38 -0
  29. package/dist/esm/runtime/internals/operations/utils.mjs.map +1 -0
  30. package/dist/meta/cjs.tsbuildinfo +1 -1
  31. package/package.json +1 -1
  32. package/src/MappedTypes/MapSecondaryIndexes.ts +22 -26
  33. package/src/SchemaProcessor.ts +6 -1
  34. package/src/runtime/client/index.ts +34 -11
  35. package/src/runtime/internals/operations/custom.ts +44 -5
  36. package/src/runtime/internals/operations/get.ts +47 -7
  37. package/src/runtime/internals/operations/indexQuery.ts +43 -11
  38. package/src/runtime/internals/operations/list.ts +63 -7
  39. package/src/runtime/internals/operations/utils.ts +35 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/data-schema",
3
- "version": "0.16.2",
3
+ "version": "0.17.1",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,4 +1,3 @@
1
- import { IsEmptyStringOrNever } from '@aws-amplify/data-schema-types';
2
1
  import { ModelIndexType } from '../ModelIndex';
3
2
 
4
3
  type ModelIndexTypeShape = ModelIndexType<any, any, any, any, any>;
@@ -34,31 +33,28 @@ export type SecondaryIndexToIR<
34
33
  *
35
34
  * @remarks - the IR type alias is defined as SecondaryIndexIrShape in data-schema-types
36
35
  */
37
- type SingleIndexIrFromType<
38
- Idx extends ModelIndexTypeShape,
39
- ResolvedFields,
40
- > = Idx extends ModelIndexType<
41
- any,
42
- infer PK extends string,
43
- infer SK,
44
- infer QueryField extends string | never,
45
- any
46
- >
47
- ? {
48
- queryField: IsEmptyStringOrNever<QueryField> extends true
49
- ? `listBy${QueryFieldLabelFromTuple<SK, Capitalize<PK>>}`
50
- : QueryField;
51
- pk: PK extends keyof ResolvedFields
52
- ? {
53
- [Key in PK]: Exclude<ResolvedFields[PK], null>;
54
- }
55
- : never;
56
- // distribute ResolvedFields over SK
57
- sk: unknown extends SK
58
- ? never
59
- : ResolvedSortKeyFields<SK, ResolvedFields>;
60
- }
61
- : never;
36
+ type SingleIndexIrFromType<Idx extends ModelIndexTypeShape, ResolvedFields> =
37
+ Idx extends ModelIndexType<
38
+ any,
39
+ infer PK extends string,
40
+ infer SK,
41
+ infer QueryField extends string | never,
42
+ any
43
+ >
44
+ ? {
45
+ defaultQueryFieldSuffix: `${QueryFieldLabelFromTuple<SK, Capitalize<PK>>}`;
46
+ queryField: QueryField;
47
+ pk: PK extends keyof ResolvedFields
48
+ ? {
49
+ [Key in PK]: Exclude<ResolvedFields[PK], null>;
50
+ }
51
+ : never;
52
+ // distribute ResolvedFields over SK
53
+ sk: unknown extends SK
54
+ ? never
55
+ : ResolvedSortKeyFields<SK, ResolvedFields>;
56
+ }
57
+ : never;
62
58
 
63
59
  /**
64
60
  * @typeParam SK - tuple of SortKey field names, e.g. ['viewCount', 'createdAt']
@@ -810,12 +810,13 @@ type TransformedSecondaryIndexes = {
810
810
  * @returns default query field name
811
811
  */
812
812
  const secondaryIndexDefaultQueryField = (
813
+ modelName: string,
813
814
  pk: string,
814
815
  sk?: readonly string[],
815
816
  ): string => {
816
817
  const skName = sk?.length ? 'And' + sk?.map(capitalize).join('And') : '';
817
818
 
818
- const queryField = `listBy${capitalize(pk)}${skName}`;
819
+ const queryField = `list${capitalize(modelName)}By${capitalize(pk)}${skName}`;
819
820
 
820
821
  return queryField;
821
822
  };
@@ -825,6 +826,7 @@ const secondaryIndexDefaultQueryField = (
825
826
  * and the value is an array of transformed Amplify @index directives with all supplied attributes
826
827
  */
827
828
  const transformedSecondaryIndexesForModel = (
829
+ modelName: string,
828
830
  secondaryIndexes: readonly InternalModelIndexType[],
829
831
  ): TransformedSecondaryIndexes => {
830
832
  const indexDirectiveWithAttributes = (
@@ -835,6 +837,7 @@ const transformedSecondaryIndexesForModel = (
835
837
  ): string => {
836
838
  if (!sortKeys.length && !indexName && !queryField) {
837
839
  return `@index(queryField: "${secondaryIndexDefaultQueryField(
840
+ modelName,
838
841
  partitionKey,
839
842
  )}")`;
840
843
  }
@@ -856,6 +859,7 @@ const transformedSecondaryIndexesForModel = (
856
859
  } else {
857
860
  attributes.push(
858
861
  `queryField: "${secondaryIndexDefaultQueryField(
862
+ modelName,
859
863
  partitionKey,
860
864
  sortKeys,
861
865
  )}"`,
@@ -1164,6 +1168,7 @@ const schemaPreprocessor = (
1164
1168
  const [partitionKey] = identifier;
1165
1169
 
1166
1170
  const transformedSecondaryIndexes = transformedSecondaryIndexesForModel(
1171
+ typeName,
1167
1172
  typeDef.data.secondaryIndexes,
1168
1173
  );
1169
1174
 
@@ -8,6 +8,7 @@ import {
8
8
  Equal,
9
9
  __modelMeta__,
10
10
  ExtractModelMeta,
11
+ IsEmptyStringOrNever,
11
12
  } from '@aws-amplify/data-schema-types';
12
13
  import type { Observable } from 'rxjs';
13
14
 
@@ -494,10 +495,11 @@ type ModelMetaShape = {
494
495
 
495
496
  // TODO: remove export. added for debugging.
496
497
  export type ModelTypesClient<
498
+ ModelName extends string,
497
499
  Model extends Record<string, unknown>,
498
500
  ModelMeta extends ModelMetaShape,
499
501
  FlatModel extends Record<string, unknown> = ResolvedModel<Model>,
500
- > = IndexQueryMethodsFromIR<ModelMeta['secondaryIndexes'], Model> & {
502
+ > = IndexQueryMethodsFromIR<ModelMeta['secondaryIndexes'], ModelName, Model> & {
501
503
  create: (
502
504
  model: Prettify<CreateModelInput<Model, ModelMeta>>,
503
505
  options?: {
@@ -589,10 +591,11 @@ export type ModelTypesClient<
589
591
  };
590
592
 
591
593
  type ModelTypesSSRCookies<
594
+ ModelName extends string,
592
595
  Model extends Record<string, unknown>,
593
596
  ModelMeta extends ModelMetaShape,
594
597
  FlatModel extends Record<string, unknown> = ResolvedModel<Model>,
595
- > = IndexQueryMethodsFromIR<ModelMeta['secondaryIndexes'], Model> & {
598
+ > = IndexQueryMethodsFromIR<ModelMeta['secondaryIndexes'], ModelName, Model> & {
596
599
  create: (
597
600
  model: Prettify<CreateModelInput<Model, ModelMeta>>,
598
601
  options?: {
@@ -641,10 +644,11 @@ type ModelTypesSSRCookies<
641
644
  };
642
645
 
643
646
  type ModelTypesSSRRequest<
647
+ ModelName extends string,
644
648
  Model extends Record<string, unknown>,
645
649
  ModelMeta extends ModelMetaShape,
646
650
  FlatModel extends Record<string, unknown> = ResolvedModel<Model>,
647
- > = IndexQueryMethodsFromIR<ModelMeta['secondaryIndexes'], Model> & {
651
+ > = IndexQueryMethodsFromIR<ModelMeta['secondaryIndexes'], ModelName, Model> & {
648
652
  create: (
649
653
  // TODO: actual type
650
654
  contextSpec: any,
@@ -716,11 +720,19 @@ export type ModelTypes<
716
720
  >]: ModelName extends string
717
721
  ? Schema[ModelName] extends Record<string, unknown>
718
722
  ? Context extends 'CLIENT'
719
- ? ModelTypesClient<Schema[ModelName], ModelMeta[ModelName]>
723
+ ? ModelTypesClient<ModelName, Schema[ModelName], ModelMeta[ModelName]>
720
724
  : Context extends 'COOKIES'
721
- ? ModelTypesSSRCookies<Schema[ModelName], ModelMeta[ModelName]>
725
+ ? ModelTypesSSRCookies<
726
+ ModelName,
727
+ Schema[ModelName],
728
+ ModelMeta[ModelName]
729
+ >
722
730
  : Context extends 'REQUEST'
723
- ? ModelTypesSSRRequest<Schema[ModelName], ModelMeta[ModelName]>
731
+ ? ModelTypesSSRRequest<
732
+ ModelName,
733
+ Schema[ModelName],
734
+ ModelMeta[ModelName]
735
+ >
724
736
  : never
725
737
  : never
726
738
  : never;
@@ -847,6 +859,7 @@ export type CustomHeaders =
847
859
  * SecondaryIndex index types and query methods
848
860
  */
849
861
  export type SecondaryIndexIrShape = {
862
+ defaultQueryFieldSuffix: string;
850
863
  queryField: string;
851
864
  pk: { [key: string]: string | number };
852
865
  sk: { [key: string]: string | number };
@@ -854,20 +867,30 @@ export type SecondaryIndexIrShape = {
854
867
 
855
868
  type IndexQueryMethodsFromIR<
856
869
  SecondaryIdxTuple extends SecondaryIndexIrShape[],
870
+ ModelName extends string,
857
871
  Model extends Record<string, unknown>,
858
872
  Res = unknown, // defaulting `unknown` because it gets absorbed in an intersection, e.g. `{a: 1} & unknown` => `{a: 1}`
859
873
  > = SecondaryIdxTuple extends [
860
874
  infer A extends SecondaryIndexIrShape,
861
875
  ...infer B extends SecondaryIndexIrShape[],
862
876
  ]
863
- ? IndexQueryMethodsFromIR<B, Model, IndexQueryMethodSignature<A, Model> & Res>
877
+ ? IndexQueryMethodsFromIR<
878
+ B,
879
+ ModelName,
880
+ Model,
881
+ IndexQueryMethodSignature<A, ModelName, Model> & Res
882
+ >
864
883
  : Res;
865
884
 
866
885
  type IndexQueryMethodSignature<
867
886
  Idx extends SecondaryIndexIrShape,
887
+ ModelName extends string,
868
888
  Model extends Record<string, unknown>,
869
- > = {
870
- [K in Idx['queryField'] & string]: <
889
+ > = Record<
890
+ IsEmptyStringOrNever<Idx['queryField']> extends false
891
+ ? Idx['queryField']
892
+ : `list${ModelName}By${Idx['defaultQueryFieldSuffix']}`,
893
+ <
871
894
  FlatModel extends Record<string, unknown> = ResolvedModel<Model>,
872
895
  SelectionSet extends ReadonlyArray<ModelPath<FlatModel>> = never[],
873
896
  >(
@@ -886,8 +909,8 @@ type IndexQueryMethodSignature<
886
909
  authToken?: string;
887
910
  headers?: CustomHeaders;
888
911
  },
889
- ) => ListReturnValue<Prettify<ReturnValue<Model, FlatModel, SelectionSet>>>;
890
- };
912
+ ) => ListReturnValue<Prettify<ReturnValue<Model, FlatModel, SelectionSet>>>
913
+ >;
891
914
 
892
915
  type FilteredKeys<T> = {
893
916
  [P in keyof T]: T[P] extends never ? never : P;
@@ -27,6 +27,8 @@ import {
27
27
  selectionSetIRToString,
28
28
  } from '../APIClient';
29
29
 
30
+ import { handleSingularGraphQlError } from './utils';
31
+
30
32
  type CustomOperationOptions = AuthModeParams & ListArgs;
31
33
 
32
34
  // these are the 4 possible sets of arguments custom operations methods can receive
@@ -417,12 +419,49 @@ async function _op(
417
419
  return { data: null, extensions };
418
420
  }
419
421
  } catch (error: any) {
420
- if (error.errors) {
421
- // graphql errors pass through
422
- return error as any;
422
+ /**
423
+ * The `data` type returned by `error` here could be:
424
+ * 1) `null`
425
+ * 2) an empty object
426
+ * 3) "populated" but with a `null` value `{ getPost: null }`
427
+ * 4) an actual record `{ getPost: { id: '1', title: 'Hello, World!' } }`
428
+ */
429
+ const { data, errors } = error;
430
+
431
+ /**
432
+ * `data` is not `null`, and is not an empty object:
433
+ */
434
+ if (data && Object.keys(data).length !== 0 && errors) {
435
+ const [key] = Object.keys(data);
436
+ const flattenedResult = flattenItems(data)[key];
437
+
438
+ /**
439
+ * `flattenedResult` could be `null` here (e.g. `data: { getPost: null }`)
440
+ * if `flattenedResult`, result is an actual record:
441
+ */
442
+ if (flattenedResult) {
443
+ // TODO: custom selection set. current selection set is default selection set only
444
+ // custom selection set requires data-schema-type + runtime updates above.
445
+ const [initialized] = returnTypeModelName
446
+ ? initializeModel(
447
+ client,
448
+ returnTypeModelName,
449
+ [flattenedResult],
450
+ modelIntrospection,
451
+ auth.authMode,
452
+ auth.authToken,
453
+ !!context,
454
+ )
455
+ : [flattenedResult];
456
+
457
+ return { data: initialized, errors };
458
+ } else {
459
+ // was `data: { getPost: null }`)
460
+ return handleSingularGraphQlError(error);
461
+ }
423
462
  } else {
424
- // non-graphql errors re re-thrown
425
- throw error;
463
+ // `data` is `null`:
464
+ return handleSingularGraphQlError(error);
426
465
  }
427
466
  }
428
467
  }
@@ -25,6 +25,8 @@ import {
25
25
  initializeModel,
26
26
  } from '../APIClient';
27
27
 
28
+ import { handleSingularGraphQlError } from './utils';
29
+
28
30
  export function getFactory(
29
31
  client: BaseClient,
30
32
  modelIntrospection: ModelIntrospectionSchema,
@@ -90,9 +92,9 @@ async function _get(
90
92
  modelIntrospection,
91
93
  );
92
94
 
93
- try {
94
- const auth = authModeParams(client, getInternals, options);
95
+ const auth = authModeParams(client, getInternals, options);
95
96
 
97
+ try {
96
98
  const headers = getCustomHeaders(client, getInternals, options?.headers);
97
99
 
98
100
  const { data, extensions } = context
@@ -139,12 +141,50 @@ async function _get(
139
141
  return { data: null, extensions };
140
142
  }
141
143
  } catch (error: any) {
142
- if (error.errors) {
143
- // graphql errors pass through
144
- return error as any;
144
+ /**
145
+ * The `data` type returned by `error` here could be:
146
+ * 1) `null`
147
+ * 2) an empty object
148
+ * 3) "populated" but with a `null` value `{ getPost: null }`
149
+ * 4) an actual record `{ getPost: { id: '1', title: 'Hello, World!' } }`
150
+ */
151
+ const { data, errors } = error;
152
+
153
+ /**
154
+ * `data` is not `null`, and is not an empty object:
155
+ */
156
+ if (data && Object.keys(data).length !== 0 && errors) {
157
+ const [key] = Object.keys(data);
158
+ const flattenedResult = flattenItems(data)[key];
159
+
160
+ /**
161
+ * `flattenedResult` could be `null` here (e.g. `data: { getPost: null }`)
162
+ * if `flattenedResult`, result is an actual record:
163
+ */
164
+ if (flattenedResult) {
165
+ if (options?.selectionSet) {
166
+ return { data: flattenedResult, errors };
167
+ } else {
168
+ // TODO: refactor to avoid destructuring here
169
+ const [initialized] = initializeModel(
170
+ client,
171
+ name,
172
+ [flattenedResult],
173
+ modelIntrospection,
174
+ auth.authMode,
175
+ auth.authToken,
176
+ !!context,
177
+ );
178
+
179
+ return { data: initialized, errors };
180
+ }
181
+ } else {
182
+ // was `data: { getPost: null }`)
183
+ return handleSingularGraphQlError(error);
184
+ }
145
185
  } else {
146
- // non-graphql errors re re-thrown
147
- throw error;
186
+ // `data` is `null`:
187
+ return handleSingularGraphQlError(error);
148
188
  }
149
189
  }
150
190
  }
@@ -21,6 +21,8 @@ import {
21
21
  initializeModel,
22
22
  } from '../APIClient';
23
23
 
24
+ import { handleListGraphQlError } from './utils';
25
+
24
26
  export interface IndexMeta {
25
27
  queryField: string;
26
28
  pk: string;
@@ -97,16 +99,6 @@ function processGraphQlResponse(
97
99
  };
98
100
  }
99
101
 
100
- function handleGraphQlError(error: any) {
101
- if (error.errors) {
102
- // graphql errors pass through
103
- return error as any;
104
- } else {
105
- // non-graphql errors re re-thrown
106
- throw error;
107
- }
108
- }
109
-
110
102
  async function _indexQuery(
111
103
  client: BaseClient,
112
104
  modelIntrospection: ModelIntrospectionSchema,
@@ -173,6 +165,46 @@ async function _indexQuery(
173
165
  );
174
166
  }
175
167
  } catch (error: any) {
176
- return handleGraphQlError(error);
168
+ /**
169
+ * The `data` type returned by `error` here could be:
170
+ * 1) `null`
171
+ * 2) an empty object
172
+ * 3) "populated" but with a `null` value:
173
+ * `data: { listByExampleId: null }`
174
+ * 4) an actual record:
175
+ * `data: { listByExampleId: items: [{ id: '1', ...etc } }]`
176
+ */
177
+ const { data, errors } = error;
178
+
179
+ // `data` is not `null`, and is not an empty object:
180
+ if (data !== undefined && Object.keys(data).length !== 0 && errors) {
181
+ const [key] = Object.keys(data);
182
+
183
+ if (data[key]?.items) {
184
+ const flattenedResult = flattenItems(data)[key];
185
+
186
+ /**
187
+ * Check exists since `flattenedResult` could be `null`.
188
+ * if `flattenedResult` exists, result is an actual record.
189
+ */
190
+ if (flattenedResult) {
191
+ return {
192
+ data: args?.selectionSet
193
+ ? flattenedResult
194
+ : modelInitializer(flattenedResult),
195
+ nextToken: data[key]?.nextToken,
196
+ };
197
+ }
198
+ }
199
+
200
+ // response is of type `data: { listByExampleId: null }`
201
+ return {
202
+ data: data[key],
203
+ nextToken: data[key]?.nextToken,
204
+ };
205
+ } else {
206
+ // `data` is `null` or an empty object:
207
+ return handleListGraphQlError(error);
208
+ }
177
209
  }
178
210
  }
@@ -22,6 +22,8 @@ import {
22
22
  initializeModel,
23
23
  } from '../APIClient';
24
24
 
25
+ import { handleListGraphQlError } from './utils';
26
+
25
27
  export function listFactory(
26
28
  client: BaseClient,
27
29
  modelIntrospection: ModelIntrospectionSchema,
@@ -68,9 +70,9 @@ async function _list(
68
70
  modelIntrospection,
69
71
  );
70
72
 
71
- try {
72
- const auth = authModeParams(client, getInternals, args);
73
+ const auth = authModeParams(client, getInternals, args);
73
74
 
75
+ try {
74
76
  const headers = getCustomHeaders(client, getInternals, args?.headers);
75
77
 
76
78
  const { data, extensions } = contextSpec
@@ -132,12 +134,66 @@ async function _list(
132
134
  };
133
135
  }
134
136
  } catch (error: any) {
135
- if (error.errors) {
136
- // graphql errors pass through
137
- return error as any;
137
+ /**
138
+ * The `data` type returned by `error` here could be:
139
+ * 1) `null`
140
+ * 2) an empty object
141
+ * 3) "populated" but with a `null` value `data: { listPosts: null }`
142
+ * 4) actual records `data: { listPosts: items: [{ id: '1', ...etc }] }`
143
+ */
144
+ const { data, errors } = error;
145
+
146
+ // `data` is not `null`, and is not an empty object:
147
+ if (data !== undefined && Object.keys(data).length !== 0 && errors) {
148
+ const [key] = Object.keys(data);
149
+
150
+ if (data[key]?.items) {
151
+ const flattenedResult = flattenItems(data)[key];
152
+
153
+ /**
154
+ * Check exists since `flattenedResult` could be `null`.
155
+ * if `flattenedResult` exists, result is an actual record.
156
+ */
157
+ if (flattenedResult) {
158
+ // don't init if custom selection set
159
+ if (args?.selectionSet) {
160
+ return {
161
+ data: flattenedResult,
162
+ nextToken: data[key]?.nextToken,
163
+ errors,
164
+ };
165
+ } else {
166
+ const initialized = initializeModel(
167
+ client,
168
+ name,
169
+ flattenedResult,
170
+ modelIntrospection,
171
+ auth.authMode,
172
+ auth.authToken,
173
+ !!contextSpec,
174
+ );
175
+
176
+ // data is full record w/out selection set:
177
+ return {
178
+ data: initialized,
179
+ nextToken: data[key]?.nextToken,
180
+ errors,
181
+ };
182
+ }
183
+ }
184
+
185
+ return {
186
+ data: data[key],
187
+ nextToken: data[key]?.nextToken,
188
+ errors,
189
+ };
190
+ } else {
191
+ // response is of type `data: { getPost: null }`)
192
+ return handleListGraphQlError(error);
193
+ }
138
194
  } else {
139
- // non-graphql errors re re-thrown
140
- throw error;
195
+ // `data` is `null` or an empty object:
196
+ return handleListGraphQlError(error);
141
197
  }
142
198
  }
143
199
  }
@@ -0,0 +1,35 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // import { GraphQLFormattedError } from '@aws-amplify/data-schema-types';
4
+
5
+ /**
6
+ * Handle errors for list return types (list and index query operations)
7
+ */
8
+ export function handleListGraphQlError(error: any) {
9
+ if (error?.errors) {
10
+ // graphql errors pass through
11
+ return {
12
+ ...error,
13
+ data: [],
14
+ } as any;
15
+ } else {
16
+ // non-graphql errors are re-thrown
17
+ throw error;
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Handle errors for singular return types (create, get, update, delete operations)
23
+ */
24
+ export function handleSingularGraphQlError(error: any) {
25
+ if (error.errors) {
26
+ // graphql errors pass through
27
+ return {
28
+ ...error,
29
+ data: null,
30
+ } as any;
31
+ } else {
32
+ // non-graphql errors are re-thrown
33
+ throw error;
34
+ }
35
+ }