aws-amplify / amplify-category-api

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development. This plugin provides functionality for the API category, allowing for the creation and management of GraphQL and REST based backends for your amplify project.
https://docs.amplify.aws/
Apache License 2.0
81 stars 71 forks source link

DataSchema breaks if updatedAt/createdAt are not defined in the model when creating secondaryIndex with sortKeys with them #2654

Open mauriciomassaia opened 6 days ago

mauriciomassaia commented 6 days ago

Environment information

System:
  OS: macOS 14.5
  CPU: (8) arm64 Apple M1
  Memory: 143.28 MB / 16.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 20.12.1 - ~/.nvm/versions/node/v20.12.1/bin/node
  Yarn: undefined - undefined
  npm: 10.5.0 - ~/.nvm/versions/node/v20.12.1/bin/npm
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 1.0.2
  @aws-amplify/backend-cli: 1.0.3
  aws-amplify: 6.3.4
  aws-cdk: 2.141.0
  aws-cdk-lib: 2.141.0
  typescript: 5.4.5
AWS environment variables:
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
No CDK environment variables

Data packages

├─┬ @aws-amplify/backend-cli@1.0.3
│ └─┬ @aws-amplify/schema-generator@1.0.0
│   └── @aws-amplify/graphql-schema-generator@0.8.5
└─┬ @aws-amplify/backend@1.0.2
  └─┬ @aws-amplify/backend-data@1.0.1
    └── @aws-amplify/data-construct@1.8.2

Description

In the docs: https://docs.amplify.aws/react/build-a-backend/data/mutate-data/#create-an-item says:

Note: You do not need to specify createdAt or updatedAt fields because Amplify automatically populates these fields for you.

But if you don't declare them, the lint breaks if you want to use them as sortKeys, so I had to declare both of them to be able to use as sortKeys. and it also broke the auto complete for my models list methods.

for example:

const schema = a.schema({
  Privacy: a.enum(['public', 'private', 'shared']),
  MyModel: a
    .model({
      ownerUserId: a.id().required(),
      name: a.string(),
      privacy: a.ref('Privacy'),
    })
    .secondaryIndexes((index) => [
      index('ownerUserId').name('byOwner').sortKeys(['updatedAt']),
    ]),
});

So it auto generated the following query so to be used in the frontend:

client.models.MyModel.listCreativeMetaByOwnerUserId({
  ownerUserId: 'USER_ID_HERE'
});

It shows this error:

 error TS2322: Type '"updatedAt"' is not assignable to type '"name" | "ownerUserId" | "privacy"'.
TypeScript validation check failed.
Resolution: Fix the syntax and type errors in your backend definition.

To by pass this I had to add updatedAt and created to my model:

const schema = a.schema({
  Privacy: a.enum(['public', 'private', 'shared']),
  MyModel: a
    .model({
      updatedAt: a.datetime(),
      createdAt: a.datetime(),
      ownerUserId: a.id().required(),
      name: a.string(),
      privacy: a.ref('Privacy'),
    })
    .secondaryIndexes((index) => [
      index('ownerUserId').name('byOwner').sortKeys(['updatedAt']),
    ]),
});

So it auto generated the following query so to be used in the frontend:

client.models.MyModel.listCreativeMetaByOwnerUserIdAndUpdatedAt({
  ownerUserId: 'USER_ID_HERE'
});

And then it works as intended.

Just wanna check if this is the intended behaviour or if im missing something.

chrisbonifacio commented 4 days ago

Hi @mauriciomassaia , this is expected behavior. Any fields used as sort keys or referenced through the schema builder functions must be defined on the model. The createdAt/updatedAt fields are added at the time of transformation.

However, we might be able to improve this by making it available in the types ahead of time.

I'll mark this as a feature request for the team to consider as it sounds like it could be a potential DX improvement.