Skip to content

Commit

Permalink
fix: gql compiler fix for user defined mutation (#6059)
Browse files Browse the repository at this point in the history
* fix: gql compiler fix for user defined mutation
  • Loading branch information
akshbhu authored Mar 5, 2021
1 parent 9df296c commit 063d84f
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 4 deletions.
6 changes: 6 additions & 0 deletions packages/amplify-cli-core/src/feature-flags/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,12 @@ export class FeatureFlags {
defaultValueForExistingProjects: false,
defaultValueForNewProjects: true,
},
{
name: 'skipOverrideMutationInput',
type: 'boolean',
defaultValueForExistingProjects: false,
defaultValueForNewProjects: true,
}
]);

this.registerFlag('frontend-ios', [
Expand Down
19 changes: 16 additions & 3 deletions packages/graphql-key-transformer/src/KeyTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,22 +454,35 @@ export class KeyTransformer extends Transformer {
if (this.isPrimaryKey(directive)) {
const directiveArgs: KeyArguments = getDirectiveArguments(directive);

// check @model mutation argument to update schema or not
let shouldMakeCreate = true;
let shouldMakeUpdate = true;
let shouldMakeDelete = true;

if (ctx.featureFlags.getBoolean('skipOverrideMutationInputTypes', false)) {
const modelDirective = definition.directives.find(dir => dir.name.value === 'model');
const modelDirectiveArgs = getDirectiveArguments(modelDirective);
// Figure out which mutations to make and if they have name overrides
shouldMakeCreate = !!modelDirectiveArgs?.mutations?.create;
shouldMakeUpdate = !!modelDirectiveArgs?.mutations?.update;
shouldMakeDelete = !!modelDirectiveArgs?.mutations?.delete;
}
const hasIdField = definition.fields.find(f => f.name.value === 'id');
if (!hasIdField) {
const createInput = ctx.getType(
ModelResourceIDs.ModelCreateInputObjectName(definition.name.value),
) as InputObjectTypeDefinitionNode;
if (createInput) {
if (createInput && shouldMakeCreate) {
ctx.putType(replaceCreateInput(definition, createInput, directiveArgs.fields));
}
}

const updateInput = ctx.getType(ModelResourceIDs.ModelUpdateInputObjectName(definition.name.value)) as InputObjectTypeDefinitionNode;
if (updateInput) {
if (updateInput && shouldMakeUpdate) {
ctx.putType(replaceUpdateInput(definition, updateInput, directiveArgs.fields));
}
const deleteInput = ctx.getType(ModelResourceIDs.ModelDeleteInputObjectName(definition.name.value)) as InputObjectTypeDefinitionNode;
if (deleteInput) {
if (deleteInput && shouldMakeDelete) {
ctx.putType(replaceDeleteInput(definition, deleteInput, directiveArgs.fields));
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { parse, InputObjectTypeDefinitionNode, DefinitionNode, DocumentNode, Kind } from 'graphql';
import { GraphQLTransform, InvalidDirectiveError, SyncConfig, ConflictHandlerType } from 'graphql-transformer-core';
import { GraphQLTransform, InvalidDirectiveError, SyncConfig, ConflictHandlerType, FeatureFlagProvider } from 'graphql-transformer-core';
import { KeyTransformer } from '../KeyTransformer';
import { DynamoDBModelTransformer } from 'graphql-dynamodb-transformer';

Expand Down Expand Up @@ -298,3 +298,99 @@ function getInputType(doc: DocumentNode, type: string): InputObjectTypeDefinitio
| InputObjectTypeDefinitionNode
| undefined;
}

describe('check schema input', () => {
let ff: FeatureFlagProvider;
beforeEach(() => {
ff = {
getBoolean: jest.fn().mockImplementation((name, defaultValue) => {
if (name === 'skipOverrideMutationInputTypes') {
return true;
}
}),
getNumber: jest.fn(),
getObject: jest.fn(),
getString: jest.fn(),
};
});

it('@model mutation with user defined null args ', () => {
const validSchema = /* GraphQL */ `
type Call
@model(queries: null, mutations: null)
@key(fields: ["receiverId", "senderId"])
@key(name: "bySender", fields: ["senderId", "receiverId"]) {
senderId: ID!
receiverId: ID!
}
type Mutation {
createCall(input: CreateCallInput!): Call
deleteCall(input: DeleteCallInput!): Call
}
input CreateCallInput {
receiverId: ID!
}
input DeleteCallInput {
receiverId: ID!
}
`;
const transformer = new GraphQLTransform({
transformers: [new DynamoDBModelTransformer(), new KeyTransformer()],
featureFlags: ff,
});
const out = transformer.transform(validSchema);
expect(out).toBeDefined();
const schema = parse(out.schema);

const DeleteCallInput: InputObjectTypeDefinitionNode = schema.definitions.find(
d => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'DeleteCallInput',
) as InputObjectTypeDefinitionNode | undefined;
expect(DeleteCallInput).toBeDefined();
const receiverIdField = DeleteCallInput.fields.find(f => f.name.value === 'receiverId');
expect(receiverIdField).toBeDefined();
expect(receiverIdField.type.kind).toBe('NonNullType');
const senderIdField = DeleteCallInput.fields.find(f => f.name.value === 'senderId');
expect(senderIdField).toBeUndefined();
});

it('@model mutation with user defined create args ', () => {
const validSchema = /* GraphQL */ `
type Call
@model(queries: null, mutations: { delete: "testDelete" })
@key(fields: ["receiverId", "senderId"])
@key(name: "bySender", fields: ["senderId", "receiverId"]) {
senderId: ID!
receiverId: ID!
}
input CreateCallInput {
receiverId: ID!
}
input DeleteCallInput {
receiverId: ID!
}
`;
const transformer = new GraphQLTransform({
transformers: [new DynamoDBModelTransformer(), new KeyTransformer()],
featureFlags: ff,
});
const out = transformer.transform(validSchema);
expect(out).toBeDefined();
const schema = parse(out.schema);

const DeleteCallInput: InputObjectTypeDefinitionNode = schema.definitions.find(
d => d.kind === 'InputObjectTypeDefinition' && d.name.value === 'DeleteCallInput',
) as InputObjectTypeDefinitionNode | undefined;
expect(DeleteCallInput).toBeDefined();
const receiverIdField = DeleteCallInput.fields.find(f => f.name.value === 'receiverId');
expect(receiverIdField).toBeDefined();
expect(receiverIdField.type.kind).toBe('NonNullType');
const senderIdField = DeleteCallInput.fields.find(f => f.name.value === 'senderId');
expect(senderIdField).toBeDefined();
expect(senderIdField.type.kind).toBe('NonNullType');
});
});

0 comments on commit 063d84f

Please sign in to comment.