Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: gql compiler fix for user defined mutation #6059

Merged
merged 6 commits into from
Mar 5, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
akshbhu marked this conversation as resolved.
Show resolved Hide resolved
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');
});
});