Skip to content

Commit e12116a

Browse files
committed
fix: use related fields for has_one and belongs_to properties when building GraphQL API payloads
1 parent af94de2 commit e12116a

File tree

9 files changed

+160
-85
lines changed

9 files changed

+160
-85
lines changed

packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react-forms.test.ts.snap

Lines changed: 68 additions & 56 deletions
Large diffs are not rendered by default.

packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react-forms.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1001,9 +1001,9 @@ describe('amplify form renderer tests', () => {
10011001
);
10021002

10031003
expect(componentText).toContain('postCommentsId');
1004-
expect(componentText).not.toContain('postID');
1005-
expect(componentText).not.toContain('userCommentsId');
1006-
expect(componentText).not.toContain('orgCommentsId');
1004+
expect(componentText).toContain('postID');
1005+
expect(componentText).toContain('userCommentsId');
1006+
expect(componentText).toContain('orgCommentsId');
10071007
expect(componentText).toMatchSnapshot();
10081008
expect(declaration).toMatchSnapshot();
10091009
});

packages/codegen-ui-react/lib/amplify-ui-renderers/form.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,13 @@ export default class FormRenderer extends ReactComponentRenderer<BaseComponentPr
323323
[],
324324
),
325325
),
326-
buildModelFieldObject(dataSourceType !== 'DataStore', formMetadata?.fieldConfigs),
326+
buildModelFieldObject(
327+
dataSourceType !== 'DataStore',
328+
formMetadata?.fieldConfigs,
329+
this.componentMetadata.dataSchemaMetadata?.models,
330+
undefined,
331+
this.isRenderingGraphQL(),
332+
),
327333
...onSubmitValidationRun(hasModelField),
328334
...this.getOnSubmitDSCall(),
329335
],

packages/codegen-ui-react/lib/forms/form-renderer-helper/all-props.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,9 @@ export const addFormAttributes = (
113113
if (formMetadata.formActionType === 'update' && !fieldConfig.isArray && !isControlledComponent(componentType)) {
114114
attributes.push(renderDefaultValueAttribute(renderedVariableName, fieldConfig, componentType));
115115
}
116-
attributes.push(buildOnChangeStatement(component, formMetadata.fieldConfigs, dataApi));
116+
attributes.push(
117+
buildOnChangeStatement(component, formMetadata.fieldConfigs, dataApi, dataSchema?.models, dataApi === 'GraphQL'),
118+
);
117119
attributes.push(buildOnBlurStatement(componentName, fieldConfig));
118120
attributes.push(
119121
factory.createJsxAttribute(

packages/codegen-ui-react/lib/forms/form-renderer-helper/event-handler-props.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
isValidVariableName,
2323
shouldIncludeCancel,
2424
InvalidInputError,
25+
GenericDataModel,
2526
} from '@aws-amplify/codegen-ui';
2627
import {
2728
BindingElement,
@@ -211,6 +212,8 @@ export const buildOverrideOnChangeStatement = (
211212
fieldName: string,
212213
fieldConfigs: Record<string, FieldConfigMetadata>,
213214
valueNameOverride?: Identifier,
215+
models?: Record<string, GenericDataModel>,
216+
isRenderingGraphQL = false,
214217
): IfStatement => {
215218
const keyPath = fieldName.split('.');
216219
const keyName = keyPath[0];
@@ -229,9 +232,15 @@ export const buildOverrideOnChangeStatement = (
229232
factory.createIdentifier('onChange'),
230233
factory.createBlock(
231234
[
232-
buildModelFieldObject(true, fieldConfigs, {
233-
[keyName]: keyValueExpression,
234-
}),
235+
buildModelFieldObject(
236+
true,
237+
fieldConfigs,
238+
models || {},
239+
{
240+
[keyName]: keyValueExpression,
241+
},
242+
isRenderingGraphQL,
243+
),
235244
factory.createVariableStatement(
236245
undefined,
237246
factory.createVariableDeclarationList(
@@ -286,7 +295,9 @@ function getCallbackVarName(fieldType: string): string {
286295
export const buildOnChangeStatement = (
287296
component: StudioComponent | StudioComponentChild,
288297
fieldConfigs: Record<string, FieldConfigMetadata>,
289-
dataApi?: DataApiKind,
298+
dataApi: DataApiKind | undefined,
299+
models: Record<string, GenericDataModel> = {},
300+
isRenderingGraphQL = false,
290301
) => {
291302
const { name: fieldName, componentType: fieldType } = component;
292303
const fieldConfig = fieldConfigs[fieldName];
@@ -309,7 +320,9 @@ export const buildOnChangeStatement = (
309320
}
310321

311322
if (!shouldWrapInArrayField(fieldConfig)) {
312-
handleChangeStatements.push(buildOverrideOnChangeStatement(fieldName, fieldConfigs));
323+
handleChangeStatements.push(
324+
buildOverrideOnChangeStatement(fieldName, fieldConfigs, undefined, models, isRenderingGraphQL),
325+
);
313326
}
314327

315328
handleChangeStatements.push(getOnChangeValidationBlock(fieldName));
@@ -515,6 +528,7 @@ export const buildStorageManagerOnChangeStatement = (
515528
component: StudioComponent | StudioComponentChild,
516529
fieldConfigs: Record<string, FieldConfigMetadata>,
517530
handlerName: 'onUploadSuccess' | 'onFileRemove',
531+
isRenderingGraphQL: boolean,
518532
) => {
519533
const { name: fieldName } = component;
520534
const fieldConfig = fieldConfigs[fieldName];
@@ -581,7 +595,7 @@ export const buildStorageManagerOnChangeStatement = (
581595
NodeFlags.Let,
582596
),
583597
),
584-
buildOverrideOnChangeStatement(fieldName, fieldConfigs),
598+
buildOverrideOnChangeStatement(fieldName, fieldConfigs, undefined, undefined, isRenderingGraphQL),
585599
factory.createReturnStatement(factory.createIdentifier('value')),
586600
],
587601
true,

packages/codegen-ui-react/lib/forms/form-renderer-helper/model-fields.ts

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
limitations under the License.
1515
*/
1616
import { factory, NodeFlags, ObjectLiteralElementLike } from 'typescript';
17-
import { FieldConfigMetadata } from '@aws-amplify/codegen-ui';
17+
import { FieldConfigMetadata, GenericDataModel } from '@aws-amplify/codegen-ui';
1818

1919
/**
2020
* builds modelFields object which is used to validate, onSubmit, onSuccess/onError
@@ -33,30 +33,49 @@ import { FieldConfigMetadata } from '@aws-amplify/codegen-ui';
3333
export const buildModelFieldObject = (
3434
shouldBeConst: boolean,
3535
fieldConfigs: Record<string, FieldConfigMetadata> = {},
36+
models: Record<string, GenericDataModel> = {},
3637
nameOverrides: Record<string, ObjectLiteralElementLike> = {},
38+
isRenderingGraphQL = false,
3739
) => {
3840
const fieldSet = new Set<string>();
3941
const fields = Object.keys(fieldConfigs).reduce<ObjectLiteralElementLike[]>((acc, value) => {
4042
const fieldName = value.split('.')[0];
41-
const { sanitizedFieldName } = fieldConfigs[value];
43+
const { sanitizedFieldName, relationship } = fieldConfigs[value];
4244
const renderedFieldName = sanitizedFieldName || fieldName;
4345
if (!fieldSet.has(renderedFieldName)) {
44-
let assignment: ObjectLiteralElementLike = factory.createShorthandPropertyAssignment(
45-
factory.createIdentifier(fieldName),
46-
undefined,
47-
);
48-
46+
let assignments: ObjectLiteralElementLike[] = [
47+
factory.createShorthandPropertyAssignment(factory.createIdentifier(fieldName), undefined),
48+
];
4949
if (nameOverrides[fieldName]) {
50-
assignment = nameOverrides[fieldName];
50+
assignments = [nameOverrides[fieldName]];
51+
} else if (
52+
isRenderingGraphQL &&
53+
typeof fieldConfigs[value].dataType === 'object' &&
54+
relationship &&
55+
(relationship.type === 'BELONGS_TO' || relationship.type === 'HAS_ONE')
56+
) {
57+
assignments =
58+
relationship.associatedFields?.map((associatedField, index) => {
59+
return factory.createPropertyAssignment(
60+
factory.createStringLiteral(associatedField),
61+
factory.createPropertyAccessChain(
62+
factory.createIdentifier(fieldName),
63+
undefined,
64+
models[relationship.relatedModelName].primaryKeys[index],
65+
),
66+
);
67+
}) || [];
5168
} else if (sanitizedFieldName) {
5269
// if overrides present, ignore sanitizedFieldName
53-
assignment = factory.createPropertyAssignment(
54-
factory.createStringLiteral(fieldName),
55-
factory.createIdentifier(sanitizedFieldName),
56-
);
70+
assignments = [
71+
factory.createPropertyAssignment(
72+
factory.createStringLiteral(fieldName),
73+
factory.createIdentifier(sanitizedFieldName),
74+
),
75+
];
5776
}
5877

59-
acc.push(assignment);
78+
acc.push(...assignments);
6079
fieldSet.add(renderedFieldName);
6180
}
6281
return acc;

packages/codegen-ui-react/lib/forms/form-renderer-helper/render-array-field.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
16-
import { FieldConfigMetadata, LabelDecorator } from '@aws-amplify/codegen-ui';
16+
import { FieldConfigMetadata, GenericDataModel, LabelDecorator } from '@aws-amplify/codegen-ui';
1717
import { Expression, factory, Identifier, JsxAttribute, JsxChild, NodeFlags, SyntaxKind } from 'typescript';
1818
import {
1919
buildAccessChain,
@@ -38,12 +38,16 @@ function getOnChangeAttribute({
3838
renderedFieldName,
3939
fieldConfigs,
4040
isLimitedToOneValue,
41+
models,
42+
isRenderingGraphQL,
4143
}: {
4244
setStateName: Identifier;
4345
fieldName: string;
4446
renderedFieldName: string;
4547
fieldConfigs: Record<string, FieldConfigMetadata>;
4648
isLimitedToOneValue?: boolean;
49+
models: Record<string, GenericDataModel> | undefined;
50+
isRenderingGraphQL: boolean;
4751
}): JsxAttribute {
4852
const fieldConfig = fieldConfigs[fieldName];
4953
const { dataType, componentType } = fieldConfig;
@@ -97,7 +101,7 @@ function getOnChangeAttribute({
97101
NodeFlags.Let,
98102
),
99103
),
100-
buildOverrideOnChangeStatement(fieldName, fieldConfigs, valueName),
104+
buildOverrideOnChangeStatement(fieldName, fieldConfigs, valueName, models, isRenderingGraphQL),
101105
...setStateStatements,
102106
],
103107
true,
@@ -132,6 +136,7 @@ export const renderArrayFieldComponent = (
132136
labelDecorator?: LabelDecorator,
133137
isRequired?: boolean,
134138
dataApi: DataApiKind = 'DataStore',
139+
models: Record<string, GenericDataModel> = {},
135140
) => {
136141
const fieldConfig = fieldConfigs[fieldName];
137142
const { sanitizedFieldName, dataType, componentType } = fieldConfig;
@@ -172,7 +177,17 @@ export const renderArrayFieldComponent = (
172177
);
173178
}
174179

175-
props.push(getOnChangeAttribute({ fieldName, isLimitedToOneValue, fieldConfigs, renderedFieldName, setStateName }));
180+
props.push(
181+
getOnChangeAttribute({
182+
fieldName,
183+
isLimitedToOneValue,
184+
fieldConfigs,
185+
renderedFieldName,
186+
setStateName,
187+
models,
188+
isRenderingGraphQL: dataApi === 'GraphQL',
189+
}),
190+
);
176191
let labelAttribute = factory.createJsxAttribute(
177192
factory.createIdentifier('label'),
178193
factory.createJsxExpression(undefined, factory.createStringLiteral(fieldLabel)),

packages/codegen-ui-react/lib/react-component-renderer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ export class ReactComponentRenderer<TPropIn> extends ComponentRendererBase<
9898
fieldConfigs,
9999
labelDecorator,
100100
isRequired,
101+
this.importCollection.rendererConfig?.apiConfiguration?.dataApi === 'GraphQL',
101102
);
102103
}
103104

@@ -118,6 +119,7 @@ export class ReactComponentRenderer<TPropIn> extends ComponentRendererBase<
118119
labelDecorator,
119120
isRequired,
120121
this.importCollection.rendererConfig?.apiConfiguration?.dataApi,
122+
this.componentMetadata.dataSchemaMetadata?.models,
121123
);
122124
}
123125
}

packages/codegen-ui-react/lib/utils/forms/storage-field-component.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ export const renderStorageFieldComponent = (
324324
fieldConfigs: Record<string, FieldConfigMetadata>,
325325
labelDecorator?: LabelDecorator,
326326
isRequired?: boolean,
327+
isRenderingGraphQL = false,
327328
) => {
328329
const { name: componentName } = component;
329330
const dataTypeName = componentMetadata.formMetadata?.dataType.dataTypeName || '';
@@ -418,8 +419,12 @@ export const renderStorageFieldComponent = (
418419
);
419420
}
420421

421-
storageManagerAttributes.push(buildStorageManagerOnChangeStatement(component, fieldConfigs, 'onUploadSuccess'));
422-
storageManagerAttributes.push(buildStorageManagerOnChangeStatement(component, fieldConfigs, 'onFileRemove'));
422+
storageManagerAttributes.push(
423+
buildStorageManagerOnChangeStatement(component, fieldConfigs, 'onUploadSuccess', isRenderingGraphQL),
424+
);
425+
storageManagerAttributes.push(
426+
buildStorageManagerOnChangeStatement(component, fieldConfigs, 'onFileRemove', isRenderingGraphQL),
427+
);
423428
storageManagerAttributes.push(
424429
factory.createJsxAttribute(
425430
factory.createIdentifier('processFile'),

0 commit comments

Comments
 (0)