@aws-amplify/graphql-model-transformer
Advanced tools
Comparing version 0.6.0 to 0.6.1-beta.0
@@ -6,2 +6,15 @@ # Change Log | ||
## [0.6.1-beta.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-model-transformer@0.6.0...@aws-amplify/graphql-model-transformer@0.6.1-beta.0) (2021-08-30) | ||
### Bug Fixes | ||
* add model transformer v2 e2e tests ([#7946](https://github.com/aws-amplify/amplify-cli/issues/7946)) ([351a8bc](https://github.com/aws-amplify/amplify-cli/commit/351a8bce6069398535878fd62886e0ee5c402329)) | ||
* model transformer support condition ([#7935](https://github.com/aws-amplify/amplify-cli/issues/7935)) ([fc93dba](https://github.com/aws-amplify/amplify-cli/commit/fc93dbabb38427607ef6abb6f1d7fb2f357a284b)) | ||
* update and create input field type known model types filtering ([#7929](https://github.com/aws-amplify/amplify-cli/issues/7929)) ([16334f7](https://github.com/aws-amplify/amplify-cli/commit/16334f7217f0ac751a642d82512240aedec17721)) | ||
# [0.6.0](https://github.com/aws-amplify/amplify-cli/compare/@aws-amplify/graphql-model-transformer@0.5.1...@aws-amplify/graphql-model-transformer@0.6.0) (2021-08-24) | ||
@@ -8,0 +21,0 @@ |
import { TransformerModelBase } from '@aws-amplify/graphql-transformer-core'; | ||
import { AppSyncDataSourceType, DataSourceInstance, MutationFieldType, QueryFieldType, SubscriptionFieldType, TransformerContextProvider, TransformerModelProvider, TransformerPrepareStepContextProvider, TransformerResolverProvider, TransformerSchemaVisitStepContextProvider, TransformerTransformSchemaStepContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; | ||
import { DirectiveNode, FieldDefinitionNode, InputValueDefinitionNode, ObjectTypeDefinitionNode } from 'graphql'; | ||
import { DirectiveNode, InputValueDefinitionNode, ObjectTypeDefinitionNode } from 'graphql'; | ||
export declare type Nullable<T> = T | null; | ||
@@ -68,3 +68,5 @@ export declare type OptionalAndNullable<T> = Partial<T>; | ||
}>) => string; | ||
createSubscriptionFields: (ctx: TransformerTransformSchemaStepContextProvider, def: ObjectTypeDefinitionNode) => FieldDefinitionNode[]; | ||
private createQueryFields; | ||
private createMutationFields; | ||
private createSubscriptionFields; | ||
getSubscriptionFieldNames: (ctx: TransformerTransformSchemaStepContextProvider, type: ObjectTypeDefinitionNode) => Set<{ | ||
@@ -93,3 +95,4 @@ fieldName: string; | ||
private getSubscriptionToMutationsReverseMap; | ||
private ensureModelSortDirectionEnum; | ||
} | ||
//# sourceMappingURL=graphql-model-transformer.d.ts.map |
@@ -120,26 +120,10 @@ "use strict"; | ||
graphql_types_1.addModelConditionInputs(ctx); | ||
this.ensureModelSortDirectionEnum(ctx); | ||
for (const type of this.typesWithModelDirective) { | ||
const def = ctx.output.getObject(type); | ||
this.createNonModelInputs(ctx, def); | ||
const queryFields = this.getQueryFieldNames(ctx, def); | ||
for (const queryField of queryFields.values()) { | ||
const outputType = this.getOutputType(ctx, def, queryField); | ||
const args = this.getInputs(ctx, def, { | ||
fieldName: queryField.fieldName, | ||
typeName: queryField.typeName, | ||
type: queryField.type, | ||
}); | ||
const getField = graphql_transformer_common_1.makeField(queryField.fieldName, args, graphql_transformer_common_1.makeNamedType(outputType.name.value)); | ||
ctx.output.addQueryFields([getField]); | ||
} | ||
const mutationFields = this.getMutationFieldNames(ctx, def); | ||
for (const mutationField of mutationFields) { | ||
const args = this.getInputs(ctx, def, { | ||
fieldName: mutationField.fieldName, | ||
typeName: mutationField.typeName, | ||
type: mutationField.type, | ||
}); | ||
const field = graphql_transformer_common_1.makeField(mutationField.fieldName, args, graphql_transformer_common_1.makeNamedType(def.name.value)); | ||
ctx.output.addMutationFields([field]); | ||
} | ||
const queryFields = this.createQueryFields(ctx, def); | ||
ctx.output.addQueryFields(queryFields); | ||
const mutationFields = this.createMutationFields(ctx, def); | ||
ctx.output.addMutationFields(mutationFields); | ||
const subscriptionsFields = this.createSubscriptionFields(ctx, def); | ||
@@ -385,2 +369,29 @@ ctx.output.addSubscriptionFields(subscriptionsFields); | ||
}; | ||
this.createQueryFields = (ctx, def) => { | ||
const queryFields = []; | ||
const queryFieldNames = this.getQueryFieldNames(ctx, def); | ||
for (const queryField of queryFieldNames.values()) { | ||
const outputType = this.getOutputType(ctx, def, queryField); | ||
const args = this.getInputs(ctx, def, { | ||
fieldName: queryField.fieldName, | ||
typeName: queryField.typeName, | ||
type: queryField.type, | ||
}); | ||
queryFields.push(graphql_transformer_common_1.makeField(queryField.fieldName, args, graphql_transformer_common_1.makeNamedType(outputType.name.value))); | ||
} | ||
return queryFields; | ||
}; | ||
this.createMutationFields = (ctx, def) => { | ||
const mutationFields = []; | ||
const mutationFieldNames = this.getMutationFieldNames(ctx, def); | ||
for (const mutationField of mutationFieldNames) { | ||
const args = this.getInputs(ctx, def, { | ||
fieldName: mutationField.fieldName, | ||
typeName: mutationField.typeName, | ||
type: mutationField.type, | ||
}); | ||
mutationFields.push(graphql_transformer_common_1.makeField(mutationField.fieldName, args, graphql_transformer_common_1.makeNamedType(def.name.value))); | ||
} | ||
return mutationFields; | ||
}; | ||
this.createSubscriptionFields = (ctx, def) => { | ||
@@ -476,4 +487,5 @@ const subscriptionToMutationsMap = this.getSubscriptionToMutationsReverseMap(ctx, def); | ||
const filterInputName = graphql_transformer_common_1.toPascalCase(['Model', type.name.value, 'FilterInput']); | ||
const filterInputs = graphql_types_1.makeListQueryFilterInput(ctx, filterInputName, type); | ||
for (let input of [filterInputs]) { | ||
const filterInputs = graphql_types_1.createEnumModelFilters(ctx, type); | ||
filterInputs.push(graphql_types_1.makeListQueryFilterInput(ctx, filterInputName, type)); | ||
for (let input of filterInputs) { | ||
const conditionInputName = input.name.value; | ||
@@ -623,4 +635,10 @@ if (!ctx.output.getType(conditionInputName)) { | ||
} | ||
ensureModelSortDirectionEnum(ctx) { | ||
if (!ctx.output.hasType('ModelSortDirection')) { | ||
const modelSortDirection = graphql_types_1.makeModelSortDirectionEnumObject(); | ||
ctx.output.addEnum(modelSortDirection); | ||
} | ||
} | ||
} | ||
exports.ModelTransformer = ModelTransformer; | ||
//# sourceMappingURL=graphql-model-transformer.js.map |
import { TransformerTransformSchemaStepContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; | ||
import { EnumTypeDefinitionNode, FieldDefinitionNode, InputObjectTypeDefinitionNode, ObjectTypeDefinitionNode } from 'graphql'; | ||
import { InputObjectDefinitionWrapper } from '../wrappers/object-definition-wrapper'; | ||
import { FieldWrapper, InputObjectDefinitionWrapper } from '../wrappers/object-definition-wrapper'; | ||
export declare const makeConditionFilterInput: (ctx: TransformerTransformSchemaStepContextProvider, name: string, object: ObjectTypeDefinitionNode) => InputObjectDefinitionWrapper; | ||
@@ -12,4 +12,4 @@ export declare const addModelConditionInputs: (ctx: TransformerTransformSchemaStepContextProvider) => void; | ||
export declare function makeSizeInputType(): InputObjectTypeDefinitionNode; | ||
export declare function makeEnumFilterInput(name: string): InputObjectTypeDefinitionNode; | ||
export declare function makeEnumFilterInput(fieldWrapper: FieldWrapper): InputObjectTypeDefinitionNode; | ||
export declare function makeModelSortDirectionEnumObject(): EnumTypeDefinitionNode; | ||
//# sourceMappingURL=common.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.makeModelSortDirectionEnumObject = exports.makeEnumFilterInput = exports.makeSizeInputType = exports.makeSubscriptionField = exports.makeAttributeTypeEnum = exports.makeModelScalarFilterInputObject = exports.createEnumModelFilters = exports.generateModelScalarFilterInputName = exports.addModelConditionInputs = exports.makeConditionFilterInput = void 0; | ||
const graphql_1 = require("graphql"); | ||
const graphql_transformer_common_1 = require("graphql-transformer-common"); | ||
@@ -8,2 +9,3 @@ const definitions_1 = require("../definitions"); | ||
const makeConditionFilterInput = (ctx, name, object) => { | ||
const supportsConditions = true; | ||
const input = object_definition_wrapper_1.InputObjectDefinitionWrapper.create(name); | ||
@@ -13,14 +15,10 @@ const wrappedObject = new object_definition_wrapper_1.ObjectDefinitionWrapper(object); | ||
const fieldType = ctx.output.getType(field.getTypeName()); | ||
const isEnumType = fieldType && fieldType.kind === 'EnumTypeDefinition'; | ||
if (field.isScalar() || field.isList()) { | ||
const conditionTypeName = field.isList() | ||
? graphql_transformer_common_1.ModelResourceIDs.ModelFilterListInputTypeName(field.getTypeName(), true) | ||
: graphql_transformer_common_1.ModelResourceIDs.ModelFilterScalarInputTypeName(field.getTypeName(), true); | ||
const inputField = object_definition_wrapper_1.InputFieldWrapper.create(field.name, conditionTypeName, true, field.isList()); | ||
const isEnumType = fieldType && fieldType.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION; | ||
if (field.isScalar() || isEnumType) { | ||
const conditionTypeName = isEnumType && field.isList() | ||
? graphql_transformer_common_1.ModelResourceIDs.ModelFilterListInputTypeName(field.getTypeName(), !supportsConditions) | ||
: graphql_transformer_common_1.ModelResourceIDs.ModelFilterScalarInputTypeName(field.getTypeName(), !supportsConditions); | ||
const inputField = object_definition_wrapper_1.InputFieldWrapper.create(field.name, conditionTypeName, true); | ||
input.addField(inputField); | ||
} | ||
else if (isEnumType) { | ||
const inputField = object_definition_wrapper_1.InputFieldWrapper.create(field.name, field.getTypeName(), true, field.isList()); | ||
input.addField(inputField); | ||
} | ||
} | ||
@@ -39,3 +37,3 @@ for (let additionalField of ['and', 'or']) { | ||
const addModelConditionInputs = (ctx) => { | ||
const conditionsInput = ['String', 'Int', 'Float', 'Boolean', 'ID'].map(scalarName => makeModelScalarFilterInputObject(scalarName, false)); | ||
const conditionsInput = ['String', 'Int', 'Float', 'Boolean', 'ID'].map(scalarName => makeModelScalarFilterInputObject(scalarName, true)); | ||
conditionsInput.push(makeAttributeTypeEnum()); | ||
@@ -66,3 +64,3 @@ conditionsInput.push(makeSizeInputType()); | ||
}); | ||
return enumFields.map(field => makeEnumFilterInput(field.getTypeName())); | ||
return enumFields.map(field => makeEnumFilterInput(field)); | ||
}; | ||
@@ -162,9 +160,18 @@ exports.createEnumModelFilters = createEnumModelFilters; | ||
exports.makeSizeInputType = makeSizeInputType; | ||
function makeEnumFilterInput(name) { | ||
const inputName = graphql_transformer_common_1.toPascalCase(['Model', name, 'Input']); | ||
const input = object_definition_wrapper_1.InputObjectDefinitionWrapper.create(inputName); | ||
function makeEnumFilterInput(fieldWrapper) { | ||
const supportsConditions = true; | ||
const conditionTypeName = fieldWrapper.isList() | ||
? graphql_transformer_common_1.ModelResourceIDs.ModelFilterListInputTypeName(fieldWrapper.getTypeName(), !supportsConditions) | ||
: graphql_transformer_common_1.ModelResourceIDs.ModelFilterScalarInputTypeName(fieldWrapper.getTypeName(), !supportsConditions); | ||
const input = object_definition_wrapper_1.InputObjectDefinitionWrapper.create(conditionTypeName); | ||
['eq', 'ne'].forEach(fieldName => { | ||
const field = object_definition_wrapper_1.InputFieldWrapper.create(fieldName, name, true); | ||
const field = object_definition_wrapper_1.InputFieldWrapper.create(fieldName, fieldWrapper.getTypeName(), true, fieldWrapper.isList()); | ||
input.addField(field); | ||
}); | ||
if (fieldWrapper.isList()) { | ||
['contains', 'notContains'].forEach(fieldName => { | ||
const field = object_definition_wrapper_1.InputFieldWrapper.create(fieldName, fieldWrapper.getTypeName(), true); | ||
input.addField(field); | ||
}); | ||
} | ||
return input.serialize(); | ||
@@ -171,0 +178,0 @@ } |
import { TransformerTransformSchemaStepContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; | ||
import { ObjectTypeDefinitionNode, InputObjectTypeDefinitionNode, DocumentNode } from 'graphql'; | ||
import { DocumentNode, InputObjectTypeDefinitionNode, ObjectTypeDefinitionNode } from 'graphql'; | ||
import { ModelDirectiveConfiguration } from '../graphql-model-transformer'; | ||
@@ -4,0 +4,0 @@ export declare const makeUpdateInputField: (obj: ObjectTypeDefinitionNode, modelDirectiveConfig: ModelDirectiveConfiguration, knownModelTypes: Set<string>, document: DocumentNode) => InputObjectTypeDefinitionNode; |
@@ -21,3 +21,3 @@ "use strict"; | ||
.map(field => { | ||
return field.getTypeName(); | ||
return field.name; | ||
}); | ||
@@ -72,3 +72,3 @@ const objectTypeDefinition = { | ||
.map(field => { | ||
return field.getTypeName(); | ||
return field.name; | ||
}); | ||
@@ -102,3 +102,3 @@ const objectTypeDefinition = { | ||
const input = common_1.makeConditionFilterInput(ctx, name, object); | ||
const idField = input.fields.find(f => f.name === 'id' && f.getTypeName() === 'ID'); | ||
const idField = input.fields.find(f => f.name === 'id' && f.getTypeName() === 'ModelIDInput'); | ||
if (idField) { | ||
@@ -105,0 +105,0 @@ input.removeField(idField); |
@@ -28,2 +28,3 @@ import { ArgumentNode, DirectiveNode, DocumentNode, EnumTypeDefinitionNode, FieldDefinitionNode, InputObjectTypeDefinitionNode, InputValueDefinitionNode, Location, NamedTypeNode, NameNode, ObjectTypeDefinitionNode, StringValueNode, TypeNode, ValueNode } from 'graphql'; | ||
unWrapListType: () => boolean; | ||
private isListType; | ||
getBaseType: () => NamedTypeNode; | ||
@@ -30,0 +31,0 @@ getTypeName: () => string; |
@@ -46,3 +46,3 @@ "use strict"; | ||
this.isList = () => { | ||
return graphql_1.isListType(this.type); | ||
return this.isListType(this.type); | ||
}; | ||
@@ -82,2 +82,10 @@ this.isNonNullable = () => { | ||
}; | ||
this.isListType = (type) => { | ||
if (type.kind === graphql_1.Kind.NON_NULL_TYPE) { | ||
return graphql_1.isListType(type.type); | ||
} | ||
else { | ||
return type.kind === graphql_1.Kind.LIST_TYPE; | ||
} | ||
}; | ||
this.getBaseType = () => { | ||
@@ -298,3 +306,3 @@ let node = this.type; | ||
this.removeField = (field) => { | ||
if (this.hasField(field.name)) { | ||
if (!this.hasField(field.name)) { | ||
throw new Error(`type ${this.name} does not have the field with name ${field.name}`); | ||
@@ -301,0 +309,0 @@ } |
{ | ||
"name": "@aws-amplify/graphql-model-transformer", | ||
"version": "0.6.0", | ||
"version": "0.6.1-beta.0", | ||
"description": "Amplify graphql @model transformer", | ||
@@ -31,4 +31,4 @@ "repository": { | ||
"dependencies": { | ||
"@aws-amplify/graphql-transformer-core": "0.8.2", | ||
"@aws-amplify/graphql-transformer-interfaces": "1.8.2", | ||
"@aws-amplify/graphql-transformer-core": "0.9.0-beta.0", | ||
"@aws-amplify/graphql-transformer-interfaces": "1.9.0-beta.0", | ||
"@aws-cdk/assets": "~1.119.0", | ||
@@ -61,3 +61,3 @@ "@aws-cdk/aws-applicationautoscaling": "~1.119.0", | ||
"graphql-mapping-template": "4.18.3", | ||
"graphql-transformer-common": "4.19.8", | ||
"graphql-transformer-common": "4.19.9-beta.0", | ||
"lodash": "^4.17.21" | ||
@@ -85,3 +85,3 @@ }, | ||
}, | ||
"gitHead": "5d7ddc369ad90c4d155e808ccd95b71922ee269a" | ||
"gitHead": "120d47266005cf8595781bb738ee36848689c2ee" | ||
} |
@@ -474,11 +474,11 @@ import { ModelTransformer } from '@aws-amplify/graphql-model-transformer'; | ||
const stringInputType = getInputType(parsed, 'ModelStringFilterInput'); | ||
const stringInputType = getInputType(parsed, 'ModelStringInput'); | ||
expect(stringInputType).toBeDefined(); | ||
const booleanInputType = getInputType(parsed, 'ModelBooleanFilterInput'); | ||
const booleanInputType = getInputType(parsed, 'ModelBooleanInput'); | ||
expect(booleanInputType).toBeDefined(); | ||
const intInputType = getInputType(parsed, 'ModelIntFilterInput'); | ||
const intInputType = getInputType(parsed, 'ModelIntInput'); | ||
expect(intInputType).toBeDefined(); | ||
const floatInputType = getInputType(parsed, 'ModelFloatFilterInput'); | ||
const floatInputType = getInputType(parsed, 'ModelFloatInput'); | ||
expect(floatInputType).toBeDefined(); | ||
const idInputType = getInputType(parsed, 'ModelIDFilterInput'); | ||
const idInputType = getInputType(parsed, 'ModelIDInput'); | ||
expect(idInputType).toBeDefined(); | ||
@@ -490,7 +490,7 @@ const postInputType = getInputType(parsed, 'ModelPostFilterInput'); | ||
expect(verifyInputCount(parsed, 'ModelStringFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelBooleanFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIntFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelFloatFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIDFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelStringInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelBooleanInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIntInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelFloatInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIDInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelPostFilterInput', 1)).toBeTruthy(); | ||
@@ -560,3 +560,2 @@ expect(verifyInputCount(parsed, 'ModelUserFilterInput', 1)).toBeTruthy(); | ||
const parsed = parse(definition); | ||
validateModelSchema(parsed); | ||
@@ -612,7 +611,7 @@ | ||
expect(verifyInputCount(parsed, 'ModelStringFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelBooleanFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIntFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelFloatFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIDFilterInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelStringInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelBooleanInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIntInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelFloatInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelIDInput', 1)).toBeTruthy(); | ||
expect(verifyInputCount(parsed, 'ModelPostFilterInput', 1)).toBeTruthy(); | ||
@@ -657,2 +656,232 @@ }); | ||
}); | ||
it('should not generate superfluous input and filter types', () => { | ||
const validSchema = ` | ||
type Entity @model(mutations: null, subscriptions: null, queries: {get: "getEntity"}) { | ||
id: ID! | ||
str: String | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
expect(result.schema).toMatchSnapshot(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
}); | ||
it('should support timestamp parameters when generating pipelineFunctions and output schema', () => { | ||
const validSchema = ` | ||
type Post @model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn"}) { | ||
id: ID! | ||
str: String | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
expect(result.schema).toMatchSnapshot(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
expect(result.pipelineFunctions['Mutation.createPost.req.vtl']).toMatchSnapshot(); | ||
expect(result.pipelineFunctions['Mutation.updatePost.req.vtl']).toMatchSnapshot(); | ||
}); | ||
it('should not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime', () => { | ||
const validSchema = ` | ||
type Post @model { | ||
id: ID! | ||
str: String | ||
createdAt: AWSTimestamp | ||
updatedAt: AWSTimestamp | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
expect(result.schema).toMatchSnapshot(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
expect(result.pipelineFunctions['Mutation.createPost.req.vtl']).toMatchSnapshot(); | ||
expect(result.pipelineFunctions['Mutation.updatePost.req.vtl']).toMatchSnapshot(); | ||
}); | ||
it('should have timestamps as nullable fields when the type makes it non-nullable', () => { | ||
const validSchema = ` | ||
type Post @model { | ||
id: ID! | ||
str: String | ||
createdAt: AWSDateTime! | ||
updatedAt: AWSDateTime! | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
expect(result.schema).toMatchSnapshot(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
expect(result.pipelineFunctions['Mutation.createPost.req.vtl']).toMatchSnapshot(); | ||
expect(result.pipelineFunctions['Mutation.updatePost.req.vtl']).toMatchSnapshot(); | ||
}); | ||
it('should not to include createdAt and updatedAt field when timestamps is set to null', () => { | ||
const validSchema = ` | ||
type Post @model(timestamps: null) { | ||
id: ID! | ||
str: String | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
expect(result.schema).toMatchSnapshot(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
expect(result.pipelineFunctions['Mutation.createPost.req.vtl']).toMatchSnapshot(); | ||
expect(result.pipelineFunctions['Mutation.updatePost.req.vtl']).toMatchSnapshot(); | ||
}); | ||
it('should filter known input types from create and update input fields', () => { | ||
const validSchema = ` | ||
type Test @model { | ||
id: ID! | ||
email: Email | ||
} | ||
type Email @model { | ||
id: ID! | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
expect(result.schema).toMatchSnapshot(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
const createTestInput = getInputType(schema, 'CreateTestInput'); | ||
expect(getFieldOnInputType(createTestInput!, 'email')).toBeUndefined(); | ||
const updateTestInput = getInputType(schema, 'UpdateTestInput'); | ||
expect(getFieldOnInputType(updateTestInput!, 'email')).toBeUndefined(); | ||
}); | ||
it('should generate enum input objects', () => { | ||
const validSchema = /* GraphQL */ ` | ||
type Post @model { | ||
id: ID! | ||
title: String! | ||
createdAt: AWSDateTime | ||
updatedAt: AWSDateTime | ||
metadata: PostMetadata | ||
entityMetadata: EntityMetadata | ||
appearsIn: [Episode!] | ||
episode: Episode | ||
} | ||
type Author @model { | ||
id: ID! | ||
name: String! | ||
postMetadata: PostMetadata | ||
entityMetadata: EntityMetadata | ||
} | ||
type EntityMetadata { | ||
isActive: Boolean | ||
} | ||
type PostMetadata { | ||
tags: Tag | ||
} | ||
type Tag { | ||
published: Boolean | ||
metadata: PostMetadata | ||
} | ||
enum Episode { | ||
NEWHOPE | ||
EMPIRE | ||
JEDI | ||
} | ||
type Require @model { | ||
id: ID! | ||
requiredField: String! | ||
notRequiredField: String | ||
} | ||
type Comment @model(timestamps: { createdAt: "createdOn", updatedAt: "updatedOn" }) { | ||
id: ID! | ||
title: String! | ||
content: String | ||
updatedOn: Int # No automatic generation of timestamp if its not AWSDateTime | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const result = transformer.transform(validSchema); | ||
expect(result).toBeDefined(); | ||
expect(result.schema).toBeDefined(); | ||
const schema = parse(result.schema); | ||
validateModelSchema(schema); | ||
expect(result.schema).toMatchSnapshot(); | ||
expect(verifyInputCount(schema, 'ModelEpisodeInput', 1)).toBeTruthy(); | ||
}); | ||
it('should support support scalar list', () => { | ||
const validSchema = /* GraphQL */ ` | ||
type Post @model { | ||
id: ID! | ||
author: String! | ||
title: String | ||
content: String | ||
url: String | ||
ups: Int | ||
downs: Int | ||
version: Int | ||
postedAt: String | ||
createdAt: AWSDateTime | ||
comments: [String!] | ||
ratings: [Int!] | ||
percentageUp: Float | ||
isPublished: Boolean | ||
jsonField: AWSJSON | ||
} | ||
`; | ||
const transformer = new GraphQLTransform({ | ||
transformers: [new ModelTransformer()], | ||
featureFlags, | ||
}); | ||
const out = transformer.transform(validSchema); | ||
expect(out).toBeDefined(); | ||
validateModelSchema(parse(out.schema)); | ||
}); | ||
}); |
@@ -48,2 +48,3 @@ import { InvalidDirectiveError, MappingTemplate, TransformerModelBase } from '@aws-amplify/graphql-transformer-core'; | ||
makeListQueryModel, | ||
makeModelSortDirectionEnumObject, | ||
makeMutationConditionInput, | ||
@@ -196,7 +197,6 @@ makeUpdateInputField, | ||
transformSchema = (ctx: TransformerTransformSchemaStepContextProvider): void => { | ||
// Create Non Model input types | ||
// add the model input conditions | ||
addModelConditionInputs(ctx); | ||
this.ensureModelSortDirectionEnum(ctx); | ||
for (const type of this.typesWithModelDirective) { | ||
@@ -206,25 +206,8 @@ const def = ctx.output.getObject(type)!; | ||
this.createNonModelInputs(ctx, def); | ||
const queryFields = this.getQueryFieldNames(ctx, def!); | ||
for (const queryField of queryFields.values()) { | ||
const outputType = this.getOutputType(ctx, def, queryField); | ||
const args = this.getInputs(ctx, def!, { | ||
fieldName: queryField.fieldName, | ||
typeName: queryField.typeName, | ||
type: queryField.type, | ||
}); | ||
const getField = makeField(queryField.fieldName, args, makeNamedType(outputType.name.value)); | ||
ctx.output.addQueryFields([getField]); | ||
} | ||
const mutationFields = this.getMutationFieldNames(ctx, def!); | ||
for (const mutationField of mutationFields) { | ||
const args = this.getInputs(ctx, def!, { | ||
fieldName: mutationField.fieldName, | ||
typeName: mutationField.typeName, | ||
type: mutationField.type, | ||
}); | ||
const queryFields = this.createQueryFields(ctx, def); | ||
ctx.output.addQueryFields(queryFields); | ||
const field = makeField(mutationField.fieldName, args, makeNamedType(def!.name.value)); | ||
ctx.output.addMutationFields([field]); | ||
} | ||
const mutationFields = this.createMutationFields(ctx, def); | ||
ctx.output.addMutationFields(mutationFields); | ||
@@ -625,3 +608,37 @@ const subscriptionsFields = this.createSubscriptionFields(ctx, def!); | ||
createSubscriptionFields = (ctx: TransformerTransformSchemaStepContextProvider, def: ObjectTypeDefinitionNode): FieldDefinitionNode[] => { | ||
private createQueryFields = (ctx: TransformerValidationStepContextProvider, def: ObjectTypeDefinitionNode): FieldDefinitionNode[] => { | ||
const queryFields: FieldDefinitionNode[] = []; | ||
const queryFieldNames = this.getQueryFieldNames(ctx, def!); | ||
for (const queryField of queryFieldNames.values()) { | ||
const outputType = this.getOutputType(ctx, def, queryField); | ||
const args = this.getInputs(ctx, def!, { | ||
fieldName: queryField.fieldName, | ||
typeName: queryField.typeName, | ||
type: queryField.type, | ||
}); | ||
queryFields.push(makeField(queryField.fieldName, args, makeNamedType(outputType.name.value))); | ||
} | ||
return queryFields; | ||
}; | ||
private createMutationFields = (ctx: TransformerValidationStepContextProvider, def: ObjectTypeDefinitionNode): FieldDefinitionNode[] => { | ||
const mutationFields: FieldDefinitionNode[] = []; | ||
const mutationFieldNames = this.getMutationFieldNames(ctx, def!); | ||
for (const mutationField of mutationFieldNames) { | ||
const args = this.getInputs(ctx, def!, { | ||
fieldName: mutationField.fieldName, | ||
typeName: mutationField.typeName, | ||
type: mutationField.type, | ||
}); | ||
mutationFields.push(makeField(mutationField.fieldName, args, makeNamedType(def!.name.value))); | ||
} | ||
return mutationFields; | ||
}; | ||
private createSubscriptionFields = ( | ||
ctx: TransformerTransformSchemaStepContextProvider, | ||
def: ObjectTypeDefinitionNode, | ||
): FieldDefinitionNode[] => { | ||
const subscriptionToMutationsMap = this.getSubscriptionToMutationsReverseMap(ctx, def); | ||
@@ -773,4 +790,5 @@ const mutationFields = this.getMutationFieldNames(ctx, def!); | ||
const filterInputName = toPascalCase(['Model', type.name.value, 'FilterInput']); | ||
const filterInputs = makeListQueryFilterInput(ctx, filterInputName, type); | ||
for (let input of [filterInputs]) { | ||
const filterInputs = createEnumModelFilters(ctx, type); | ||
filterInputs.push(makeListQueryFilterInput(ctx, filterInputName, type)); | ||
for (let input of filterInputs) { | ||
const conditionInputName = input.name.value; | ||
@@ -781,2 +799,3 @@ if (!ctx.output.getType(conditionInputName)) { | ||
} | ||
return [ | ||
@@ -960,2 +979,10 @@ makeInputValueDefinition('filter', makeNamedType(filterInputName)), | ||
}; | ||
private ensureModelSortDirectionEnum(ctx: TransformerValidationStepContextProvider): void { | ||
if (!ctx.output.hasType('ModelSortDirection')) { | ||
const modelSortDirection = makeModelSortDirectionEnumObject(); | ||
ctx.output.addEnum(modelSortDirection); | ||
} | ||
} | ||
} |
@@ -6,2 +6,3 @@ import { TransformerTransformSchemaStepContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; | ||
InputObjectTypeDefinitionNode, | ||
Kind, | ||
ObjectTypeDefinitionNode, | ||
@@ -18,3 +19,2 @@ TypeDefinitionNode, | ||
ModelResourceIDs, | ||
toPascalCase, | ||
} from 'graphql-transformer-common'; | ||
@@ -37,2 +37,3 @@ import { | ||
EnumWrapper, | ||
FieldWrapper, | ||
InputFieldWrapper, | ||
@@ -47,3 +48,3 @@ InputObjectDefinitionWrapper, | ||
* @param name model name | ||
* @param object ModelObjectDefination | ||
* @param object ModelObjectDefinition | ||
*/ | ||
@@ -55,2 +56,3 @@ export const makeConditionFilterInput = ( | ||
): InputObjectDefinitionWrapper => { | ||
const supportsConditions = true; | ||
const input = InputObjectDefinitionWrapper.create(name); | ||
@@ -60,12 +62,10 @@ const wrappedObject = new ObjectDefinitionWrapper(object); | ||
const fieldType = ctx.output.getType(field.getTypeName()); | ||
const isEnumType = fieldType && fieldType.kind === 'EnumTypeDefinition'; | ||
if (field.isScalar() || field.isList()) { | ||
const conditionTypeName = field.isList() | ||
? ModelResourceIDs.ModelFilterListInputTypeName(field.getTypeName(), true) | ||
: ModelResourceIDs.ModelFilterScalarInputTypeName(field.getTypeName(), true); | ||
const inputField = InputFieldWrapper.create(field.name, conditionTypeName, true, field.isList()); | ||
const isEnumType = fieldType && fieldType.kind === Kind.ENUM_TYPE_DEFINITION; | ||
if (field.isScalar() || isEnumType) { | ||
const conditionTypeName = | ||
isEnumType && field.isList() | ||
? ModelResourceIDs.ModelFilterListInputTypeName(field.getTypeName(), !supportsConditions) | ||
: ModelResourceIDs.ModelFilterScalarInputTypeName(field.getTypeName(), !supportsConditions); | ||
const inputField = InputFieldWrapper.create(field.name, conditionTypeName, true); | ||
input.addField(inputField); | ||
} else if (isEnumType) { | ||
const inputField = InputFieldWrapper.create(field.name, field.getTypeName(), true, field.isList()); | ||
input.addField(inputField); | ||
} | ||
@@ -89,3 +89,3 @@ } | ||
const conditionsInput: TypeDefinitionNode[] = ['String', 'Int', 'Float', 'Boolean', 'ID'].map(scalarName => | ||
makeModelScalarFilterInputObject(scalarName, false), | ||
makeModelScalarFilterInputObject(scalarName, true), | ||
); | ||
@@ -126,3 +126,4 @@ conditionsInput.push(makeAttributeTypeEnum()); | ||
}); | ||
return enumFields.map(field => makeEnumFilterInput(field.getTypeName())); | ||
return enumFields.map(field => makeEnumFilterInput(field)); | ||
}; | ||
@@ -234,9 +235,20 @@ | ||
export function makeEnumFilterInput(name: string): InputObjectTypeDefinitionNode { | ||
const inputName = toPascalCase(['Model', name, 'Input']); | ||
const input = InputObjectDefinitionWrapper.create(inputName); | ||
export function makeEnumFilterInput(fieldWrapper: FieldWrapper): InputObjectTypeDefinitionNode { | ||
const supportsConditions = true; | ||
const conditionTypeName = fieldWrapper.isList() | ||
? ModelResourceIDs.ModelFilterListInputTypeName(fieldWrapper.getTypeName(), !supportsConditions) | ||
: ModelResourceIDs.ModelFilterScalarInputTypeName(fieldWrapper.getTypeName(), !supportsConditions); | ||
const input = InputObjectDefinitionWrapper.create(conditionTypeName); | ||
['eq', 'ne'].forEach(fieldName => { | ||
const field = InputFieldWrapper.create(fieldName, name, true); | ||
const field = InputFieldWrapper.create(fieldName, fieldWrapper.getTypeName(), true, fieldWrapper.isList()); | ||
input.addField(field); | ||
}); | ||
if (fieldWrapper.isList()) { | ||
['contains', 'notContains'].forEach(fieldName => { | ||
const field = InputFieldWrapper.create(fieldName, fieldWrapper.getTypeName(), true); | ||
input.addField(field); | ||
}); | ||
} | ||
return input.serialize(); | ||
@@ -243,0 +255,0 @@ } |
import { TransformerTransformSchemaStepContextProvider } from '@aws-amplify/graphql-transformer-interfaces'; | ||
import { ObjectTypeDefinitionNode, InputObjectTypeDefinitionNode, DocumentNode } from 'graphql'; | ||
import { DocumentNode, InputObjectTypeDefinitionNode, ObjectTypeDefinitionNode } from 'graphql'; | ||
import { ModelResourceIDs, toPascalCase } from 'graphql-transformer-common'; | ||
import { ModelDirectiveConfiguration } from '../graphql-model-transformer'; | ||
import { ObjectDefinitionWrapper, InputObjectDefinitionWrapper, InputFieldWrapper } from '../wrappers/object-definition-wrapper'; | ||
import { InputFieldWrapper, InputObjectDefinitionWrapper, ObjectDefinitionWrapper } from '../wrappers/object-definition-wrapper'; | ||
import { makeConditionFilterInput } from './common'; | ||
@@ -33,3 +33,3 @@ | ||
.map(field => { | ||
return field.getTypeName(); | ||
return field.name; | ||
}); | ||
@@ -107,3 +107,3 @@ | ||
.map(field => { | ||
return field.getTypeName(); | ||
return field.name; | ||
}); | ||
@@ -145,3 +145,3 @@ | ||
const input = makeConditionFilterInput(ctx, name, object); | ||
const idField = input.fields.find(f => f.name === 'id' && f.getTypeName() === 'ID'); | ||
const idField = input.fields.find(f => f.name === 'id' && f.getTypeName() === 'ModelIDInput'); | ||
if (idField) { | ||
@@ -148,0 +148,0 @@ input.removeField(idField); |
@@ -91,3 +91,3 @@ import { | ||
isList = (): boolean => { | ||
return isListType(this.type); | ||
return this.isListType(this.type); | ||
}; | ||
@@ -132,2 +132,11 @@ | ||
}; | ||
private isListType = (type: TypeNode): boolean => { | ||
if (type.kind === Kind.NON_NULL_TYPE) { | ||
return isListType(type.type); | ||
} else { | ||
return type.kind === Kind.LIST_TYPE; | ||
} | ||
}; | ||
public getBaseType = (): NamedTypeNode => { | ||
@@ -399,3 +408,3 @@ let node = this.type; | ||
removeField = (field: InputFieldWrapper): void => { | ||
if (this.hasField(field.name)) { | ||
if (!this.hasField(field.name)) { | ||
throw new Error(`type ${this.name} does not have the field with name ${field.name}`); | ||
@@ -402,0 +411,0 @@ } |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
561989
5319
+ Added@aws-amplify/graphql-transformer-core@0.9.0-beta.0(transitive)
+ Added@aws-amplify/graphql-transformer-interfaces@1.9.0-beta.0(transitive)
+ Addedgraphql-transformer-common@4.19.9-beta.0(transitive)
- Removed@aws-amplify/graphql-transformer-core@0.8.2(transitive)
- Removed@aws-amplify/graphql-transformer-interfaces@1.8.2(transitive)
- Removedgraphql-transformer-common@4.19.8(transitive)
Updated@aws-amplify/graphql-transformer-interfaces@1.9.0-beta.0