@aws-amplify/appsync-modelgen-plugin
Version:
906 lines • 42.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AppSyncModelVisitor = exports.CodeGenPrimaryKeyType = exports.CodeGenGenerateEnum = void 0;
const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common");
const change_case_1 = require("change-case");
const pluralize_1 = require("pluralize");
const crypto_1 = __importDefault(require("crypto"));
const graphql_1 = require("graphql");
const fieldUtils_1 = require("../utils/fieldUtils");
const get_type_info_1 = require("../utils/get-type-info");
const process_connections_1 = require("../utils/process-connections");
const sort_1 = require("../utils/sort");
const warn_1 = require("../utils/warn");
const process_auth_1 = require("../utils/process-auth");
const process_connections_v2_1 = require("../utils/process-connections-v2");
const graphql_transformer_common_1 = require("graphql-transformer-common");
const process_primary_key_1 = require("../utils/process-primary-key");
const process_index_1 = require("../utils/process-index");
const constants_1 = require("../utils/constants");
const process_has_many_1 = require("../utils/process-has-many");
var CodeGenGenerateEnum;
(function (CodeGenGenerateEnum) {
CodeGenGenerateEnum["metadata"] = "metadata";
CodeGenGenerateEnum["code"] = "code";
CodeGenGenerateEnum["loader"] = "loader";
})(CodeGenGenerateEnum = exports.CodeGenGenerateEnum || (exports.CodeGenGenerateEnum = {}));
var CodeGenPrimaryKeyType;
(function (CodeGenPrimaryKeyType) {
CodeGenPrimaryKeyType["ManagedId"] = "ManagedId";
CodeGenPrimaryKeyType["OptionallyManagedId"] = "OptionallyManagedId";
CodeGenPrimaryKeyType["CustomId"] = "CustomId";
})(CodeGenPrimaryKeyType = exports.CodeGenPrimaryKeyType || (exports.CodeGenPrimaryKeyType = {}));
class AppSyncModelVisitor extends visitor_plugin_common_1.BaseVisitor {
constructor(_schema, rawConfig, additionalConfig, defaultScalars = visitor_plugin_common_1.DEFAULT_SCALARS) {
super(rawConfig, {
...additionalConfig,
scalars: (0, visitor_plugin_common_1.buildScalars)(_schema, rawConfig.scalars || '', defaultScalars),
target: rawConfig.target,
isDataStoreEnabled: rawConfig.isDataStoreEnabled,
isTimestampFieldsAdded: rawConfig.isTimestampFieldsAdded,
handleListNullabilityTransparently: rawConfig.handleListNullabilityTransparently,
usePipelinedTransformer: rawConfig.usePipelinedTransformer,
transformerVersion: rawConfig.transformerVersion,
respectPrimaryKeyAttributesOnConnectionField: rawConfig.respectPrimaryKeyAttributesOnConnectionField,
improvePluralization: rawConfig.improvePluralization,
generateModelsForLazyLoadAndCustomSelectionSet: rawConfig.generateModelsForLazyLoadAndCustomSelectionSet,
codegenVersion: rawConfig.codegenVersion,
});
this._schema = _schema;
this.READ_ONLY_FIELDS = ['id'];
this.SCALAR_TYPE_MAP = {};
this.modelMap = {};
this.nonModelMap = {};
this.enumMap = {};
this.queryMap = {};
this.mutationMap = {};
this.subscriptionMap = {};
this.inputObjectMap = {};
this.unionMap = {};
this.interfaceMap = {};
this.typesToSkip = ['AMPLIFY'];
const typesUsedInDirectives = [];
if (rawConfig.directives) {
const directiveSchema = (0, graphql_1.parse)(rawConfig.directives);
directiveSchema.definitions.forEach((definition) => {
if (definition.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION || definition.kind === graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION) {
typesUsedInDirectives.push(definition.name.value);
}
});
}
this.typesToSkip.push(...typesUsedInDirectives);
}
ObjectTypeDefinition(node, index, parent) {
var _a, _b, _c;
if (this.typesToSkip.includes(node.name.value)) {
return;
}
const directives = this.getDirectives(node.directives);
const fields = node.fields;
const modelDirective = directives.find(directive => directive.name === 'model');
if (modelDirective) {
const model = {
name: node.name.value,
type: 'model',
directives,
fields,
};
if (this.config.respectPrimaryKeyAttributesOnConnectionField || this.config.target === 'introspection') {
this.ensurePrimaryKeyField(model, directives);
}
else {
this.ensureIdField(model);
}
this.addTimestampFields(model, modelDirective);
this.sortFields(model);
this.modelMap[node.name.value] = model;
}
else if (node.name.value === ((_a = this._schema.getQueryType()) === null || _a === void 0 ? void 0 : _a.name)) {
fields.forEach(field => {
this.queryMap[field.name] = {
...field,
operationType: 'query',
};
});
}
else if (node.name.value === ((_b = this._schema.getMutationType()) === null || _b === void 0 ? void 0 : _b.name)) {
fields.forEach(field => {
this.mutationMap[field.name] = {
...field,
operationType: 'mutation',
};
});
}
else if (node.name.value === ((_c = this._schema.getSubscriptionType()) === null || _c === void 0 ? void 0 : _c.name)) {
fields.forEach(field => {
this.subscriptionMap[field.name] = {
...field,
operationType: 'subscription',
};
});
}
else {
const nonModel = {
name: node.name.value,
type: 'model',
directives,
fields,
};
this.nonModelMap[node.name.value] = nonModel;
}
}
FieldDefinition(node) {
var _a;
const directive = this.getDirectives(node.directives);
const parameters = (_a = node.arguments) !== null && _a !== void 0 ? _a : [];
return {
name: node.name.value,
directives: directive,
...(0, get_type_info_1.getTypeInfo)(node.type, this._schema),
parameters,
};
}
InputObjectTypeDefinition(node) {
if (this.typesToSkip.includes(node.name.value)) {
return;
}
const inputValues = node.fields;
const inputObject = {
name: node.name.value,
type: 'input',
inputValues,
};
this.inputObjectMap[node.name.value] = inputObject;
}
InputValueDefinition(node) {
const directives = this.getDirectives(node.directives);
return {
name: node.name.value,
directives,
...(0, get_type_info_1.getTypeInfo)(node.type, this._schema),
};
}
EnumTypeDefinition(node) {
if (this.typesToSkip.includes(node.name.value)) {
return;
}
const enumName = this.getEnumName(node.name.value);
const values = node.values
? node.values.reduce((acc, val) => {
acc[this.getEnumValue(val.name.value)] = val.name.value;
return acc;
}, {})
: {};
this.enumMap[node.name.value] = {
name: enumName,
type: 'enum',
values,
};
}
UnionTypeDefinition(node) {
var _a, _b;
if (this.typesToSkip.includes(node.name.value)) {
return;
}
const unionObject = {
name: node.name.value,
type: 'union',
typeNames: (_b = (_a = node.types) === null || _a === void 0 ? void 0 : _a.map(type => type.name.value)) !== null && _b !== void 0 ? _b : [],
};
this.unionMap[node.name.value] = unionObject;
}
InterfaceTypeDefinition(node) {
if (this.typesToSkip.includes(node.name.value)) {
return;
}
const fields = node.fields;
const interfaceEntry = {
name: node.name.value,
type: 'interface',
fields,
};
this.interfaceMap[node.name.value] = interfaceEntry;
}
processDirectives(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne = false) {
if (this.config.usePipelinedTransformer || this.config.transformerVersion === 2) {
this.processV2KeyDirectives();
this.processConnectionDirectivesV2(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne);
}
else {
this.processConnectionDirective();
}
this.processAuthDirectives();
}
generate() {
const shouldUseModelNameFieldInHasManyAndBelongsTo = false;
const shouldImputeKeyForUniDirectionalHasMany = false;
this.processDirectives(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany);
return '';
}
getDirectives(directives) {
if (directives) {
return directives.map(d => ({
name: d.name.value,
arguments: this.getDirectiveArguments(d),
}));
}
return [];
}
getDirectiveArguments(directive) {
const directiveArguments = {};
if (directive.arguments) {
directive.arguments.reduce((acc, arg) => {
directiveArguments[arg.name.value] = (0, graphql_1.valueFromASTUntyped)(arg.value);
if ((directive.name.value === 'hasOne' || directive.name.value === 'belongsTo' || directive.name.value === 'hasMany') &&
directiveArguments.references &&
!Array.isArray(directiveArguments.references)) {
directiveArguments.references = [directiveArguments.references];
}
return directiveArguments;
}, directiveArguments);
}
return directiveArguments;
}
getSelectedModels() {
if (this._parsedConfig.selectedType) {
const selectedModel = this.modelMap[this._parsedConfig.selectedType];
return selectedModel ? { [this._parsedConfig.selectedType]: selectedModel } : {};
}
return this.modelMap;
}
getSelectedNonModels() {
if (this._parsedConfig.selectedType) {
const selectedModel = this.nonModelMap[this._parsedConfig.selectedType];
return selectedModel ? { [this._parsedConfig.selectedType]: selectedModel } : {};
}
return this.nonModelMap;
}
getSelectedEnums() {
if (this._parsedConfig.selectedType) {
const selectedModel = this.enumMap[this._parsedConfig.selectedType];
return selectedModel ? { [this._parsedConfig.selectedType]: selectedModel } : {};
}
return this.enumMap;
}
selectedTypeIsEnum() {
if (this._parsedConfig && this._parsedConfig.selectedType) {
if (this._parsedConfig.selectedType in this.enumMap) {
return true;
}
}
return false;
}
selectedTypeIsNonModel() {
if (this._parsedConfig && this._parsedConfig.selectedType) {
if (this._parsedConfig.selectedType in this.nonModelMap) {
return true;
}
}
return false;
}
getNativeType(field, options) {
const typeName = field.type;
let typeNameStr = '';
if (typeName in this.scalars) {
typeNameStr = this.scalars[typeName];
}
else if (this.isModelType(field)) {
typeNameStr = this.getModelName(this.modelMap[typeName]);
}
else if (this.isEnumType(field)) {
typeNameStr = this.getEnumName(this.enumMap[typeName]);
}
else if (this.isNonModelType(field)) {
typeNameStr = this.getNonModelName(this.nonModelMap[typeName]);
}
else {
throw new Error(`Unknown type ${typeName} for field ${field.name}. Did you forget to add the directive`);
}
return field.isList ? this.getListType(typeNameStr, field) : typeNameStr;
}
getListType(typeStr, field) {
return `List<${typeStr}>`;
}
getFieldName(field) {
return field.name;
}
getEnumName(enumField) {
if (typeof enumField === 'string') {
return enumField;
}
return enumField.name;
}
getModelName(model) {
return model.name;
}
getNonModelName(model) {
return model.name;
}
getEnumValue(value) {
return (0, change_case_1.constantCase)(value);
}
getModelPrimaryKeyField(model) {
return model.fields.find(field => field.primaryKeyInfo);
}
isEnumType(field) {
const typeName = field.type;
return typeName in this.enumMap;
}
isModelType(field) {
const typeName = field.type;
return typeName in this.modelMap;
}
isNonModelType(field) {
const typeName = field.type;
return typeName in this.nonModelMap;
}
computeVersion() {
const typeArr = [];
Object.values({ ...this.modelMap, ...this.nonModelMap }).forEach((obj) => {
const directives = this.config.usePipelinedTransformer || this.config.transformerVersion === 2
? obj.directives.filter(dir => dir.name === 'primaryKey' || dir.name === 'index')
: obj.directives.filter(dir => dir.name === 'key');
const fields = obj.fields
.map((field) => {
const fieldDirectives = this.config.usePipelinedTransformer
? field.directives.filter(field => field.name === 'hasOne' || field.name === 'belongsTo' || field.name === 'hasMany' || field.name === 'manyToMany')
: field.directives.filter(field => field.name === 'connection');
return {
name: field.name,
directives: fieldDirectives,
type: field.type,
isNullable: field.isNullable,
isList: field.isList,
isListNullable: field.isListNullable,
};
})
.sort((a, b) => (0, sort_1.sortFields)(a, b));
typeArr.push({
name: obj.name,
directives,
fields,
});
});
typeArr.sort(sort_1.sortFields);
return crypto_1.default
.createHash('MD5')
.update(JSON.stringify(typeArr))
.digest()
.toString('hex');
}
sortFields(model) {
model.fields = model.fields.reduce((acc, field) => {
if (field.name === 'id') {
acc.unshift(field);
}
else {
acc.push(field);
}
return acc;
}, []);
}
ensurePrimaryKeyField(model, directives) {
if (this.config.usePipelinedTransformer || this.config.transformerVersion === 2) {
this.ensurePrimaryKeyFieldV2(model, directives);
}
else {
this.ensurePrimaryKeyFieldV1(model, directives);
}
}
ensurePrimaryKeyFieldV2(model, directives) {
var _a;
let primaryKeyFieldName;
let primaryKeyField;
const fieldWithPrimaryKeyDirective = model.fields.find(f => f.directives.find(dir => dir.name === 'primaryKey'));
if (!fieldWithPrimaryKeyDirective) {
primaryKeyFieldName = constants_1.DEFAULT_HASH_KEY_FIELD;
this.ensureIdField(model);
primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName);
primaryKeyField.primaryKeyInfo = {
primaryKeyType: CodeGenPrimaryKeyType.ManagedId,
sortKeyFields: [],
};
}
else {
primaryKeyFieldName = fieldWithPrimaryKeyDirective.name;
primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName);
const sortKeyFieldNames = (_a = (0, process_connections_1.flattenFieldDirectives)(model).find(d => d.name === 'primaryKey')) === null || _a === void 0 ? void 0 : _a.arguments.sortKeyFields;
const sortKeyFields = (sortKeyFieldNames === null || sortKeyFieldNames === void 0 ? void 0 : sortKeyFieldNames.length) > 0 ? sortKeyFieldNames.map(fieldName => model.fields.find(f => f.name === fieldName)) : [];
primaryKeyField.primaryKeyInfo = {
primaryKeyType: primaryKeyFieldName === constants_1.DEFAULT_HASH_KEY_FIELD && sortKeyFields.length === 0
? CodeGenPrimaryKeyType.OptionallyManagedId
: CodeGenPrimaryKeyType.CustomId,
sortKeyFields,
};
}
}
ensurePrimaryKeyFieldV1(model, directives) {
let primaryKeyFieldName;
let primaryKeyField;
const keyDirective = directives.find(d => d.name === 'key' && !d.arguments.name);
if (keyDirective) {
primaryKeyFieldName = keyDirective.arguments.fields[0];
primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName);
const sortKeyFieldNames = keyDirective.arguments.fields.slice(1);
const sortKeyFields = (sortKeyFieldNames === null || sortKeyFieldNames === void 0 ? void 0 : sortKeyFieldNames.length) > 0 ? sortKeyFieldNames.map(fieldName => model.fields.find(f => f.name === fieldName)) : [];
primaryKeyField.primaryKeyInfo = {
primaryKeyType: primaryKeyFieldName === constants_1.DEFAULT_HASH_KEY_FIELD && sortKeyFields.length === 0
? CodeGenPrimaryKeyType.OptionallyManagedId
: CodeGenPrimaryKeyType.CustomId,
sortKeyFields,
};
}
else {
primaryKeyFieldName = constants_1.DEFAULT_HASH_KEY_FIELD;
this.ensureIdField(model);
primaryKeyField = this.getPrimaryKeyFieldByName(model, primaryKeyFieldName);
primaryKeyField.primaryKeyInfo = {
primaryKeyType: CodeGenPrimaryKeyType.ManagedId,
sortKeyFields: [],
};
}
}
getPrimaryKeyFieldByName(model, primaryKeyFieldName) {
const primaryKeyField = model.fields.find(f => f.name === primaryKeyFieldName);
if (!primaryKeyField) {
throw new Error(`Cannot find primary key field in type ${model.name}`);
}
if (primaryKeyField.isNullable) {
throw new Error(`The primary key on type '${model.name}' must reference non-null fields.`);
}
return primaryKeyField;
}
ensureIdField(model) {
const idField = model.fields.find(field => field.name === constants_1.DEFAULT_HASH_KEY_FIELD);
if (idField) {
idField.isNullable = false;
}
else {
model.fields.splice(0, 0, {
name: 'id',
type: 'ID',
isNullable: false,
isList: false,
directives: [],
});
}
}
processConnectionDirective() {
Object.values(this.modelMap).forEach(model => {
model.fields.forEach(field => {
var _a, _b;
const connectionInfo = (0, process_connections_1.processConnections)(field, model, this.modelMap, !!this.config.isDataStoreEnabled);
if (connectionInfo) {
if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_MANY || connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_ONE) {
(0, fieldUtils_1.addFieldToModel)(connectionInfo.connectedModel, connectionInfo.associatedWith);
}
else if (connectionInfo.targetName && ((_b = connectionInfo.targetName !== ((_a = this.getModelPrimaryKeyField(model)) === null || _a === void 0 ? void 0 : _a.name)) !== null && _b !== void 0 ? _b : 'id')) {
(0, fieldUtils_1.removeFieldFromModel)(model, connectionInfo.targetName);
}
field.connectionInfo = connectionInfo;
}
});
const modelTypes = Object.values(this.modelMap).map(model => model.name);
model.fields = model.fields.filter(field => {
const fieldType = field.type;
const connectionInfo = field.connectionInfo;
if (modelTypes.includes(fieldType) && connectionInfo === undefined) {
(0, warn_1.printWarning)(`Model ${model.name} has field ${field.name} of type ${field.type} but its not connected. Add a directive if want to connect them.`);
return false;
}
return true;
});
});
}
generateIntermediateModel(firstModel, secondModel, relationName) {
const firstModelKeyFieldName = this.generateIntermediateModelPrimaryKeyFieldName(firstModel);
const firstModelSortKeyFields = this.getSortKeyFields(firstModel);
const secondModelKeyFieldName = this.generateIntermediateModelPrimaryKeyFieldName(secondModel);
const secondModelSortKeyFields = this.getSortKeyFields(secondModel);
let intermediateModel = {
name: relationName,
type: 'model',
directives: [{ name: 'model', arguments: {} }],
fields: [
{
type: 'ID',
isNullable: false,
isList: false,
name: 'id',
directives: [],
},
{
type: 'ID',
isNullable: true,
isList: false,
name: firstModelKeyFieldName,
directives: [
{
name: 'index',
arguments: {
name: 'by' + firstModel.name,
sortKeyFields: firstModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(firstModel, f)),
},
},
],
},
...firstModelSortKeyFields.map(field => {
return {
type: field.type,
isNullable: true,
isList: field.isList,
name: this.generateIntermediateModelSortKeyFieldName(firstModel, field),
directives: [],
};
}),
{
type: 'ID',
isNullable: true,
isList: false,
name: secondModelKeyFieldName,
directives: [
{
name: 'index',
arguments: {
name: 'by' + secondModel.name,
sortKeyFields: secondModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(secondModel, f)),
},
},
],
},
...secondModelSortKeyFields.map(field => {
return {
type: field.type,
isNullable: true,
isList: field.isList,
name: this.generateIntermediateModelSortKeyFieldName(secondModel, field),
directives: [],
};
}),
{
type: firstModel.name,
isNullable: false,
isList: false,
name: (0, change_case_1.camelCase)(firstModel.name),
directives: [
{
name: 'belongsTo',
arguments: {
fields: [
firstModelKeyFieldName,
...firstModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(firstModel, f)),
],
},
},
],
},
{
type: secondModel.name,
isNullable: false,
isList: false,
name: (0, change_case_1.camelCase)(secondModel.name),
directives: [
{
name: 'belongsTo',
arguments: {
fields: [
secondModelKeyFieldName,
...secondModelSortKeyFields.map(f => this.generateIntermediateModelSortKeyFieldName(secondModel, f)),
],
},
},
],
},
],
};
return intermediateModel;
}
generateIntermediateModelPrimaryKeyFieldName(model) {
if (this.isCustomPKEnabled()) {
const primaryKeyField = model.fields.find(f => f.primaryKeyInfo);
return (0, fieldUtils_1.toCamelCase)([model.name, primaryKeyField.name]);
}
return `${(0, change_case_1.camelCase)(model.name)}ID`;
}
generateIntermediateModelSortKeyFieldName(model, sortKeyField) {
const modelName = model.name.charAt(0).toLocaleLowerCase() + model.name.slice(1);
return `${modelName}${sortKeyField.name}`;
}
getSortKeyFields(model) {
const keyDirective = model.directives.find(d => d.name === 'key' && !d.arguments.name);
return keyDirective
? keyDirective.arguments.fields.slice(1).map(fieldName => model.fields.find(f => f.name === fieldName))
: [];
}
determinePrimaryKeyFieldname(model) {
let primaryKeyFieldName = 'id';
model.fields.forEach(field => {
field.directives.forEach(dir => {
if (dir.name === 'primaryKey') {
primaryKeyFieldName = field.name;
}
});
});
return primaryKeyFieldName;
}
convertManyToManyDirectives(contexts) {
contexts.forEach(context => {
let directiveIndex = context.field.directives.indexOf(context.directive, 0);
if (directiveIndex > -1) {
context.field.directives.splice(directiveIndex, 1);
context.field.type = (0, graphql_transformer_common_1.graphqlName)((0, graphql_transformer_common_1.toUpper)(context.directive.arguments.relationName));
context.field.directives.push({
name: 'hasMany',
arguments: {
indexName: `by${context.model.name}`,
fields: [
this.determinePrimaryKeyFieldname(context.model),
...this.getSortKeyFields(context.model).map(f => this.getFieldName(f)),
],
},
});
}
else {
throw new Error('manyToMany directive not found on manyToMany field...');
}
});
}
processManyToManyDirectives() {
let manyDirectiveMap = new Map();
Object.values(this.modelMap).forEach(model => {
model.fields.forEach(field => {
field.directives.forEach(dir => {
if (dir.name === 'manyToMany') {
let relationName = (0, graphql_transformer_common_1.graphqlName)((0, graphql_transformer_common_1.toUpper)(dir.arguments.relationName));
let existingRelation = manyDirectiveMap.get(relationName);
if (existingRelation) {
existingRelation.push({ model: model, field: field, directive: dir });
}
else {
manyDirectiveMap.set(relationName, [{ model: model, field: field, directive: dir }]);
}
}
});
});
});
manyDirectiveMap.forEach((value, key) => {
if (value.length != 2) {
throw new Error(`Error for relation: '${value[0].directive.arguments.relationName}', there should be two matching manyToMany directives and found: ${value.length}`);
}
let intermediateModel = this.generateIntermediateModel(value[0].model, value[1].model, (0, graphql_transformer_common_1.graphqlName)((0, graphql_transformer_common_1.toUpper)(value[0].directive.arguments.relationName)));
const extractedAuthDirectives = [...value[0].model.directives, ...value[1].model.directives]
.filter(directive => directive.name === 'auth');
const serializedDirectives = extractedAuthDirectives.map(directive => JSON.stringify(directive));
const uniqueSerializedDirectives = serializedDirectives.filter((serializedDirective, index, array) => array.indexOf(serializedDirective) === index);
const authDirectives = uniqueSerializedDirectives.map(serializedDirective => JSON.parse(serializedDirective));
intermediateModel.directives = [...intermediateModel.directives, ...authDirectives];
const modelDirective = intermediateModel.directives.find(directive => directive.name === 'model');
if (modelDirective) {
(0, process_primary_key_1.processPrimaryKey)(intermediateModel);
(0, process_index_1.processIndex)(intermediateModel);
this.ensurePrimaryKeyField(intermediateModel, intermediateModel.directives);
this.addTimestampFields(intermediateModel, modelDirective);
this.sortFields(intermediateModel);
}
this.modelMap[intermediateModel.name] = intermediateModel;
this.convertManyToManyDirectives(value);
});
}
processConnectionDirectivesV2(shouldUseModelNameFieldInHasManyAndBelongsTo, shouldImputeKeyForUniDirectionalHasMany, shouldUseFieldsInAssociatedWithInHasOne) {
var _a;
this.processManyToManyDirectives();
const isCustomPKEnabled = this.isCustomPKEnabled();
Object.values(this.modelMap).forEach(model => {
model.fields.forEach(field => {
const connectionInfo = (0, process_connections_v2_1.processConnectionsV2)(field, model, this.modelMap, shouldUseModelNameFieldInHasManyAndBelongsTo, isCustomPKEnabled, shouldUseFieldsInAssociatedWithInHasOne);
if (connectionInfo) {
if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_MANY) {
if (isCustomPKEnabled) {
connectionInfo.associatedWithFields.forEach(associateField => (0, fieldUtils_1.addFieldToModel)(connectionInfo.connectedModel, associateField));
}
else {
(0, fieldUtils_1.addFieldToModel)(connectionInfo.connectedModel, connectionInfo.associatedWith);
}
if (shouldImputeKeyForUniDirectionalHasMany && (0, process_has_many_1.hasManyHasImplicitKey)(field, model, connectionInfo)) {
(0, process_has_many_1.addHasManyKey)(field, model, connectionInfo);
}
}
else if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.HAS_ONE) {
if (isCustomPKEnabled) {
const connectedModelFields = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(connectionInfo.connectedModel);
if ((connectedModelFields === null || connectedModelFields === void 0 ? void 0 : connectedModelFields.length) > 0 && connectionInfo.targetNames) {
connectionInfo.targetNames.forEach((target, index) => {
(0, fieldUtils_1.addFieldToModel)(model, {
name: target,
directives: [],
type: connectedModelFields[index].type,
isList: false,
isNullable: field.isNullable,
});
});
}
}
else if (connectionInfo.targetName) {
(0, fieldUtils_1.addFieldToModel)(model, {
name: connectionInfo.targetName,
directives: [],
type: 'ID',
isList: false,
isNullable: field.isNullable,
});
}
}
else if (connectionInfo.kind === process_connections_1.CodeGenConnectionType.BELONGS_TO) {
if (isCustomPKEnabled) {
const connectedModelFields = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(connectionInfo.connectedModel);
if ((connectedModelFields === null || connectedModelFields === void 0 ? void 0 : connectedModelFields.length) > 0) {
connectionInfo.targetNames.forEach((target, index) => {
(0, fieldUtils_1.addFieldToModel)(model, {
name: target,
directives: [],
type: connectedModelFields[index].type,
isList: false,
isNullable: field.isNullable,
});
});
}
}
else {
(0, fieldUtils_1.addFieldToModel)(model, {
name: connectionInfo.targetName,
directives: [],
type: 'ID',
isList: false,
isNullable: field.isNullable,
});
}
}
field.connectionInfo = connectionInfo;
}
});
const modelTypes = Object.values(this.modelMap).map(model => model.name);
model.fields = model.fields.filter(field => {
const fieldType = field.type;
const connectionInfo = field.connectionInfo;
if (modelTypes.includes(fieldType) && connectionInfo === undefined) {
(0, warn_1.printWarning)(`Model ${model.name} has field ${field.name} of type ${field.type} but its not connected. Add the appropriate ${field.isList ? '@hasMany' : '@hasOne'}/ directive if you want to connect them.`);
return false;
}
return true;
});
});
if (isCustomPKEnabled) {
if (['java', 'swift', 'dart'].includes((_a = this.config.target) !== null && _a !== void 0 ? _a : '')) {
Object.values(this.modelMap).forEach(model => {
model.fields.forEach(field => {
const connectionInfo = field.connectionInfo;
if (connectionInfo &&
connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_MANY &&
connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_ONE &&
connectionInfo.targetNames &&
connectionInfo.targetName !== 'id') {
const primaryKeyFieldNames = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(model).map(field => field.name);
connectionInfo.targetNames
.filter(targetName => !primaryKeyFieldNames.includes(targetName))
.forEach(targetName => (0, fieldUtils_1.removeFieldFromModel)(model, targetName));
}
});
});
}
}
else {
Object.values(this.modelMap).forEach(model => {
const primaryKeyFields = (0, fieldUtils_1.getModelPrimaryKeyComponentFields)(model);
const primaryKeyName = ((primaryKeyFields === null || primaryKeyFields === void 0 ? void 0 : primaryKeyFields.length) > 0) ? this.getFieldName(primaryKeyFields[0]) : undefined;
model.fields.forEach(field => {
const connectionInfo = field.connectionInfo;
if (connectionInfo &&
connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_MANY &&
connectionInfo.kind !== process_connections_1.CodeGenConnectionType.HAS_ONE &&
connectionInfo.targetName &&
connectionInfo.targetName !== 'id' &&
!connectionInfo.isUsingReferences &&
!(this.config.target === 'introspection' &&
primaryKeyName && primaryKeyName === connectionInfo.targetName)) {
(0, fieldUtils_1.removeFieldFromModel)(model, connectionInfo.targetName);
}
});
});
}
}
processV2KeyDirectives() {
Object.values(this.modelMap).forEach(model => {
(0, process_primary_key_1.processPrimaryKey)(model);
(0, process_index_1.processIndex)(model);
});
}
processAuthDirectives() {
Object.values(this.modelMap).forEach(model => {
const filteredDirectives = model.directives.filter(d => d.name !== 'auth');
const authDirectives = (0, process_auth_1.processAuthDirective)(model.directives);
model.directives = [...filteredDirectives, ...authDirectives];
model.fields.forEach(field => {
const nonAuthDirectives = field.directives.filter(d => d.name != 'auth');
const authDirectives = (0, process_auth_1.processAuthDirective)(field.directives);
field.directives = [...nonAuthDirectives, ...authDirectives];
});
});
}
pluralizeModelName(model) {
return (0, pluralize_1.plural)(model.name);
}
addTimestampFields(model, directive) {
if (!this.config.isTimestampFieldsAdded) {
return;
}
if (directive.name !== 'model') {
return;
}
if (directive.arguments && directive.arguments.hasOwnProperty('timestamps') && directive.arguments.timestamps === null) {
return;
}
const timestamps = directive.arguments.timestamps;
const createdAtField = {
name: (timestamps === null || timestamps === void 0 ? void 0 : timestamps.createdAt) || constants_1.DEFAULT_CREATED_TIME,
directives: [],
type: 'AWSDateTime',
isList: false,
isNullable: true,
isReadOnly: true,
};
const updatedAtField = {
name: (timestamps === null || timestamps === void 0 ? void 0 : timestamps.updatedAt) || constants_1.DEFAULT_UPDATED_TIME,
directives: [],
type: 'AWSDateTime',
isList: false,
isNullable: true,
isReadOnly: true,
};
(0, fieldUtils_1.addFieldToModel)(model, createdAtField);
(0, fieldUtils_1.addFieldToModel)(model, updatedAtField);
}
isRequiredField(field) {
return !(this.config.handleListNullabilityTransparently ? (field.isList ? field.isListNullable : field.isNullable) : field.isNullable);
}
isCustomPKEnabled() {
var _a;
return ((this.config.usePipelinedTransformer || this.config.transformerVersion === 2) &&
((_a = this.config.respectPrimaryKeyAttributesOnConnectionField) !== null && _a !== void 0 ? _a : false));
}
isGenerateModelsForLazyLoadAndCustomSelectionSet() {
var _a;
return (_a = this.config.generateModelsForLazyLoadAndCustomSelectionSet) !== null && _a !== void 0 ? _a : false;
}
get models() {
return this.modelMap;
}
get enums() {
return this.enumMap;
}
get nonModels() {
return this.nonModelMap;
}
get queries() {
return this.queryMap;
}
get mutations() {
return this.mutationMap;
}
get subscriptions() {
return this.subscriptionMap;
}
get inputs() {
return this.inputObjectMap;
}
get unions() {
return this.unionMap;
}
get interfaces() {
return this.interfaceMap;
}
}
exports.AppSyncModelVisitor = AppSyncModelVisitor;
//# sourceMappingURL=appsync-visitor.js.map