Skip to content

Commit

Permalink
fix(amplify-codegen): support multiple indexes on the same field in i…
Browse files Browse the repository at this point in the history
…ntrospection schema
  • Loading branch information
sundersc committed Sep 16, 2024
1 parent 359533d commit affca61
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,78 @@ describe('processIndex', () => {
]);
});

it('support multiple @index directives on a field', () => {
const model: CodeGenModel = {
directives: [
{
name: 'model',
arguments: {},
},
],
name: 'testModel',
type: 'model',
fields: [
{
type: 'field',
isList: false,
isNullable: true,
name: 'connectionField',
directives: [
{
name: 'index',
arguments: {
name: 'byItemAndSortField',
sortKeyFields: ['sortField'],
},
},
{
name: 'index',
arguments: {
name: 'byItemAndAnotherSortField',
sortKeyFields: ['anotherSortField'],
},
},
{
name: 'index',
arguments: {
name: 'byItemAndSomeOtherSortField',
sortKeyFields: ['someOtherSortField'],
},
},
],
},
],
};
processIndex(model);
expect(model.directives).toEqual([
{
name: 'model',
arguments: {},
},
{
name: 'key',
arguments: {
name: 'byItemAndSortField',
fields: ['connectionField', 'sortField'],
},
},
{
name: 'key',
arguments: {
name: 'byItemAndAnotherSortField',
fields: ['connectionField', 'anotherSortField'],
},
},
{
name: 'key',
arguments: {
name: 'byItemAndSomeOtherSortField',
fields: ['connectionField', 'someOtherSortField'],
},
},
]);
});

it('adds simple @index directives as model key attributes', () => {
const model: CodeGenModel = {
directives: [
Expand Down
3 changes: 3 additions & 0 deletions packages/appsync-modelgen-plugin/src/utils/fieldUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export function removeFieldFromModel(model: CodeGenModel, fieldName: string): vo
export const getDirective = (fieldOrModel: CodeGenField | CodeGenModel) => (directiveName: string): CodeGenDirective | undefined =>
fieldOrModel.directives.find(d => d.name === directiveName);

export const getDirectives = (fieldOrModel: CodeGenField | CodeGenModel) => (directiveName: string): CodeGenDirective[] | undefined =>
fieldOrModel.directives.filter(d => d.name === directiveName);

// Function matching to GraphQL transformer so that the auto-generated field
export function toCamelCase(words: string[]): string {
const formatted = words.map((w, i) => (i === 0 ? w.charAt(0).toLowerCase() + w.slice(1) : w.charAt(0).toUpperCase() + w.slice(1)));
Expand Down
32 changes: 19 additions & 13 deletions packages/appsync-modelgen-plugin/src/utils/process-index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CodeGenDirective, CodeGenModel } from '../visitors/appsync-visitor';
import { getDirective } from './fieldUtils';
import { getDirectives } from './fieldUtils';
import pluralize from 'pluralize';
import { toLower, toUpper } from './stringUtils';

Expand All @@ -9,21 +9,27 @@ import { toLower, toUpper } from './stringUtils';
*/
export const processIndex = (model: CodeGenModel) => {
const indexMap = model.fields.reduce((acc, field) => {
const indexDirective = getDirective(field)('index');
if (!indexDirective) {
const indexDirectives = getDirectives(field)('index');
if (!indexDirectives) {
return acc;
}
return { ...acc, [field.name]: indexDirective };
}, {} as Record<string, CodeGenDirective>);
return { ...acc, [field.name]: indexDirectives };
}, {} as Record<string, CodeGenDirective[]>);

const keyList: CodeGenDirective[] = [];
Object.entries(indexMap).forEach(([fieldName, directives]) => {
directives.forEach(directive => {
keyList.push({
name: 'key',
arguments: {
name: directive.arguments.name ?? generateDefaultIndexName(model.name, [fieldName].concat((directive.arguments.sortKeyFields as string[]) ?? [])),
queryField: directive.arguments.queryField,
fields: [fieldName].concat((directive.arguments.sortKeyFields as string[]) ?? []),
},
});
});
});

const keyList: CodeGenDirective[] = Object.entries(indexMap).map(([fieldName, directive]) => ({
name: 'key',
arguments: {
name: directive.arguments.name ?? generateDefaultIndexName(model.name, [fieldName].concat((directive.arguments.sortKeyFields as string[]) ?? [])),
queryField: directive.arguments.queryField,
fields: [fieldName].concat((directive.arguments.sortKeyFields as string[]) ?? []),
},
}));
const existingIndexNames = model.directives
.filter(directive => directive.name === 'key' && !!directive.arguments.name)
.map(directive => directive.arguments.name);
Expand Down

0 comments on commit affca61

Please sign in to comment.