Skip to content

Commit 98356b0

Browse files
committed
fix(amplify-codegen): updates hasone link location
1 parent 24e1c31 commit 98356b0

File tree

3 files changed

+63
-17
lines changed

3 files changed

+63
-17
lines changed

packages/appsync-modelgen-plugin/src/__tests__/visitors/appsync-visitor.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,31 @@ describe('AppSyncModelVisitor', () => {
317317
expect(commentsField).not.toContain('post');
318318
expect(commentsField).toContain('postCommentsId'); // because of connection from Post.comments
319319
});
320+
321+
it('should generate projectTeamId connection field for hasOne directive in the parent object', () => {
322+
const schema = /* GraphQL */ `
323+
type Project @model {
324+
id: ID!
325+
name: String
326+
team: Team @hasOne
327+
}
328+
type Team @model {
329+
id: ID!
330+
name: String!
331+
}
332+
`;
333+
const ast = parse(schema);
334+
const builtSchema = buildSchemaWithDirectives(schema);
335+
const visitor = new AppSyncModelVisitor(
336+
builtSchema,
337+
{ directives, target: 'typescript', generate: CodeGenGenerateEnum.code, usePipelinedTransformer: true },
338+
{},
339+
);
340+
visit(ast, { leave: visitor });
341+
visitor.generate();
342+
const projectFields = visitor.models.Project.fields.map(field => field.name);
343+
expect(projectFields).toContain('projectTeamId');
344+
});
320345
});
321346

322347
describe('auth directive', () => {

packages/appsync-modelgen-plugin/src/utils/process-connections-v2.ts

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { CodeGenField, CodeGenFieldDirective, CodeGenModel, CodeGenModelMap } from '../visitors/appsync-visitor';
22
import {
3-
CodeGenFieldConnection, DEFAULT_HASH_KEY_FIELD, flattenFieldDirectives,
3+
CodeGenFieldConnection,
4+
DEFAULT_HASH_KEY_FIELD,
5+
flattenFieldDirectives,
46
getDirective,
57
makeConnectionAttributeName,
68
} from './process-connections';
@@ -10,13 +12,18 @@ import { processHasManyConnection } from './process-has-many';
1012

1113
// TODO: This file holds several references to utility functions in the v1 process connections file, those functions need to go here before that file is removed
1214

13-
export function getConnectedFieldV2(field: CodeGenField, model: CodeGenModel, connectedModel: CodeGenModel, directiveName: string): CodeGenField {
15+
export function getConnectedFieldV2(
16+
field: CodeGenField,
17+
model: CodeGenModel,
18+
connectedModel: CodeGenModel,
19+
directiveName: string,
20+
): CodeGenField {
1421
const connectionInfo = getDirective(field)(directiveName);
1522
if (!connectionInfo) {
1623
throw new Error(`The ${field.name} on model ${model.name} is not connected`);
1724
}
1825

19-
if(connectionInfo.name === 'belongsTo') {
26+
if (connectionInfo.name === 'belongsTo') {
2027
let connectedFieldBelongsTo = getBelongsToConnectedField(field, model, connectedModel);
2128
if (connectedFieldBelongsTo) {
2229
return connectedFieldBelongsTo;
@@ -25,7 +32,7 @@ export function getConnectedFieldV2(field: CodeGenField, model: CodeGenModel, co
2532

2633
const indexName = connectionInfo.arguments.indexName;
2734
const connectionFields = connectionInfo.arguments.fields;
28-
if (connectionFields) {
35+
if (connectionFields || directiveName === 'hasOne') {
2936
let indexDirective;
3037
if (indexName) {
3138
indexDirective = flattenFieldDirectives(connectedModel).find(dir => {
@@ -43,12 +50,20 @@ export function getConnectedFieldV2(field: CodeGenField, model: CodeGenModel, co
4350
}
4451

4552
// when there is a fields argument in the connection
46-
const connectedFieldName = indexDirective ? ((fieldDir: CodeGenFieldDirective) => { return fieldDir.fieldName ;})(indexDirective as CodeGenFieldDirective) : DEFAULT_HASH_KEY_FIELD;
53+
const connectedFieldName = indexDirective
54+
? ((fieldDir: CodeGenFieldDirective) => {
55+
return fieldDir.fieldName;
56+
})(indexDirective as CodeGenFieldDirective)
57+
: DEFAULT_HASH_KEY_FIELD;
4758

4859
// Find a field on the other side which connected by a @connection and has the same fields[0] as indexName field
4960
const otherSideConnectedField = connectedModel.fields.find(f => {
5061
return f.directives.find(d => {
51-
return (d.name === 'belongsTo' || d.name === 'hasOne' || d.name === 'hasMany') && d.arguments.fields && d.arguments.fields[0] === connectedFieldName;
62+
return (
63+
(d.name === 'belongsTo' || d.name === 'hasOne' || d.name === 'hasMany') &&
64+
d.arguments.fields &&
65+
d.arguments.fields[0] === connectedFieldName
66+
);
5267
});
5368
});
5469
if (otherSideConnectedField) {
@@ -68,25 +83,23 @@ export function getConnectedFieldV2(field: CodeGenField, model: CodeGenModel, co
6883
return connectedField
6984
? connectedField
7085
: {
71-
name: connectedFieldName,
72-
directives: [],
73-
type: 'ID',
74-
isList: false,
75-
isNullable: true,
76-
};
86+
name: connectedFieldName,
87+
directives: [],
88+
type: 'ID',
89+
isList: false,
90+
isNullable: true,
91+
};
7792
}
7893

79-
8094
export function processConnectionsV2(
8195
field: CodeGenField,
8296
model: CodeGenModel,
8397
modelMap: CodeGenModelMap,
8498
): CodeGenFieldConnection | undefined {
8599
const connectionDirective = field.directives.find(d => d.name === 'hasOne' || d.name === 'hasMany' || d.name === 'belongsTo');
86100

87-
if(connectionDirective) {
88-
89-
switch(connectionDirective.name) {
101+
if (connectionDirective) {
102+
switch (connectionDirective.name) {
90103
case 'hasOne':
91104
return processHasOneConnection(field, model, modelMap, connectionDirective);
92105
case 'belongsTo':

packages/appsync-modelgen-plugin/src/visitors/appsync-visitor.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -679,9 +679,17 @@ export class AppSyncModelVisitor<
679679
model.fields.forEach(field => {
680680
const connectionInfo = processConnectionsV2(field, model, this.modelMap);
681681
if (connectionInfo) {
682-
if (connectionInfo.kind === CodeGenConnectionType.HAS_MANY || connectionInfo.kind === CodeGenConnectionType.HAS_ONE) {
682+
if (connectionInfo.kind === CodeGenConnectionType.HAS_MANY) {
683683
// Need to update the other side of the connection even if there is no connection directive
684684
addFieldToModel(connectionInfo.connectedModel, connectionInfo.associatedWith);
685+
} else if (connectionInfo.kind === CodeGenConnectionType.HAS_ONE) {
686+
addFieldToModel(model, {
687+
name: connectionInfo.targetName,
688+
directives: [],
689+
type: 'ID',
690+
isList: false,
691+
isNullable: connectionInfo.associatedWith.isNullable,
692+
});
685693
} else if (connectionInfo.targetName !== 'id') {
686694
// Need to remove the field that is targetName
687695
removeFieldFromModel(model, connectionInfo.targetName);

0 commit comments

Comments
 (0)