in packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts [10:121]
export function getConnectedFieldV2(
field: CodeGenField,
model: CodeGenModel,
connectedModel: CodeGenModel,
directiveName: string,
shouldUseModelNameFieldInHasManyAndBelongsTo: boolean = false
): CodeGenField {
const connectionInfo = getDirective(field)(directiveName);
if (!connectionInfo) {
throw new Error(`The ${field.name} on model ${model.name} is not connected`);
}
if (connectionInfo.name === 'belongsTo') {
let connectedFieldBelongsTo = getBelongsToConnectedField(field, model, connectedModel);
if (connectedFieldBelongsTo) {
return connectedFieldBelongsTo;
}
}
const indexName = connectionInfo.arguments.indexName;
const connectionFields = connectionInfo.arguments.fields;
if (connectionFields || directiveName === 'hasOne') {
let connectionDirective;
if (indexName) {
connectionDirective = flattenFieldDirectives(connectedModel).find(dir => {
return dir.name === 'index' && dir.arguments.name === indexName;
});
if (!connectionDirective) {
throw new Error(
`Error processing @${connectionInfo.name} directive on ${model.name}.${field.name}, @index directive with name ${indexName} was not found in connected model ${connectedModel.name}`,
);
}
} else {
connectionDirective = flattenFieldDirectives(connectedModel).find(dir => {
return dir.name === 'primaryKey';
});
}
const getOtherSideBelongsToField = (type: string, otherSideModel: CodeGenModel) => {
return otherSideModel.fields
.filter(f => f.type === type)
.find(f =>
f.directives.find(
d => d.name === 'belongsTo'
)
)?.name;
}
// when there is a fields argument in the connection
let connectedFieldName: string = DEFAULT_HASH_KEY_FIELD;
if (connectionDirective) {
connectedFieldName = ((fieldDir: CodeGenFieldDirective) => {
return fieldDir.fieldName;
})(connectionDirective as CodeGenFieldDirective)
} else {
const otherSideBelongsToField = getOtherSideBelongsToField(model.name, connectedModel);
if (otherSideBelongsToField) {
connectedFieldName = otherSideBelongsToField;
}
}
// Find a field on the other side which connected by a @connection and has the same fields[0] as indexName field
const otherSideConnectedField = connectedModel.fields
.filter(f => f.type === model.name)
.find(f =>
f.directives.find(
d =>
(d.name === 'belongsTo' || d.name === 'hasOne' || d.name === 'hasMany') &&
d.arguments.fields &&
d.arguments.fields[0] === connectedFieldName,
),
);
if (otherSideConnectedField) {
return otherSideConnectedField;
}
// If there are no field with @connection with indexName then try to find a field that has same name as connection name
const connectedField = connectedModel.fields.find(f => f.name === connectedFieldName);
if (!connectedField) {
throw new Error(`Can not find key field ${connectedFieldName} in ${connectedModel.name}`);
}
return connectedField;
}
// TODO: Remove us, leaving in to be explicit on why this flag is here.
if (shouldUseModelNameFieldInHasManyAndBelongsTo) {
const otherSideConnectedField = connectedModel.fields
.filter(f => f.type === model.name)
.find(f =>
f.directives.find(
d =>
(d.name === 'belongsTo' || d.name === 'hasOne' || d.name === 'hasMany')
),
);
if (otherSideConnectedField) {
return otherSideConnectedField;
}
}
// un-named connection. Use an existing field or generate a new field
const connectedFieldName = makeConnectionAttributeName(model.name, field.name);
const connectedField = connectedModel.fields.find(f => f.name === connectedFieldName);
return connectedField
? connectedField
: {
name: connectedFieldName,
directives: [],
type: 'ID',
isList: false,
isNullable: true,
};
}