diff --git a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap index 3eccfa182..6a4b1fb45 100644 --- a/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap +++ b/packages/codegen-ui-react/lib/__tests__/__snapshots__/studio-ui-codegen-react.test.ts.snap @@ -1094,7 +1094,7 @@ export default function CollectionOfCustomButtons( } = props; const itemsFilterObj = { and: [ - { field: \\"age\\", operand: \\"10\\", operator: \\"gt\\" }, + { field: \\"age\\", operand: 10, operator: \\"eq\\" }, { field: \\"lastName\\", operand: \\"L\\", operator: \\"beginsWith\\" }, ], }; diff --git a/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts b/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts index 78a17003b..54eedc477 100644 --- a/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts +++ b/packages/codegen-ui-react/lib/__tests__/__utils__/mock-data-schemas.ts @@ -480,3 +480,90 @@ export const compositePersonSchema: GenericDataSchema = getGenericFromDataStore( codegenVersion: '3.3.2', version: 'accea0d7a2f24829740c710ceb3264a8', }); + +export const userSchema: GenericDataSchema = getGenericFromDataStore({ + models: { + User: { + name: 'User', + fields: { + id: { + name: 'id', + isArray: false, + type: 'ID', + isRequired: true, + attributes: [], + }, + firstName: { + name: 'firstName', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + lastName: { + name: 'lastName', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + age: { + name: 'age', + isArray: false, + type: 'Int', + isRequired: false, + attributes: [], + }, + isLoggedIn: { + name: 'isLoggedIn', + isArray: false, + type: 'Boolean', + isRequired: false, + attributes: [], + }, + loggedInColor: { + name: 'loggedInColor', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + loggedOutColor: { + name: 'loggedOutColor', + isArray: false, + type: 'String', + isRequired: false, + attributes: [], + }, + createdAt: { + name: 'createdAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + updatedAt: { + name: 'updatedAt', + isArray: false, + type: 'AWSDateTime', + isRequired: false, + attributes: [], + isReadOnly: true, + }, + }, + syncable: true, + pluralName: 'Users', + attributes: [ + { + type: 'model', + properties: {}, + }, + ], + }, + }, + enums: {}, + nonModels: {}, + codegenVersion: '3.3.2', + version: 'accea0d7a2f24829740c710ceb3264a8', +}); diff --git a/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts b/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts index 9b53eab2a..c179c35dd 100644 --- a/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts +++ b/packages/codegen-ui-react/lib/__tests__/react-component-render-helper.test.ts @@ -35,6 +35,7 @@ import { buildConditionalExpression, hasChildrenProp, buildConcatExpression, + parseNumberOperand, } from '../react-component-render-helper'; import { assertASTMatchesSnapshot } from './__utils__'; @@ -345,4 +346,15 @@ describe('react-component-render-helper', () => { assertASTMatchesSnapshot(exp); }); }); + + describe('parseNumberOperand', () => { + test('should parse int if field data type is Int', () => { + expect(parseNumberOperand('10', { dataType: 'Int', readOnly: false, required: false, isArray: false })).toBe(10); + }); + test('should parse int if field data type is Int', () => { + expect(parseNumberOperand('10.01', { dataType: 'Float', readOnly: false, required: false, isArray: false })).toBe( + 10.01, + ); + }); + }); }); diff --git a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts index dbe109820..aff8e6984 100644 --- a/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts +++ b/packages/codegen-ui-react/lib/__tests__/studio-ui-codegen-react.test.ts @@ -14,7 +14,7 @@ limitations under the License. */ import { ModuleKind, ScriptTarget, ScriptKind } from '..'; -import { authorHasManySchema, compositePersonSchema, generateWithAmplifyRenderer } from './__utils__'; +import { authorHasManySchema, compositePersonSchema, generateWithAmplifyRenderer, userSchema } from './__utils__'; describe('amplify render tests', () => { describe('basic component tests', () => { @@ -121,7 +121,12 @@ describe('amplify render tests', () => { }); it('should render collection with data binding if binding name is items', () => { - const generatedCode = generateWithAmplifyRenderer('collectionWithBindingItemsName'); + const generatedCode = generateWithAmplifyRenderer( + 'collectionWithBindingItemsName', + undefined, + undefined, + userSchema, + ); expect(generatedCode.componentText).toMatchSnapshot(); }); diff --git a/packages/codegen-ui-react/lib/react-component-render-helper.ts b/packages/codegen-ui-react/lib/react-component-render-helper.ts index f526d2568..35caae940 100644 --- a/packages/codegen-ui-react/lib/react-component-render-helper.ts +++ b/packages/codegen-ui-react/lib/react-component-render-helper.ts @@ -52,7 +52,13 @@ import { ArrayLiteralExpression, } from 'typescript'; -import { FormMetadata, FormStyleConfig, StudioFormInputFieldProperty } from '@aws-amplify/codegen-ui/lib/types'; +import { + DataFieldDataType, + FormMetadata, + FormStyleConfig, + GenericDataField, + StudioFormInputFieldProperty, +} from '@aws-amplify/codegen-ui/lib/types'; import { ImportCollection, ImportSource } from './imports'; import { json, jsonToLiteral } from './react-studio-template-renderer-helper'; import { getChildPropMappingForComponentName } from './workflow/utils'; @@ -458,6 +464,19 @@ export function getSyntaxKindToken(operator: RelationalOperator): BinaryOperator } } +export function parseNumberOperand(operand: string | number | boolean, dataField: GenericDataField | undefined) { + if (dataField) { + const numberOperandType: DataFieldDataType[] = ['Int', 'Float']; + if (numberOperandType.includes(dataField.dataType)) { + const parsedOperand = parseFloat(`${operand}`); + if (!Number.isNaN(parsedOperand) && Number.isFinite(parsedOperand)) { + return parsedOperand; + } + } + } + return operand; +} + export function getConditionalOperandExpression( operand: string | number | boolean, operandType: string | undefined, diff --git a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts index 061847486..c0f3d5525 100644 --- a/packages/codegen-ui-react/lib/react-studio-template-renderer.ts +++ b/packages/codegen-ui-react/lib/react-studio-template-renderer.ts @@ -72,6 +72,7 @@ import { addBindingPropertiesImports, getComponentPropName, getConditionalOperandExpression, + parseNumberOperand, } from './react-component-render-helper'; import { transpile, @@ -934,7 +935,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer const modelName = this.importCollection.addImport(ImportSource.LOCAL_MODELS, model); if (predicate) { - statements.push(this.buildPredicateDeclaration(propName, predicate)); + statements.push(this.buildPredicateDeclaration(propName, predicate, model)); statements.push(this.buildCreateDataStorePredicateCall(modelName, propName)); } if (sort) { @@ -1255,7 +1256,9 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer * operator: "eq", * } */ - statements.push(this.buildPredicateDeclaration(propName, bindingProperties.predicate)); + statements.push( + this.buildPredicateDeclaration(propName, bindingProperties.predicate, bindingProperties.model), + ); statements.push(this.buildCreateDataStorePredicateCall(modelName, propName)); /** * const buttonColorDataStore = useDataStoreBinding({ @@ -1436,11 +1439,14 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer ]); } - private predicateToObjectLiteralExpression(predicate: StudioComponentPredicate): ObjectLiteralExpression { + private predicateToObjectLiteralExpression( + predicate: StudioComponentPredicate, + model: string, + ): ObjectLiteralExpression { const { operandType, ...filteredPredicate } = predicate; if (filteredPredicate.operator === 'between') { - return this.predicateToObjectLiteralExpression(resolveBetweenPredicateToMultiplePredicates(predicate)); + return this.predicateToObjectLiteralExpression(resolveBetweenPredicateToMultiplePredicates(predicate), model); } const objectAssignments = Object.entries(filteredPredicate).map(([key, value]) => { @@ -1449,7 +1455,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer factory.createIdentifier(key), factory.createArrayLiteralExpression( (predicate[key] as StudioComponentPredicate[]).map( - (pred: StudioComponentPredicate) => this.predicateToObjectLiteralExpression(pred), + (pred: StudioComponentPredicate) => this.predicateToObjectLiteralExpression(pred, model), false, ), ), @@ -1458,7 +1464,13 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer if (key === 'operand' && typeof value === 'string') { return factory.createPropertyAssignment( factory.createIdentifier(key), - getConditionalOperandExpression(value, operandType), + getConditionalOperandExpression( + parseNumberOperand( + value, + this.componentMetadata.dataSchemaMetadata?.models[model]?.fields[predicate.field || ''], + ), + operandType, + ), ); } return factory.createPropertyAssignment( @@ -1480,7 +1492,11 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer return []; } - private buildPredicateDeclaration(name: string, predicate: StudioComponentPredicate): VariableStatement { + private buildPredicateDeclaration( + name: string, + predicate: StudioComponentPredicate, + model: string, + ): VariableStatement { return factory.createVariableStatement( undefined, factory.createVariableDeclarationList( @@ -1489,7 +1505,7 @@ export abstract class ReactStudioTemplateRenderer extends StudioTemplateRenderer factory.createIdentifier(this.getFilterObjName(name)), undefined, undefined, - this.predicateToObjectLiteralExpression(predicate), + this.predicateToObjectLiteralExpression(predicate, model), ), ], ts.NodeFlags.Const, diff --git a/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json b/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json index 9e792eacb..3a4a365d5 100644 --- a/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json +++ b/packages/codegen-ui/example-schemas/collectionWithBindingItemsName.json @@ -45,7 +45,7 @@ { "field": "age", "operand": "10", - "operator": "gt" + "operator": "eq" }, { "field": "lastName",