Skip to content

Commit

Permalink
feat: support cpk for manyToMany form
Browse files Browse the repository at this point in the history
  • Loading branch information
Hein Jeong authored and hein-j committed Dec 1, 2022
1 parent 517125b commit c5d6abd
Show file tree
Hide file tree
Showing 11 changed files with 593 additions and 220 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,23 @@ describe('amplify form renderer tests', () => {

it('should render an update form for model with cpk', () => {
const { componentText, declaration } = generateWithAmplifyFormRenderer(
'forms/teacher-datastore-update-cpk',
'forms/cpk-teacher-datastore-update',
'datastore/cpk-relationships',
);
// hasOne
expect(componentText).toContain('specialTeacherId: specialTeacherIdProp');
expect(componentText).toContain('await DataStore.query(Teacher, specialTeacherIdProp)');
expect(componentText).toContain('await DataStore.query(CPKTeacher, specialTeacherIdProp)');
expect(componentText).toContain('Student: (record) => record?.specialStudentId');
expect(componentText).toContain('id: r.specialStudentId');

// manyToMany
expect(componentText).toContain('const count = cPKClassesMap.get(r.specialClassId)');
expect(componentText).toContain('cPKClassesMap.set(r.specialClassId, newCount)');
expect(componentText).toContain('const count = linkedCPKClassesMap.get(r.specialClassId)');
expect(componentText).toContain('linkedCPKClassesMap.set(r.specialClassId, newCount)');
expect(componentText).toContain('r.cpkTeacherID.eq(cPKTeacherRecord.specialTeacherId)');
expect(componentText).toContain('cpkTeacherID: cPKTeacherRecord.specialTeacherId');

expect(componentText).toMatchSnapshot();
expect(declaration).toMatchSnapshot();
});
Expand Down
14 changes: 13 additions & 1 deletion packages/codegen-ui-react/lib/amplify-ui-renderers/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import { BaseComponentProps } from '@aws-amplify/ui-react';
import {
ComponentMetadata,
InternalError,
StudioComponent,
StudioComponentChild,
StudioForm,
Expand Down Expand Up @@ -111,6 +112,11 @@ export default class FormRenderer extends ReactComponentRenderer<BaseComponentPr
];
}
if (dataSourceType === 'DataStore') {
const primaryKey = this.componentMetadata.dataSchemaMetadata?.models[dataTypeName].primaryKey;

if (!primaryKey) {
throw new InternalError(`Could not find primary key for ${dataTypeName}`);
}
return [
factory.createIfStatement(
onSubmitIdentifier,
Expand All @@ -133,7 +139,13 @@ export default class FormRenderer extends ReactComponentRenderer<BaseComponentPr
factory.createTryStatement(
factory.createBlock(
[
...buildDataStoreExpression(formActionType, dataTypeName, importedModelName, formMetadata.fieldConfigs),
...buildDataStoreExpression(
formActionType,
dataTypeName,
importedModelName,
formMetadata.fieldConfigs,
primaryKey,
),
// call onSuccess hook if it exists
factory.createIfStatement(
factory.createIdentifier('onSuccess'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const buildDataStoreExpression = (
modelName: string,
importedModelName: string,
fieldConfigs: Record<string, FieldConfigMetadata>,
thisModelPrimaryKey: string,
) => {
let isHasManyFieldConfigExisting = false;
const hasManyDataStoreStatements: (VariableStatement | ExpressionStatement)[] = [];
Expand All @@ -47,7 +48,12 @@ export const buildDataStoreExpression = (
isHasManyFieldConfigExisting = true;
if (isManyToManyRelationship(fieldConfigMetaData)) {
hasManyDataStoreStatements.push(
...buildManyToManyRelationshipDataStoreStatements(dataStoreActionType, importedModelName, fieldConfig),
...buildManyToManyRelationshipDataStoreStatements(
dataStoreActionType,
importedModelName,
fieldConfig,
thisModelPrimaryKey,
),
);
} else {
hasManyDataStoreStatements.push(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@
limitations under the License.
*/
import { factory, NodeFlags, SyntaxKind } from 'typescript';
import { FieldConfigMetadata, GenericDataRelationshipType, HasManyRelationshipType } from '@aws-amplify/codegen-ui';
import {
FieldConfigMetadata,
GenericDataRelationshipType,
HasManyRelationshipType,
InternalError,
} from '@aws-amplify/codegen-ui';
import { getRecordsName, getLinkedDataName, getSetNameIdentifier } from './form-state';
import { buildBaseCollectionVariableStatement } from '../../react-studio-template-renderer-helper';
import { ImportCollection, ImportSource } from '../../imports';
import { lowerCaseFirst } from '../../helpers';
import { isManyToManyRelationship } from './map-from-fieldConfigs';
import { extractModelAndKey } from './display-value';

export const buildRelationshipQuery = (
relationship: GenericDataRelationshipType,
Expand All @@ -46,18 +52,25 @@ export const buildManyToManyRelationshipDataStoreStatements = (
dataStoreActionType: 'update' | 'create',
modelName: string,
hasManyFieldConfig: [string, FieldConfigMetadata],
thisModelPrimaryKey: string,
) => {
let [fieldName] = hasManyFieldConfig;
const [, fieldConfigMetaData] = hasManyFieldConfig;
fieldName = fieldConfigMetaData.sanitizedFieldName || fieldName;
const { relatedModelField, relatedJoinFieldName, relatedJoinTableName } =
const { relatedModelField, relatedJoinFieldName, relatedJoinTableName, relatedModelName } =
fieldConfigMetaData.relationship as HasManyRelationshipType;
if (dataStoreActionType === 'update') {
const linkedDataName = getLinkedDataName(fieldName);
const dataToLinkMap = `${lowerCaseFirst(fieldName)}ToLinkMap`;
const dataToUnlinkMap = `${lowerCaseFirst(fieldName)}ToUnLinkMap`;
const updatedMap = `${lowerCaseFirst(fieldName)}Map`;
const originalMap = `${linkedDataName}Map`;
const { key } = extractModelAndKey(fieldConfigMetaData.valueMappings);
if (!key) {
throw new InternalError(`Could not identify primary key for ${relatedModelName}`);
}
const relatedModelPrimaryKey = key;

return [
factory.createVariableStatement(
undefined,
Expand Down Expand Up @@ -101,6 +114,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
NodeFlags.Const,
),
),
// const linkedCPKClassesMap = new Map();
factory.createVariableStatement(
undefined,
factory.createVariableDeclarationList(
Expand Down Expand Up @@ -143,6 +157,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createVariableStatement(
undefined,
// const count = cPKClassesMap.get(r.specialClassId);
factory.createVariableDeclarationList(
[
factory.createVariableDeclaration(
Expand All @@ -158,7 +173,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createPropertyAccessExpression(
factory.createIdentifier('r'),
factory.createIdentifier('id'),
factory.createIdentifier(relatedModelPrimaryKey),
),
],
),
Expand Down Expand Up @@ -191,6 +206,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
NodeFlags.Const,
),
),
// cPKClassesMap.set(r.specialClassId, newCount);
factory.createExpressionStatement(
factory.createCallExpression(
factory.createPropertyAccessExpression(
Expand All @@ -201,7 +217,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createPropertyAccessExpression(
factory.createIdentifier('r'),
factory.createIdentifier('id'),
factory.createIdentifier(relatedModelPrimaryKey),
),
factory.createIdentifier('newCount'),
],
Expand Down Expand Up @@ -244,6 +260,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
undefined,
factory.createVariableDeclarationList(
[
// const count = linkedCPKClassesMap.get(r.specialClassId);
factory.createVariableDeclaration(
factory.createIdentifier('count'),
undefined,
Expand All @@ -257,7 +274,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createPropertyAccessExpression(
factory.createIdentifier('r'),
factory.createIdentifier('id'),
factory.createIdentifier(relatedModelPrimaryKey),
),
],
),
Expand Down Expand Up @@ -291,6 +308,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
),
),
factory.createExpressionStatement(
// linkedCPKClassesMap.set(r.specialClassId, newCount);
factory.createCallExpression(
factory.createPropertyAccessExpression(
factory.createIdentifier(originalMap),
Expand All @@ -300,7 +318,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createPropertyAccessExpression(
factory.createIdentifier('r'),
factory.createIdentifier('id'),
factory.createIdentifier(relatedModelPrimaryKey),
),
factory.createIdentifier('newCount'),
],
Expand Down Expand Up @@ -671,6 +689,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
undefined,
[factory.createIdentifier('id')],
),
// r.cpkTeacherID.eq(cPKTeacherRecord.specialTeacherId),
factory.createCallExpression(
factory.createPropertyAccessExpression(
factory.createPropertyAccessExpression(
Expand All @@ -683,7 +702,7 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createPropertyAccessExpression(
factory.createIdentifier(`${lowerCaseFirst(modelName)}Record`),
factory.createIdentifier('id'),
factory.createIdentifier(thisModelPrimaryKey),
),
],
),
Expand Down Expand Up @@ -835,11 +854,12 @@ export const buildManyToManyRelationshipDataStoreStatements = (
[
factory.createObjectLiteralExpression(
[
// cpkTeacherID: cPKTeacherRecord.specialTeacherId,
factory.createPropertyAssignment(
factory.createIdentifier(`${relatedModelField}ID`),
factory.createPropertyAccessExpression(
factory.createIdentifier(`${lowerCaseFirst(modelName)}Record`),
factory.createIdentifier('id'),
factory.createIdentifier(thisModelPrimaryKey),
),
),
factory.createPropertyAssignment(
Expand Down
8 changes: 3 additions & 5 deletions packages/codegen-ui-react/lib/forms/react-form-renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import {
StudioNode,
StudioTemplateRenderer,
validateFormSchema,
DataSchemaMetaData,
getDataSchemaMetaData,
} from '@aws-amplify/codegen-ui';
import { EOL } from 'os';
Expand Down Expand Up @@ -122,8 +121,6 @@ export abstract class ReactFormTemplateRenderer extends StudioTemplateRenderer<

protected shouldRenderArrayField = false;

protected dataSchemaMetadata: DataSchemaMetaData | undefined;

protected primaryKey: string | undefined;

constructor(component: StudioForm, dataSchema: GenericDataSchema | undefined, renderConfig: ReactRenderConfig) {
Expand All @@ -144,10 +141,11 @@ export abstract class ReactFormTemplateRenderer extends StudioTemplateRenderer<
this.componentMetadata.formMetadata = mapFormMetadata(this.component, this.formDefinition);
this.importCollection = new ImportCollection(this.componentMetadata);
if (dataSchema) {
this.dataSchemaMetadata = getDataSchemaMetaData({ dataSchema });
const dataSchemaMetadata = getDataSchemaMetaData({ dataSchema });
this.componentMetadata.dataSchemaMetadata = dataSchemaMetadata;
const { dataSourceType, dataTypeName } = this.component.dataType;
if (dataSourceType === 'DataStore') {
this.primaryKey = this.dataSchemaMetadata?.models[dataTypeName].primaryKey;
this.primaryKey = dataSchemaMetadata.models[dataTypeName].primaryKey;
}
}
}
Expand Down

0 comments on commit c5d6abd

Please sign in to comment.