@aws-amplify/data-schema 0.13.14 → 0.13.16

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.
@@ -4,7 +4,7 @@ import type { ResolveSchema, SchemaTypes } from './MappedTypes/ResolveSchema';
4
4
  import type { CreateImplicitModelsFromRelations, ResolveFieldProperties } from './MappedTypes/ResolveFieldProperties';
5
5
  import type { ModelIdentifier, ModelSecondaryIndexes, RelationalMetadata } from './MappedTypes/ModelMetadata';
6
6
  import type { ExtractNonModelTypes, NonModelTypesShape } from './MappedTypes/ExtractNonModelTypes';
7
- import type { ResolveCustomOperations } from './MappedTypes/CustomOperations';
7
+ import { ResolveCustomOperations, CustomOperationHandlerTypes } from './MappedTypes/CustomOperations';
8
8
  export type ClientSchema<Schema extends ModelSchema<any, any>> = InternalClientSchema<Schema>;
9
9
  /**
10
10
  * Types for unwrapping generic type args into client-consumable types
@@ -28,7 +28,7 @@ type InternalClientSchema<Schema extends ModelSchema<any, any>, NonModelTypes ex
28
28
  [ImplicitModel in keyof ImplicitModels]: {
29
29
  identifier: 'id';
30
30
  };
31
- }, ResolvedFields extends Record<string, unknown> = ResolveFieldProperties<Schema, NonModelTypes, ImplicitModels>, IdentifierMeta extends Record<string, any> = ModelIdentifier<SchemaTypes<Schema>>, SecondaryIndexes extends Record<string, any> = ModelSecondaryIndexes<SchemaTypes<Schema>>> = ResolvedFields & {
31
+ }, ResolvedFields extends Record<string, unknown> = ResolveFieldProperties<Schema, NonModelTypes, ImplicitModels>, IdentifierMeta extends Record<string, any> = ModelIdentifier<SchemaTypes<Schema>>, SecondaryIndexes extends Record<string, any> = ModelSecondaryIndexes<SchemaTypes<Schema>>> = ResolvedFields & CustomOperationHandlerTypes<ResolveCustomOperations<Schema, ResolvedFields, NonModelTypes>['customOperations']> & ResolvedFields & {
32
32
  [__modelMeta__]: IdentifierMeta & ImplicitModelsIdentifierMeta & SecondaryIndexes & RelationalMetadata<ResolvedSchema, ResolvedFields, IdentifierMeta> & NonModelTypes & ResolveCustomOperations<Schema, ResolvedFields, NonModelTypes>;
33
33
  };
34
34
  export {};
@@ -4,6 +4,7 @@ import type { CustomOperation, CustomOperationParamShape } from '../CustomOperat
4
4
  import type { ModelField } from '../ModelField';
5
5
  import type { RefType, RefTypeParamShape } from '../RefType';
6
6
  import type { ResolveRefsOfCustomType, ResolveRefValueArrayTraits } from './ResolveFieldProperties';
7
+ import type { AppSyncResolverHandler } from 'aws-lambda';
7
8
  /**
8
9
  * Creates meta types for custom operations from a schema.
9
10
  */
@@ -44,3 +45,78 @@ export type CustomOpReturnType<Shape extends CustomOperationParamShape, FullyRes
44
45
  * with the addition that allows .ref() a model with custom operations.
45
46
  */
46
47
  export type ResolveRef<Shape extends RefTypeParamShape, FullyResolvedSchema extends Record<string, unknown>, NonModelTypes extends NonModelTypesShape, Link = Shape['link'], RefValue = Link extends keyof FullyResolvedSchema ? FullyResolvedSchema[Link] : Link extends keyof NonModelTypes['enums'] ? NonModelTypes['enums'][Link] : Link extends keyof NonModelTypes['customTypes'] ? ResolveRefsOfCustomType<NonModelTypes, NonModelTypes['customTypes'][Link]> : never, Value = Shape['valueRequired'] extends true ? RefValue : RefValue | null> = ResolveRefValueArrayTraits<Shape, Value>;
48
+ /**
49
+ * The kind of shape we need to map to custom handler (e.g., lambda) function
50
+ * signatures.
51
+ */
52
+ type CustomOperationsMap = Record<string, CustomOperationMinimalDef>;
53
+ /**
54
+ * The minimal amount of structure needed to extract types for a custom handler.
55
+ */
56
+ type CustomOperationMinimalDef = {
57
+ arguments: any;
58
+ returnType: any;
59
+ };
60
+ /**
61
+ * Derives the signature and types for a lambda handler for a particular
62
+ * custom Query or Mutation from a Schema.
63
+ */
64
+ type IndvidualCustomHandlerTypes<Op extends CustomOperationMinimalDef> = {
65
+ /**
66
+ * Handler type for lambda function implementations. E.g.,
67
+ *
68
+ * ```typescript
69
+ * import type { Schema } from './resource';
70
+ *
71
+ * export const handler: Schema['echo']['functionHandler'] = async (event, context) => {
72
+ * // event and context will be fully typed inside here.
73
+ * }
74
+ * ```
75
+ */
76
+ functionHandler: AppSyncResolverHandler<Op['arguments'], LambdaReturnType<Op['returnType']>>;
77
+ /**
78
+ * The `context.arguments` type for lambda function implementations.
79
+ *
80
+ * ```typescript
81
+ * import type { Schema } from './resource';
82
+ *
83
+ * export const handler: Schema['echo']['functionHandler'] = async (event, context) => {
84
+ * // Provides this type, if needed:
85
+ * const args: Schema['echo']['functionHandlerArguments'] = event.arguments;
86
+ * }
87
+ * ```
88
+ */
89
+ functionHandlerArguments: Op['arguments'];
90
+ /**
91
+ * The return type expected by a lambda function handler.
92
+ *
93
+ * ```typescript
94
+ * import type { Schema } from './resource';
95
+ *
96
+ * export const handler: Schema['echo']['functionHandler'] = async (event, context) => {
97
+ * // Result type enforced here:
98
+ * const result: Schema['echo']['functionHandlerResult'] = buildResult(...);
99
+ *
100
+ * // `Result` type matches expected function return type here:
101
+ * return result;
102
+ * }
103
+ * ```
104
+ */
105
+ functionHandlerResult: LambdaReturnType<Op['returnType']>;
106
+ };
107
+ /**
108
+ * Derives the function signatures for a lambda handlers for all the provided
109
+ * custom queries and mutations.
110
+ */
111
+ export type CustomOperationHandlerTypes<CustomOperations extends CustomOperationsMap> = {
112
+ [K in keyof CustomOperations]: IndvidualCustomHandlerTypes<CustomOperations[K]>;
113
+ };
114
+ /**
115
+ * Returns a return type with lazy loaders removed.
116
+ *
117
+ * (Custom handlers should not return lazy loaded fields -- they're *lazy loaded*.)
118
+ */
119
+ type LambdaReturnType<T> = T extends Record<string, any> ? {
120
+ [K in keyof Exclude<T, null | undefined> as Exclude<T, null | undefined>[K] extends (...args: any) => any ? never : K]: Exclude<T, null | undefined>[K];
121
+ } : T | (null extends T ? null : never) | (undefined extends T ? undefined : never);
122
+ export {};
@@ -164,8 +164,8 @@ function transformFunctionHandler(handlers, callSignature) {
164
164
  gqlHandlerContent += `@function(name: "${handlerData}") `;
165
165
  }
166
166
  else if (typeof handlerData.getInstance === 'function') {
167
- const fnBaseName = `Fn_${callSignature}`;
168
- const fnNameSuffix = idx === 0 ? '' : `_${idx + 1}`;
167
+ const fnBaseName = `Fn${capitalize(callSignature)}`;
168
+ const fnNameSuffix = idx === 0 ? '' : `${idx + 1}`;
169
169
  const fnName = fnBaseName + fnNameSuffix;
170
170
  lambdaFunctionDefinition[fnName] = handlerData;
171
171
  gqlHandlerContent += `@function(name: "${fnName}") `;
@@ -271,6 +271,27 @@ function addFields(existing, additions) {
271
271
  }
272
272
  }
273
273
  }
274
+ /**
275
+ * Validate that no implicit fields are used by the model definition
276
+ *
277
+ * @param existing An existing field map
278
+ * @param implicitFields A field map inferred from other schema usage
279
+ *
280
+ * @throws An error when an undefined field is used or when a field is used in a way that conflicts with its generated definition
281
+ */
282
+ function validateStaticFields(existing, implicitFields) {
283
+ if (implicitFields === undefined) {
284
+ return;
285
+ }
286
+ for (const [k, field] of Object.entries(implicitFields)) {
287
+ if (!existing[k]) {
288
+ throw new Error(`Field ${k} isn't defined.`);
289
+ }
290
+ else if (areConflicting(existing[k], field)) {
291
+ throw new Error(`Field ${k} defined twice with conflicting definitions.`);
292
+ }
293
+ }
294
+ }
274
295
  /**
275
296
  * Produces a new field definition object from every field definition object
276
297
  * given as an argument. Performs validation (conflict detection) as objects
@@ -721,6 +742,7 @@ const schemaPreprocessor = (schema) => {
721
742
  const databaseType = schema.data.configuration.database.engine === 'dynamodb'
722
743
  ? 'dynamodb'
723
744
  : 'sql';
745
+ const staticSchema = schema.data.configuration.database.engine === 'dynamodb' ? false : true;
724
746
  const fkFields = allImpliedFKs(schema);
725
747
  const topLevelTypes = Object.entries(schema.data.types);
726
748
  const { schemaAuth, functionSchemaAccess } = extractFunctionSchemaAccess(schema.data.authorization);
@@ -772,6 +794,23 @@ const schemaPreprocessor = (schema) => {
772
794
  }
773
795
  }
774
796
  }
797
+ else if (staticSchema) {
798
+ const fields = { ...typeDef.data.fields };
799
+ const identifier = typeDef.data.identifier;
800
+ const [partitionKey] = identifier;
801
+ validateStaticFields(fields, fkFields[typeName]);
802
+ const { authString, authFields } = calculateAuth(mostRelevantAuthRules);
803
+ if (authString == '') {
804
+ throw new Error(`Model \`${typeName}\` is missing authorization rules. Add global rules to the schema or ensure every model has its own rules.`);
805
+ }
806
+ const fieldLevelAuthRules = processFieldLevelAuthRules(fields, authFields);
807
+ validateStaticFields(fields, authFields);
808
+ const { gqlFields, models } = processFields(typeName, fields, fieldLevelAuthRules, identifier, partitionKey);
809
+ topLevelTypes.push(...models);
810
+ const joined = gqlFields.join('\n ');
811
+ const model = `type ${typeName} @model ${authString}\n{\n ${joined}\n}`;
812
+ gqlModels.push(model);
813
+ }
775
814
  else {
776
815
  const fields = mergeFieldObjects(typeDef.data.fields, fkFields[typeName]);
777
816
  const identifier = typeDef.data.identifier;