amplify-category-api icon indicating copy to clipboard operation
amplify-category-api copied to clipboard

[Data] GSIs do not work in multiple cases

Open ryanmalesic opened this issue 1 year ago • 2 comments

Environment information

System:
  OS: macOS 14.3.1
  CPU: (10) arm64 Apple M1 Pro
  Memory: 1.33 GB / 32.00 GB
  Shell: /bin/zsh
Binaries:
  Node: 18.17.1 - ~/.nvm/versions/node/v18.17.1/bin/node
  Yarn: undefined - undefined
  npm: 9.6.7 - ~/.nvm/versions/node/v18.17.1/bin/npm
  pnpm: undefined - undefined
NPM Packages:
  @aws-amplify/backend: 0.13.0-beta.9
  @aws-amplify/backend-cli: 0.12.0-beta.10
  aws-amplify: 6.0.21
  aws-cdk: 2.133.0
  aws-cdk-lib: 2.133.0
  typescript: 5.4.3
AWS environment variables:
  AWS_STS_REGIONAL_ENDPOINTS = regional
  AWS_NODEJS_CONNECTION_REUSE_ENABLED = 1
  AWS_SDK_LOAD_CONFIG = 1
No CDK environment variables%

Description

  1. Secondary Indexes are not defined by a callback like documentation says: https://docs.amplify.aws/gen2/build-a-backend/data/data-modeling/secondary-index/
  2. Models with multiple secondary indexes can't be used because at runtime, every generated function past the first is undefined.
  3. Models with a secondary index with createdAt or updatedAt don't work because the schema code gets generated with ModelStringKeyConditionInput and ModelAWSDateTimeKeyConditionInput is expected instead.
  4. Models with a secondary index with multiple sort keys dont work at all because the schema code gets generated with the wrong input mapping ((eq) -> sk1, sk2 is generated but sk1->(eq), sk2 ->(eq) is expected) Validation error of type UnknownArgument: Unknown field argument

1:

Argument of type '(index: any) => any[]' is not assignable to parameter of type 'readonly []'.

If we disable typescript for the definition: secondaryIndexes.reduce is not a function

Instead we can do

.secondaryIndexes([
      a.index('status').sortKeys(['service', 'name']).queryField('listByStatusAndServiceAndName'),
      a.index('status').sortKeys(['updatedAt']).queryField('listByStatusAndUpdatedAt'),
]),

This also means these indexes are now globally defined and named. I.E multiple models cant define a GSI that use the same field names as the generated name now clashes


2:

 .secondaryIndexes([
      a.index('status').sortKeys(['service', 'name']).queryField('listByStatusAndServiceAndName'),
      a.index('status').sortKeys(['updatedAt']).queryField('listByStatusAndUpdatedAt'),
]),

listByStatusAndUpdatedAt is undefined at runtime (TS typehints work though)


3:

 .secondaryIndexes([
      a.index('status').sortKeys(['updatedAt']).queryField('listByStatusAndUpdatedAt'),
]),

Validation error of type UnknownType: Unknown type ModelAWSDateTimeKeyConditionInput

listByStatusAndUpdatedAt(
		status: String!,
		updatedAt: ModelStringKeyConditionInput,
		sortDirection: ModelSortDirection,
		filter: ModelResourceTypeFilterInput,
		limit: Int,
		nextToken: String
): ModelResourceTypeConnection

4:

 .secondaryIndexes([
      a.index('status').sortKeys(['service', 'name']).queryField('listByStatusAndServiceAndName'),
])
...
const { data: resourceTypes, errors } = await cookiesClient.models.ResourceType.listByStatusAndServiceAndName({
  status: searchParams['status'] || 'active',
})

errors [
  {
    "path": null,
    "locations": [
      {
        "line": 4,
        "column": 5,
        "sourceName": null
      }
    ],
    "message": "Validation error of type UnknownArgument: Unknown field argument service @ 'listByStatusAndServiceAndName'"
  },
  {
    "path": null,
    "locations": [
      {
        "line": 5,
        "column": 5,
        "sourceName": null
      }
    ],
    "message": "Validation error of type UnknownArgument: Unknown field argument name @ 'listByStatusAndServiceAndName'"
  }
listByStatusAndServiceAndName(
		status: String!,
		serviceName: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyConditionInput,
		sortDirection: ModelSortDirection,
		filter: ModelResourceTypeFilterInput,
		limit: Int,
		nextToken: String
): ModelResourceTypeConnection

input ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyConditionInput {
	eq: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput
	le: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput
	lt: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput
	ge: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput
	gt: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput
	between: [ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput]
	beginsWith: ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput
}

input ModelResourceTypeResourceTypesByStatusAndServiceAndNameCompositeKeyInput {
	service: String
	name: String
}

ryanmalesic avatar Apr 01 '24 07:04 ryanmalesic

I've run into something similar to point 3. as well when trying to query a one-to-many relationship with a composite identifier that's not a string:

  Task: a
    .model({
      name: a.string().required(),
      events: a.hasMany('Event', 'taskId')
    }),
  Event: a
    .model({
      date: a.date().required(),
      taskId: a.id().required(),
      task: a.belongsTo('Task', 'taskId'),
    }).identifier(['taskId', 'date']),

const { data, errors } = await task.events()

"message": "Validation error of type UnknownType: Unknown type ModelAWSDateKeyConditionInput"

Its expecting a ModelAWSDateKeyConditionInput but a ModelStringKeyConditionInput is created by the backend instead for the date() field type.

deconduino avatar Apr 28 '24 09:04 deconduino

I've run into something similar to point 3. as well when trying to query a one-to-many relationship with a composite identifier that's not a string:

  Task: a
    .model({
      name: a.string().required(),
      events: a.hasMany('Event', 'taskId')
    }),
  Event: a
    .model({
      date: a.date().required(),
      taskId: a.id().required(),
      task: a.belongsTo('Task', 'taskId'),
    }).identifier(['taskId', 'date']),

const { data, errors } = await task.events()

"message": "Validation error of type UnknownType: Unknown type ModelAWSDateKeyConditionInput"

Its expecting a ModelAWSDateKeyConditionInput but a ModelStringKeyConditionInput is created by the backend instead for the date() field type.

Hi @deconduino this particular issue should be resolved now on the latest versions of @aws-amplify/backend and @aws-amplify/backend-cli.

npm i aws-amplify@latest @aws-amplify/backend@latest @aws-amplify/backend-cli@latest

We are actively working on resolving the other issues earlier mentioned in this thread.

chrisbonifacio avatar May 07 '24 18:05 chrisbonifacio

The remaining issues should now be resolved as well. If you haven't already, please upgrade the package versions as Chris suggested above:

npm i aws-amplify@latest @aws-amplify/backend@latest @aws-amplify/backend-cli@latest

Afterwards, run:

npm update @aws-amplify/data-schema

Please let us know if you run into any more issues

iartemiev avatar May 15 '24 14:05 iartemiev

This issue is now closed. Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one.

github-actions[bot] avatar May 15 '24 14:05 github-actions[bot]

The issue persists for me, Though I did follow your instructions for upgrading amplify This is my model

Record: a .model({ lotNumber: a.string(), lotId:a.string(), lot: a.belongsTo('ProductionLot', ['lotId','lotNumber']), timestamp: a.timestamp().required(), comment : a.string() }) .secondaryIndexes((index) => [ index('lotId').sortKeys(['timestamp']), ]),

the error I'm getting is:

message: "Validation error of type UnknownType: Unknown type ModelAWSTimestampKeyConditionInput"

I figured out in .amplify/artifacts/cdk.out in my query we have:

listRecordByLotIdAndTimestamp(lotId: String!, timestamp: ModelIntKeyConditionInput, sortDirection: ModelSortDirection, filter: ModelRecordFilterInput, limit: Int, nextToken: String): ModelRecordConnection @aws_iam @aws_cognito_user_pools could this be the triggering point. since timestamp type is ModelIntKeyConditionInput

nima-nejad avatar Jul 09 '24 18:07 nima-nejad