Skip to content

Commit 481b874

Browse files
committed
fix(relational-transformer): read related-table GSIs compatibly with aws-cdk-lib 2.260 (globalSecondaryIndexes no longer populated) [#3505]
aws-cdk-lib 2.260 renamed the private DynamoDB L2 Table field `globalSecondaryIndexes`/`localSecondaryIndexes` to `_globalSecondaryIndexes`/`_localSecondaryIndexes` (now ArrayBox-backed, same `.some`/`.find`/`.length` surface and `{ indexName, keySchema }` element shape). The transformer read the old names, yielding `undefined` and `TypeError: Cannot read properties of undefined (reading 'some'/'find')`, breaking 63 relational unit tests plus a conversation unit test. Read the renamed field first, falling back to the public `globalSecondaryIndexes` used by Amplify's managed-table construct, so the duplicate-index-name dedupe is preserved (not disabled) for both table types. Sites fixed: - amplify-graphql-relational-transformer/src/resolvers.ts (3 reads) - amplify-graphql-transformer-core/src/utils/schema-utils.ts (getKeySchema) - amplify-graphql-conversation-transformer conversation-resolver-generator.ts
1 parent 25bbb1d commit 481b874

3 files changed

Lines changed: 34 additions & 9 deletions

File tree

packages/amplify-graphql-conversation-transformer/src/transformer-steps/conversation-resolver-generator.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,11 @@ export class ConversationResolverGenerator {
331331
writeCapacity: cdk.Fn.ref(ResourceConstants.PARAMETERS.DynamoDBModelTableWriteIOPS),
332332
});
333333

334-
const gsi = table.globalSecondaryIndexes.find((g: any) => g.indexName === indexName);
334+
// aws-cdk-lib 2.260 renamed the private `globalSecondaryIndexes` array on the DynamoDB L2 `Table` to
335+
// `_globalSecondaryIndexes` (an `ArrayBox` exposing the same `find` surface and `{ indexName, keySchema }`
336+
// element shape); Amplify's managed-table construct keeps the public `globalSecondaryIndexes` array.
337+
const globalSecondaryIndexes = table['_globalSecondaryIndexes'] ?? table.globalSecondaryIndexes;
338+
const gsi = globalSecondaryIndexes.find((g: any) => g.indexName === indexName);
335339

336340
const newIndex = {
337341
indexName,

packages/amplify-graphql-relational-transformer/src/resolvers.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,18 @@ import { getSortKeyFields } from './schema';
2929
import { HasManyDirectiveConfiguration, HasOneDirectiveConfiguration } from './types';
3030
import { getConnectionAttributeName, getObjectPrimaryKey } from './utils';
3131

32+
/**
33+
* Reads the list of global secondary indexes tracked on a DynamoDB L2 `Table` construct.
34+
*
35+
* `aws-cdk-lib` 2.260 renamed the (private) `globalSecondaryIndexes` array to `_globalSecondaryIndexes`
36+
* and now backs it with an `ArrayBox`, which still exposes the array-like `some`/`find`/`length` surface
37+
* and the same element shape (`{ indexName, keySchema }`). Amplify's own managed-table construct
38+
* (`AmplifyDynamoDBTable`) instead keeps its indexes on a public `globalSecondaryIndexes` array. Reading
39+
* `_globalSecondaryIndexes` first and falling back to `globalSecondaryIndexes` works for both table types
40+
* and preserves the duplicate-index-name detection rather than silently disabling it.
41+
*/
42+
const getGlobalSecondaryIndexes = (table: any): any => table['_globalSecondaryIndexes'] ?? table.globalSecondaryIndexes;
43+
3244
/**
3345
* Creates a GSI on the table of the `relatedType` based on the config's `references` / `referenceNodes`
3446
*
@@ -54,7 +66,7 @@ export const updateTableForReferencesConnection = (
5466
}
5567

5668
const relatedTable = getTable(ctx, relatedType);
57-
const gsis = relatedTable.globalSecondaryIndexes;
69+
const gsis = getGlobalSecondaryIndexes(relatedTable);
5870
if (gsis.some((gsi: any) => gsi.indexName === indexName)) {
5971
// We create a GSI on the Related model's table for querying
6072
// relationships using the format 'gsi-{PrimaryModelName}.{PrimaryModelConnectionField}'
@@ -136,7 +148,7 @@ export const updateTableForConnection = (config: HasManyDirectiveConfiguration,
136148
const { field, object, relatedType } = config;
137149
const mappedObjectName = ctx.resourceHelper.getModelNameMapping(object.name.value);
138150
const table = getTable(ctx, relatedType) as any;
139-
const gsis = table.globalSecondaryIndexes;
151+
const gsis = getGlobalSecondaryIndexes(table);
140152

141153
const indexName = `gsi-${mappedObjectName}.${field.name.value}`;
142154
config.indexName = indexName;
@@ -202,7 +214,7 @@ const addGlobalSecondaryIndex = (
202214
// At the L2 level, the CDK does not handle the way Amplify sets GSI read and write capacity
203215
// very well. At the L1 level, the CDK does not create the correct IAM policy for accessing the
204216
// GSI. To get around these issues, keep the L1 and L2 GSI list in sync.
205-
const gsi = table.globalSecondaryIndexes.find((g: any) => g.indexName === indexName);
217+
const gsi = getGlobalSecondaryIndexes(table).find((g: any) => g.indexName === indexName);
206218

207219
const newIndex = {
208220
indexName,

packages/amplify-graphql-transformer-core/src/utils/schema-utils.ts

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,20 @@ import { getModelDataSourceStrategy } from './model-datasource-strategy-utils';
99
/**
1010
* getKeySchema
1111
*/
12-
export const getKeySchema = (table: any, indexName?: string): any =>
13-
(
14-
table.globalSecondaryIndexes.find((gsi: any) => gsi.indexName === indexName) ??
15-
table.localSecondaryIndexes.find((gsi: any) => gsi.indexName === indexName)
16-
)?.keySchema ?? table.keySchema;
12+
export const getKeySchema = (table: any, indexName?: string): any => {
13+
// aws-cdk-lib 2.260 renamed the private `globalSecondaryIndexes`/`localSecondaryIndexes` arrays on the
14+
// DynamoDB L2 `Table` to `_globalSecondaryIndexes`/`_localSecondaryIndexes` (now `ArrayBox`es exposing the
15+
// same `find` surface and element shape). Amplify's managed-table construct keeps the public array names.
16+
// Read the renamed fields first, falling back to the public ones so both table types resolve correctly.
17+
const globalSecondaryIndexes = table['_globalSecondaryIndexes'] ?? table.globalSecondaryIndexes;
18+
const localSecondaryIndexes = table['_localSecondaryIndexes'] ?? table.localSecondaryIndexes;
19+
return (
20+
(
21+
globalSecondaryIndexes.find((gsi: any) => gsi.indexName === indexName) ??
22+
localSecondaryIndexes.find((gsi: any) => gsi.indexName === indexName)
23+
)?.keySchema ?? table.keySchema
24+
);
25+
};
1726

1827
/**
1928
* getTable

0 commit comments

Comments
 (0)