@aws-amplify/data-schema 0.14.2 → 0.14.4
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.
|
@@ -25,16 +25,21 @@ type BackendSecret = {
|
|
|
25
25
|
resolvePath: (backendIdentifier: any) => any;
|
|
26
26
|
};
|
|
27
27
|
export type DatasourceEngine = 'mysql' | 'postgresql' | 'dynamodb';
|
|
28
|
+
type SubnetAZ = {
|
|
29
|
+
subnetId: string;
|
|
30
|
+
availabilityZone: string;
|
|
31
|
+
};
|
|
32
|
+
type VpcConfig = {
|
|
33
|
+
vpcId: string;
|
|
34
|
+
securityGroupIds: string[];
|
|
35
|
+
subnetAvailabilityZones: SubnetAZ[];
|
|
36
|
+
};
|
|
28
37
|
type DatasourceConfig<DE extends DatasourceEngine> = DE extends 'dynamodb' ? {
|
|
29
38
|
engine: DE;
|
|
30
39
|
} : {
|
|
31
40
|
engine: DE;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
password: BackendSecret;
|
|
35
|
-
port: BackendSecret;
|
|
36
|
-
databaseName: BackendSecret;
|
|
37
|
-
vpcConfig?: Record<string, never>;
|
|
41
|
+
connectionUri: BackendSecret;
|
|
42
|
+
vpcConfig?: VpcConfig;
|
|
38
43
|
};
|
|
39
44
|
export type SchemaConfig<DE extends DatasourceEngine, DC extends DatasourceConfig<DE>> = {
|
|
40
45
|
database: DC;
|
|
@@ -198,7 +198,7 @@ function customOperationToGql(typeName, typeDef, authorization, isCustom = false
|
|
|
198
198
|
throw new Error(`Unrecognized return type on ${typeName}`);
|
|
199
199
|
}
|
|
200
200
|
if (Object.keys(fieldArgs).length > 0) {
|
|
201
|
-
const { gqlFields, models } = processFields(typeName, fieldArgs, {});
|
|
201
|
+
const { gqlFields, models } = processFields(typeName, fieldArgs, {}, {});
|
|
202
202
|
callSignature += `(${gqlFields.join(', ')})`;
|
|
203
203
|
implicitModels.push(...models);
|
|
204
204
|
}
|
|
@@ -307,6 +307,24 @@ function validateStaticFields(existing, implicitFields) {
|
|
|
307
307
|
}
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Validate that no implicit fields conflict with explicitly defined fields.
|
|
312
|
+
*
|
|
313
|
+
* @param existing An existing field map
|
|
314
|
+
* @param implicitFields A field map inferred from other schema usage
|
|
315
|
+
*
|
|
316
|
+
* @throws An error when an undefined field is used or when a field is used in a way that conflicts with its generated definition
|
|
317
|
+
*/
|
|
318
|
+
function validateImpliedFields(existing, implicitFields) {
|
|
319
|
+
if (implicitFields === undefined) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
for (const [k, field] of Object.entries(implicitFields)) {
|
|
323
|
+
if (existing[k] && areConflicting(existing[k], field)) {
|
|
324
|
+
throw new Error(`Implicit field ${k} conflicts with the explicit field definition.`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
310
328
|
/**
|
|
311
329
|
* Produces a new field definition object from every field definition object
|
|
312
330
|
* given as an argument. Performs validation (conflict detection) as objects
|
|
@@ -344,7 +362,8 @@ function validateAuth(authorization = []) {
|
|
|
344
362
|
*
|
|
345
363
|
* The computed directives are intended to be appended to the graphql field definition.
|
|
346
364
|
*
|
|
347
|
-
* The computed fields
|
|
365
|
+
* The computed fields will be used to confirm no conflicts between explicit field definitions
|
|
366
|
+
* and implicit auth fields.
|
|
348
367
|
*
|
|
349
368
|
* @param authorization A list of authorization rules.
|
|
350
369
|
* @returns
|
|
@@ -590,35 +609,6 @@ const allImpliedFKs = (schema) => {
|
|
|
590
609
|
}
|
|
591
610
|
return fks;
|
|
592
611
|
};
|
|
593
|
-
/**
|
|
594
|
-
* Determines if implicit date fields are in effect for a given model. If they are,
|
|
595
|
-
* returns those implicit fields.
|
|
596
|
-
*
|
|
597
|
-
* NOTE: For now, we *only* support the default implicit fields.
|
|
598
|
-
*
|
|
599
|
-
* @param _model Model to find date fields for.
|
|
600
|
-
*/
|
|
601
|
-
const implicitTimestampFields = (_model) => {
|
|
602
|
-
return {
|
|
603
|
-
createdAt: (0, ModelField_1.datetime)().required(),
|
|
604
|
-
updatedAt: (0, ModelField_1.datetime)().required(),
|
|
605
|
-
};
|
|
606
|
-
};
|
|
607
|
-
/**
|
|
608
|
-
* Generates default Pk fields for a model, based on identifier designation.
|
|
609
|
-
*
|
|
610
|
-
* The fields from this function are just default values. They should be overridden
|
|
611
|
-
* by ID field definitions that are explicit in the model.
|
|
612
|
-
*
|
|
613
|
-
* @param _model Model to find PK fields for.
|
|
614
|
-
*/
|
|
615
|
-
const idFields = (model) => {
|
|
616
|
-
const fields = {};
|
|
617
|
-
for (const fieldName of model.data.identifier) {
|
|
618
|
-
fields[fieldName] = (0, ModelField_1.id)().required();
|
|
619
|
-
}
|
|
620
|
-
return fields;
|
|
621
|
-
};
|
|
622
612
|
function processFieldLevelAuthRules(fields, authFields) {
|
|
623
613
|
const fieldLevelAuthRules = {};
|
|
624
614
|
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
@@ -633,9 +623,10 @@ function processFieldLevelAuthRules(fields, authFields) {
|
|
|
633
623
|
}
|
|
634
624
|
return fieldLevelAuthRules;
|
|
635
625
|
}
|
|
636
|
-
function processFields(typeName, fields, fieldLevelAuthRules, identifier, partitionKey, secondaryIndexes = {}) {
|
|
626
|
+
function processFields(typeName, fields, impliedFields, fieldLevelAuthRules, identifier, partitionKey, secondaryIndexes = {}) {
|
|
637
627
|
const gqlFields = [];
|
|
638
628
|
const models = [];
|
|
629
|
+
validateImpliedFields(fields, impliedFields);
|
|
639
630
|
for (const [fieldName, fieldDef] of Object.entries(fields)) {
|
|
640
631
|
const fieldAuth = fieldLevelAuthRules[fieldName]
|
|
641
632
|
? ` ${fieldLevelAuthRules[fieldName]}`
|
|
@@ -806,7 +797,7 @@ const schemaPreprocessor = (schema) => {
|
|
|
806
797
|
const authString = '';
|
|
807
798
|
const authFields = {};
|
|
808
799
|
const fieldLevelAuthRules = processFieldLevelAuthRules(fieldAuthApplicableFields, authFields);
|
|
809
|
-
const { gqlFields, models } = processFields(typeName, fields, fieldLevelAuthRules);
|
|
800
|
+
const { gqlFields, models } = processFields(typeName, fields, authFields, fieldLevelAuthRules);
|
|
810
801
|
topLevelTypes.push(...models);
|
|
811
802
|
const joined = gqlFields.join('\n ');
|
|
812
803
|
const model = `type ${typeName} ${authString}\n{\n ${joined}\n}`;
|
|
@@ -846,7 +837,7 @@ const schemaPreprocessor = (schema) => {
|
|
|
846
837
|
}
|
|
847
838
|
const fieldLevelAuthRules = processFieldLevelAuthRules(fields, authFields);
|
|
848
839
|
validateStaticFields(fields, authFields);
|
|
849
|
-
const { gqlFields, models } = processFields(typeName, fields, fieldLevelAuthRules, identifier, partitionKey);
|
|
840
|
+
const { gqlFields, models } = processFields(typeName, fields, authFields, fieldLevelAuthRules, identifier, partitionKey);
|
|
850
841
|
topLevelTypes.push(...models);
|
|
851
842
|
const joined = gqlFields.join('\n ');
|
|
852
843
|
const model = `type ${typeName} @model ${authString}\n{\n ${joined}\n}`;
|
|
@@ -862,14 +853,7 @@ const schemaPreprocessor = (schema) => {
|
|
|
862
853
|
throw new Error(`Model \`${typeName}\` is missing authorization rules. Add global rules to the schema or ensure every model has its own rules.`);
|
|
863
854
|
}
|
|
864
855
|
const fieldLevelAuthRules = processFieldLevelAuthRules(fields, authFields);
|
|
865
|
-
const { gqlFields, models } = processFields(typeName,
|
|
866
|
-
// ID fields are not merged outside `mergeFieldObjects` to skip
|
|
867
|
-
// validation, because the `identifer()` method doesn't specify or
|
|
868
|
-
// care what the underlying field type is. We should always just defer
|
|
869
|
-
// to whatever is explicitly defined if there's an overlap.
|
|
870
|
-
...idFields(typeDef),
|
|
871
|
-
...mergeFieldObjects(fields, authFields, implicitTimestampFields(typeDef)),
|
|
872
|
-
}, fieldLevelAuthRules, identifier, partitionKey, transformedSecondaryIndexes);
|
|
856
|
+
const { gqlFields, models } = processFields(typeName, fields, authFields, fieldLevelAuthRules, identifier, partitionKey, transformedSecondaryIndexes);
|
|
873
857
|
topLevelTypes.push(...models);
|
|
874
858
|
const joined = gqlFields.join('\n ');
|
|
875
859
|
const model = `type ${typeName} @model ${authString}\n{\n ${joined}\n}`;
|