diff --git a/packages/amplify-graphql-index-transformer/src/schema.ts b/packages/amplify-graphql-index-transformer/src/schema.ts index 5af9e0005bf..97290f5522c 100644 --- a/packages/amplify-graphql-index-transformer/src/schema.ts +++ b/packages/amplify-graphql-index-transformer/src/schema.ts @@ -378,6 +378,7 @@ function generateFilterInputs(config: IndexDirectiveConfiguration, ctx: Transfor } function makeModelXFilterInputObject(config: IndexDirectiveConfiguration, ctx: TransformerContextProvider): InputObjectTypeDefinitionNode { + const supportsConditions = true; const { object } = config; const name = ModelResourceIDs.ModelFilterInputTypeName(object.name.value); const fields = object @@ -393,8 +394,8 @@ function makeModelXFilterInputObject(config: IndexDirectiveConfiguration, ctx: T if (isScalar(field.type) || isList) { filterTypeName = isList - ? ModelResourceIDs.ModelFilterListInputTypeName(baseType, true) - : ModelResourceIDs.ModelScalarFilterInputTypeName(baseType, true); + ? ModelResourceIDs.ModelFilterListInputTypeName(baseType, !supportsConditions) + : ModelResourceIDs.ModelScalarFilterInputTypeName(baseType, !supportsConditions); } return { diff --git a/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap b/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap index eb3b019d121..5e0048c7be3 100644 --- a/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap +++ b/packages/amplify-graphql-model-transformer/src/__tests__/__snapshots__/model-transformer.test.ts.snap @@ -1,5 +1,387 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`ModelTransformer: should have timestamps as nullable fields when the type makes it non-nullable 1`] = ` +" +type Post { + id: ID! + str: String + createdAt: AWSDateTime! + updatedAt: AWSDateTime! +} + +input ModelStringInput { + ne: String + eq: String + le: String + lt: String + ge: String + gt: String + contains: String + notContains: String + between: [String] + beginsWith: String + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +input ModelIntInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelFloatInput { + ne: Float + eq: Float + le: Float + lt: Float + ge: Float + gt: Float + between: [Float] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelBooleanInput { + ne: Boolean + eq: Boolean + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelIDInput { + ne: ID + eq: ID + le: ID + lt: ID + ge: ID + gt: ID + contains: ID + notContains: ID + between: [ID] + beginsWith: ID + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +enum ModelAttributeTypes { + binary + binarySet + bool + list + map + number + numberSet + string + stringSet + _null +} + +input ModelSizeInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] +} + +enum ModelSortDirection { + ASC + DESC +} + +type Query { + getPost(id: ID!): Post + listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection +} + +type ModelPostConnection { + items: [Post] + nextToken: String +} + +input ModelPostFilterInput { + id: ModelIDInput + str: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput + and: [ModelPostFilterInput] + or: [ModelPostFilterInput] + not: ModelPostFilterInput +} + +input ModelPostConditionInput { + id: ModelIDInput + str: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput + and: [ModelPostConditionInput] + or: [ModelPostConditionInput] + not: ModelPostConditionInput +} + +input CreatePostInput { + id: ID + str: String + createdAt: AWSDateTime + updatedAt: AWSDateTime +} + +type Mutation { + createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post + updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post + deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post +} + +input UpdatePostInput { + id: ID! + str: String + createdAt: AWSDateTime + updatedAt: AWSDateTime +} + +input DeletePostInput { + id: ID! +} + +type Subscription { + onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) + onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) + onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) +} + +" +`; + +exports[`ModelTransformer: should have timestamps as nullable fields when the type makes it non-nullable 2`] = ` +"## [Start] Create Request template. ** +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +$util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) +#set( $PutObject = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"PutItem\\", + \\"attributeValues\\": $util.dynamodb.toMapValues($mergedValues), + \\"condition\\": $condition +} ) +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($PutObject.put(\\"condition\\", $Conditions)) +#end +#if( $ctx.stash.metadata.modelObjectKey ) + $util.qr($PutObject.put(\\"key\\", $ctx.stash.metadata.modelObjectKey)) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($mergedValues.id) +} ) + $util.qr($PutObject.put(\\"key\\", $Key)) +#end +$util.toJson($PutObject) +## [End] Create Request template. **" +`; + +exports[`ModelTransformer: should have timestamps as nullable fields when the type makes it non-nullable 3`] = ` +"## [Start] Mutation Update resolver. ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +## Initialize the vars for creating ddb expression ** +#set( $expNames = {} ) +#set( $expValues = {} ) +#set( $expSet = {} ) +#set( $expAdd = {} ) +#set( $expRemove = [] ) +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $Key = $ctx.stash.metadata.modelObjectKey ) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.input.id) +} ) +#end +## Model key ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyFields = [] ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyFields.add(\\"$entry.key\\")) + #end +#else + #set( $keyFields = [\\"id\\"] ) +#end +#foreach( $entry in $util.map.copyAndRemoveAllKeys($mergedValues, $keyFields).entrySet() ) + #if( !$util.isNull($ctx.stash.metadata.dynamodbNameOverrideMap) && $ctx.stash.metadata.dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) + #set( $entryKeyAttributeName = $ctx.stash.metadata.dynamodbNameOverrideMap.get(\\"$entry.key\\") ) + #else + #set( $entryKeyAttributeName = $entry.key ) + #end + #if( $util.isNull($entry.value) ) + #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + #else + $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) + #end +#end +#set( $expression = \\"\\" ) +#if( !$expSet.isEmpty() ) + #set( $expression = \\"SET\\" ) + #foreach( $entry in $expSet.entrySet() ) + #set( $expression = \\"$expression $entry.key = $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expAdd.isEmpty() ) + #set( $expression = \\"$expression ADD\\" ) + #foreach( $entry in $expAdd.entrySet() ) + #set( $expression = \\"$expression $entry.key $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expRemove.isEmpty() ) + #set( $expression = \\"$expression REMOVE\\" ) + #foreach( $entry in $expRemove ) + #set( $expression = \\"$expression $entry\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#set( $update = {} ) +$util.qr($update.put(\\"expression\\", \\"$expression\\")) +#if( !$expNames.isEmpty() ) + $util.qr($update.put(\\"expressionNames\\", $expNames)) +#end +#if( !$expValues.isEmpty() ) + $util.qr($update.put(\\"expressionValues\\", $expValues)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": true +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": true + } +})) +#end +## End - key condition ** +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#set( $UpdateItem = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"UpdateItem\\", + \\"key\\": $Key, + \\"update\\": $update +} ) +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($UpdateItem.put(\\"condition\\", $Conditions)) +#end +$util.toJson($UpdateItem) +## [End] Mutation Update resolver. **" +`; + exports[`ModelTransformer: should not add default primary key when ID is defined 1`] = ` "## [Start] Create Request template. ** ## Begin - key condition ** @@ -86,3 +468,1238 @@ $util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) $util.toJson($PutObject) ## [End] Create Request template. **" `; + +exports[`ModelTransformer: should not generate superfluous input and filter types 1`] = ` +" +type Entity { + id: ID! + str: String + createdAt: AWSDateTime! + updatedAt: AWSDateTime! +} + +input ModelStringInput { + ne: String + eq: String + le: String + lt: String + ge: String + gt: String + contains: String + notContains: String + between: [String] + beginsWith: String + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +input ModelIntInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelFloatInput { + ne: Float + eq: Float + le: Float + lt: Float + ge: Float + gt: Float + between: [Float] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelBooleanInput { + ne: Boolean + eq: Boolean + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelIDInput { + ne: ID + eq: ID + le: ID + lt: ID + ge: ID + gt: ID + contains: ID + notContains: ID + between: [ID] + beginsWith: ID + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +enum ModelAttributeTypes { + binary + binarySet + bool + list + map + number + numberSet + string + stringSet + _null +} + +input ModelSizeInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] +} + +enum ModelSortDirection { + ASC + DESC +} + +type Query { + getEntity(id: ID!): Entity +} + +" +`; + +exports[`ModelTransformer: should not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime 1`] = ` +" +type Post { + id: ID! + str: String + createdAt: AWSTimestamp + updatedAt: AWSTimestamp +} + +input ModelStringInput { + ne: String + eq: String + le: String + lt: String + ge: String + gt: String + contains: String + notContains: String + between: [String] + beginsWith: String + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +input ModelIntInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelFloatInput { + ne: Float + eq: Float + le: Float + lt: Float + ge: Float + gt: Float + between: [Float] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelBooleanInput { + ne: Boolean + eq: Boolean + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelIDInput { + ne: ID + eq: ID + le: ID + lt: ID + ge: ID + gt: ID + contains: ID + notContains: ID + between: [ID] + beginsWith: ID + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +enum ModelAttributeTypes { + binary + binarySet + bool + list + map + number + numberSet + string + stringSet + _null +} + +input ModelSizeInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] +} + +enum ModelSortDirection { + ASC + DESC +} + +type Query { + getPost(id: ID!): Post + listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection +} + +type ModelPostConnection { + items: [Post] + nextToken: String +} + +input ModelPostFilterInput { + id: ModelIDInput + str: ModelStringInput + createdAt: ModelIntInput + updatedAt: ModelIntInput + and: [ModelPostFilterInput] + or: [ModelPostFilterInput] + not: ModelPostFilterInput +} + +input ModelPostConditionInput { + id: ModelIDInput + str: ModelStringInput + createdAt: ModelIntInput + updatedAt: ModelIntInput + and: [ModelPostConditionInput] + or: [ModelPostConditionInput] + not: ModelPostConditionInput +} + +input CreatePostInput { + id: ID + str: String + createdAt: AWSTimestamp + updatedAt: AWSTimestamp +} + +type Mutation { + createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post + updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post + deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post +} + +input UpdatePostInput { + id: ID! + str: String + createdAt: AWSTimestamp + updatedAt: AWSTimestamp +} + +input DeletePostInput { + id: ID! +} + +type Subscription { + onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) + onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) + onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) +} + +" +`; + +exports[`ModelTransformer: should not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime 2`] = ` +"## [Start] Create Request template. ** +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +$util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) +#set( $PutObject = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"PutItem\\", + \\"attributeValues\\": $util.dynamodb.toMapValues($mergedValues), + \\"condition\\": $condition +} ) +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($PutObject.put(\\"condition\\", $Conditions)) +#end +#if( $ctx.stash.metadata.modelObjectKey ) + $util.qr($PutObject.put(\\"key\\", $ctx.stash.metadata.modelObjectKey)) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($mergedValues.id) +} ) + $util.qr($PutObject.put(\\"key\\", $Key)) +#end +$util.toJson($PutObject) +## [End] Create Request template. **" +`; + +exports[`ModelTransformer: should not to auto generate createdAt and updatedAt when the type in schema is not AWSDateTime 3`] = ` +"## [Start] Mutation Update resolver. ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +## Initialize the vars for creating ddb expression ** +#set( $expNames = {} ) +#set( $expValues = {} ) +#set( $expSet = {} ) +#set( $expAdd = {} ) +#set( $expRemove = [] ) +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $Key = $ctx.stash.metadata.modelObjectKey ) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.input.id) +} ) +#end +## Model key ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyFields = [] ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyFields.add(\\"$entry.key\\")) + #end +#else + #set( $keyFields = [\\"id\\"] ) +#end +#foreach( $entry in $util.map.copyAndRemoveAllKeys($mergedValues, $keyFields).entrySet() ) + #if( !$util.isNull($ctx.stash.metadata.dynamodbNameOverrideMap) && $ctx.stash.metadata.dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) + #set( $entryKeyAttributeName = $ctx.stash.metadata.dynamodbNameOverrideMap.get(\\"$entry.key\\") ) + #else + #set( $entryKeyAttributeName = $entry.key ) + #end + #if( $util.isNull($entry.value) ) + #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + #else + $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) + #end +#end +#set( $expression = \\"\\" ) +#if( !$expSet.isEmpty() ) + #set( $expression = \\"SET\\" ) + #foreach( $entry in $expSet.entrySet() ) + #set( $expression = \\"$expression $entry.key = $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expAdd.isEmpty() ) + #set( $expression = \\"$expression ADD\\" ) + #foreach( $entry in $expAdd.entrySet() ) + #set( $expression = \\"$expression $entry.key $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expRemove.isEmpty() ) + #set( $expression = \\"$expression REMOVE\\" ) + #foreach( $entry in $expRemove ) + #set( $expression = \\"$expression $entry\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#set( $update = {} ) +$util.qr($update.put(\\"expression\\", \\"$expression\\")) +#if( !$expNames.isEmpty() ) + $util.qr($update.put(\\"expressionNames\\", $expNames)) +#end +#if( !$expValues.isEmpty() ) + $util.qr($update.put(\\"expressionValues\\", $expValues)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": true +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": true + } +})) +#end +## End - key condition ** +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#set( $UpdateItem = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"UpdateItem\\", + \\"key\\": $Key, + \\"update\\": $update +} ) +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($UpdateItem.put(\\"condition\\", $Conditions)) +#end +$util.toJson($UpdateItem) +## [End] Mutation Update resolver. **" +`; + +exports[`ModelTransformer: should not to include createdAt and updatedAt field when timestamps is set to null 1`] = ` +" +type Post { + id: ID! + str: String +} + +input ModelStringInput { + ne: String + eq: String + le: String + lt: String + ge: String + gt: String + contains: String + notContains: String + between: [String] + beginsWith: String + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +input ModelIntInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelFloatInput { + ne: Float + eq: Float + le: Float + lt: Float + ge: Float + gt: Float + between: [Float] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelBooleanInput { + ne: Boolean + eq: Boolean + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelIDInput { + ne: ID + eq: ID + le: ID + lt: ID + ge: ID + gt: ID + contains: ID + notContains: ID + between: [ID] + beginsWith: ID + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +enum ModelAttributeTypes { + binary + binarySet + bool + list + map + number + numberSet + string + stringSet + _null +} + +input ModelSizeInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] +} + +enum ModelSortDirection { + ASC + DESC +} + +type Query { + getPost(id: ID!): Post + listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection +} + +type ModelPostConnection { + items: [Post] + nextToken: String +} + +input ModelPostFilterInput { + id: ModelIDInput + str: ModelStringInput + and: [ModelPostFilterInput] + or: [ModelPostFilterInput] + not: ModelPostFilterInput +} + +input ModelPostConditionInput { + id: ModelIDInput + str: ModelStringInput + and: [ModelPostConditionInput] + or: [ModelPostConditionInput] + not: ModelPostConditionInput +} + +input CreatePostInput { + id: ID + str: String +} + +type Mutation { + createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post + updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post + deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post +} + +input UpdatePostInput { + id: ID! + str: String +} + +input DeletePostInput { + id: ID! +} + +type Subscription { + onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) + onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) + onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) +} + +" +`; + +exports[`ModelTransformer: should not to include createdAt and updatedAt field when timestamps is set to null 2`] = ` +"## [Start] Create Request template. ** +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +$util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) +#set( $PutObject = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"PutItem\\", + \\"attributeValues\\": $util.dynamodb.toMapValues($mergedValues), + \\"condition\\": $condition +} ) +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($PutObject.put(\\"condition\\", $Conditions)) +#end +#if( $ctx.stash.metadata.modelObjectKey ) + $util.qr($PutObject.put(\\"key\\", $ctx.stash.metadata.modelObjectKey)) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($mergedValues.id) +} ) + $util.qr($PutObject.put(\\"key\\", $Key)) +#end +$util.toJson($PutObject) +## [End] Create Request template. **" +`; + +exports[`ModelTransformer: should not to include createdAt and updatedAt field when timestamps is set to null 3`] = ` +"## [Start] Mutation Update resolver. ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +## Initialize the vars for creating ddb expression ** +#set( $expNames = {} ) +#set( $expValues = {} ) +#set( $expSet = {} ) +#set( $expAdd = {} ) +#set( $expRemove = [] ) +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $Key = $ctx.stash.metadata.modelObjectKey ) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.input.id) +} ) +#end +## Model key ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyFields = [] ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyFields.add(\\"$entry.key\\")) + #end +#else + #set( $keyFields = [\\"id\\"] ) +#end +#foreach( $entry in $util.map.copyAndRemoveAllKeys($mergedValues, $keyFields).entrySet() ) + #if( !$util.isNull($ctx.stash.metadata.dynamodbNameOverrideMap) && $ctx.stash.metadata.dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) + #set( $entryKeyAttributeName = $ctx.stash.metadata.dynamodbNameOverrideMap.get(\\"$entry.key\\") ) + #else + #set( $entryKeyAttributeName = $entry.key ) + #end + #if( $util.isNull($entry.value) ) + #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + #else + $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) + #end +#end +#set( $expression = \\"\\" ) +#if( !$expSet.isEmpty() ) + #set( $expression = \\"SET\\" ) + #foreach( $entry in $expSet.entrySet() ) + #set( $expression = \\"$expression $entry.key = $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expAdd.isEmpty() ) + #set( $expression = \\"$expression ADD\\" ) + #foreach( $entry in $expAdd.entrySet() ) + #set( $expression = \\"$expression $entry.key $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expRemove.isEmpty() ) + #set( $expression = \\"$expression REMOVE\\" ) + #foreach( $entry in $expRemove ) + #set( $expression = \\"$expression $entry\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#set( $update = {} ) +$util.qr($update.put(\\"expression\\", \\"$expression\\")) +#if( !$expNames.isEmpty() ) + $util.qr($update.put(\\"expressionNames\\", $expNames)) +#end +#if( !$expValues.isEmpty() ) + $util.qr($update.put(\\"expressionValues\\", $expValues)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": true +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": true + } +})) +#end +## End - key condition ** +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#set( $UpdateItem = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"UpdateItem\\", + \\"key\\": $Key, + \\"update\\": $update +} ) +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($UpdateItem.put(\\"condition\\", $Conditions)) +#end +$util.toJson($UpdateItem) +## [End] Mutation Update resolver. **" +`; + +exports[`ModelTransformer: should support timestamp parameters when generating pipelineFunctions and output schema 1`] = ` +" +type Post { + id: ID! + str: String + createdOn: AWSDateTime! + updatedOn: AWSDateTime! +} + +input ModelStringInput { + ne: String + eq: String + le: String + lt: String + ge: String + gt: String + contains: String + notContains: String + between: [String] + beginsWith: String + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +input ModelIntInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelFloatInput { + ne: Float + eq: Float + le: Float + lt: Float + ge: Float + gt: Float + between: [Float] + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelBooleanInput { + ne: Boolean + eq: Boolean + attributeExists: Boolean + attributeType: ModelAttributeTypes +} + +input ModelIDInput { + ne: ID + eq: ID + le: ID + lt: ID + ge: ID + gt: ID + contains: ID + notContains: ID + between: [ID] + beginsWith: ID + attributeExists: Boolean + attributeType: ModelAttributeTypes + size: ModelSizeInput +} + +enum ModelAttributeTypes { + binary + binarySet + bool + list + map + number + numberSet + string + stringSet + _null +} + +input ModelSizeInput { + ne: Int + eq: Int + le: Int + lt: Int + ge: Int + gt: Int + between: [Int] +} + +enum ModelSortDirection { + ASC + DESC +} + +type Query { + getPost(id: ID!): Post + listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection +} + +type ModelPostConnection { + items: [Post] + nextToken: String +} + +input ModelPostFilterInput { + id: ModelIDInput + str: ModelStringInput + and: [ModelPostFilterInput] + or: [ModelPostFilterInput] + not: ModelPostFilterInput +} + +input ModelPostConditionInput { + id: ModelIDInput + str: ModelStringInput + and: [ModelPostConditionInput] + or: [ModelPostConditionInput] + not: ModelPostConditionInput +} + +input CreatePostInput { + id: ID + str: String +} + +type Mutation { + createPost(input: CreatePostInput!, condition: ModelPostConditionInput): Post + updatePost(input: UpdatePostInput!, condition: ModelPostConditionInput): Post + deletePost(input: DeletePostInput!, condition: ModelPostConditionInput): Post +} + +input UpdatePostInput { + id: ID! + str: String +} + +input DeletePostInput { + id: ID! +} + +type Subscription { + onCreatePost: Post @aws_subscribe(mutations: [\\"createPost\\"]) + onUpdatePost: Post @aws_subscribe(mutations: [\\"updatePost\\"]) + onDeletePost: Post @aws_subscribe(mutations: [\\"deletePost\\"]) +} + +" +`; + +exports[`ModelTransformer: should support timestamp parameters when generating pipelineFunctions and output schema 2`] = ` +"## [Start] Create Request template. ** +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +$util.qr($mergedValues.put(\\"__typename\\", \\"Post\\")) +#set( $PutObject = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"PutItem\\", + \\"attributeValues\\": $util.dynamodb.toMapValues($mergedValues), + \\"condition\\": $condition +} ) +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": false +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": false + } +})) +#end +## End - key condition ** +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($PutObject.put(\\"condition\\", $Conditions)) +#end +#if( $ctx.stash.metadata.modelObjectKey ) + $util.qr($PutObject.put(\\"key\\", $ctx.stash.metadata.modelObjectKey)) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($mergedValues.id) +} ) + $util.qr($PutObject.put(\\"key\\", $Key)) +#end +$util.toJson($PutObject) +## [End] Create Request template. **" +`; + +exports[`ModelTransformer: should support timestamp parameters when generating pipelineFunctions and output schema 3`] = ` +"## [Start] Mutation Update resolver. ** +## Set the default values to put request ** +#set( $mergedValues = $util.defaultIfNull($ctx.stash.defaultValues, {}) ) +## copy the values from input ** +$util.qr($mergedValues.putAll($util.defaultIfNull($ctx.args.input, {}))) +## set the typename ** +## Initialize the vars for creating ddb expression ** +#set( $expNames = {} ) +#set( $expValues = {} ) +#set( $expSet = {} ) +#set( $expAdd = {} ) +#set( $expRemove = [] ) +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $Key = $ctx.stash.metadata.modelObjectKey ) +#else + #set( $Key = { + \\"id\\": $util.dynamodb.toDynamoDB($ctx.args.input.id) +} ) +#end +## Model key ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyFields = [] ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyFields.add(\\"$entry.key\\")) + #end +#else + #set( $keyFields = [\\"id\\"] ) +#end +#foreach( $entry in $util.map.copyAndRemoveAllKeys($mergedValues, $keyFields).entrySet() ) + #if( !$util.isNull($ctx.stash.metadata.dynamodbNameOverrideMap) && $ctx.stash.metadata.dynamodbNameOverrideMap.containsKey(\\"$entry.key\\") ) + #set( $entryKeyAttributeName = $ctx.stash.metadata.dynamodbNameOverrideMap.get(\\"$entry.key\\") ) + #else + #set( $entryKeyAttributeName = $entry.key ) + #end + #if( $util.isNull($entry.value) ) + #set( $discard = $expRemove.add(\\"#$entryKeyAttributeName\\") ) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + #else + $util.qr($expSet.put(\\"#$entryKeyAttributeName\\", \\":$entryKeyAttributeName\\")) + $util.qr($expNames.put(\\"#$entryKeyAttributeName\\", \\"$entry.key\\")) + $util.qr($expValues.put(\\":$entryKeyAttributeName\\", $util.dynamodb.toDynamoDB($entry.value))) + #end +#end +#set( $expression = \\"\\" ) +#if( !$expSet.isEmpty() ) + #set( $expression = \\"SET\\" ) + #foreach( $entry in $expSet.entrySet() ) + #set( $expression = \\"$expression $entry.key = $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expAdd.isEmpty() ) + #set( $expression = \\"$expression ADD\\" ) + #foreach( $entry in $expAdd.entrySet() ) + #set( $expression = \\"$expression $entry.key $entry.value\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#if( !$expRemove.isEmpty() ) + #set( $expression = \\"$expression REMOVE\\" ) + #foreach( $entry in $expRemove ) + #set( $expression = \\"$expression $entry\\" ) + #if( $foreach.hasNext() ) + #set( $expression = \\"$expression,\\" ) + #end + #end +#end +#set( $update = {} ) +$util.qr($update.put(\\"expression\\", \\"$expression\\")) +#if( !$expNames.isEmpty() ) + $util.qr($update.put(\\"expressionNames\\", $expNames)) +#end +#if( !$expValues.isEmpty() ) + $util.qr($update.put(\\"expressionValues\\", $expValues)) +#end +## Begin - key condition ** +#if( $ctx.stash.metadata.modelObjectKey ) + #set( $keyConditionExpr = {} ) + #set( $keyConditionExprNames = {} ) + #foreach( $entry in $ctx.stash.metadata.modelObjectKey.entrySet() ) + $util.qr($keyConditionExpr.put(\\"keyCondition$velocityCount\\", { + \\"attributeExists\\": true +})) + $util.qr($keyConditionExprNames.put(\\"#keyCondition$velocityCount\\", \\"$entry.key\\")) + #end + $util.qr($ctx.stash.conditions.add($keyConditionExpr)) +#else + $util.qr($ctx.stash.conditions.add({ + \\"id\\": { + \\"attributeExists\\": true + } +})) +#end +## End - key condition ** +#if( $context.args.condition ) + $util.qr($ctx.stash.conditions.add($context.args.condition)) +#end +## Start condition block ** +#if( $ctx.stash.conditions && $ctx.stash.conditions.size() != 0 ) + #set( $mergedConditions = { + \\"and\\": $ctx.stash.conditions +} ) + #set( $Conditions = $util.parseJson($util.transform.toDynamoDBConditionExpression($mergedConditions)) ) + #if( $Conditions.expressionValues && $Conditions.expressionValues.size() == 0 ) + #set( $Conditions = { + \\"expression\\": $Conditions.expression, + \\"expressionNames\\": $Conditions.expressionNames +} ) + #end + ## End condition block ** +#end +#set( $UpdateItem = { + \\"version\\": \\"2018-05-29\\", + \\"operation\\": \\"UpdateItem\\", + \\"key\\": $Key, + \\"update\\": $update +} ) +#if( $Conditions ) + #if( $keyConditionExprNames ) + $util.qr($Conditions.expressionNames.putAll($keyConditionExprNames)) + #end + $util.qr($UpdateItem.put(\\"condition\\", $Conditions)) +#end +$util.toJson($UpdateItem) +## [End] Mutation Update resolver. **" +`; diff --git a/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts b/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts index e16b304aff8..c195d10498f 100644 --- a/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts +++ b/packages/amplify-graphql-model-transformer/src/__tests__/model-transformer.test.ts @@ -471,26 +471,26 @@ describe('ModelTransformer: ', () => { expectFields(queryType!, ['listPosts']); expectFields(queryType!, ['listUsers']); - 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(); const postInputType = getInputType(parsed, 'ModelPostFilterInput'); expect(postInputType).toBeDefined(); const userInputType = getInputType(parsed, 'ModelUserFilterInput'); expect(userInputType).toBeDefined(); - 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(); expect(verifyInputCount(parsed, 'ModelUserFilterInput', 1)).toBeTruthy(); }); @@ -555,7 +555,6 @@ describe('ModelTransformer: ', () => { const definition = out.schema; expect(definition).toBeDefined(); const parsed = parse(definition); - validateModelSchema(parsed); const postMetaDataInputType = getInputType(parsed, 'PostMetadataInput'); @@ -606,11 +605,11 @@ describe('ModelTransformer: ', () => { const connectionType = getObjectType(parsed, 'ModelPostConnection'); expect(connectionType).toBeDefined(); - 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(); }); @@ -650,4 +649,116 @@ describe('ModelTransformer: ', () => { expect(mutList).toContain('updatePost'); expect(mutList).toContain('deletePost'); }); + + 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(); + }); }); diff --git a/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts b/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts index cc7c434b47f..4426d74a744 100644 --- a/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts +++ b/packages/amplify-graphql-model-transformer/src/graphql-model-transformer.ts @@ -45,6 +45,7 @@ import { makeDeleteInputField, makeListQueryFilterInput, makeListQueryModel, + makeModelSortDirectionEnumObject, makeMutationConditionInput, makeUpdateInputField, } from './graphql-types'; @@ -192,11 +193,10 @@ export class ModelTransformer extends TransformerModelBase implements Transforme }; 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) { const def = ctx.output.getObject(type)!; // add Non Model type inputs @@ -951,4 +951,12 @@ export class ModelTransformer extends TransformerModelBase implements Transforme return subscriptionToMutationsMap; }; + + private ensureModelSortDirectionEnum(ctx: TransformerValidationStepContextProvider): void { + if (!ctx.output.hasType('ModelSortDirection')) { + const modelSortDirection = makeModelSortDirectionEnumObject(); + + ctx.output.addEnum(modelSortDirection); + } + } } diff --git a/packages/amplify-graphql-model-transformer/src/graphql-types/common.ts b/packages/amplify-graphql-model-transformer/src/graphql-types/common.ts index 2b31ab209c0..bfeabc19342 100644 --- a/packages/amplify-graphql-model-transformer/src/graphql-types/common.ts +++ b/packages/amplify-graphql-model-transformer/src/graphql-types/common.ts @@ -48,6 +48,7 @@ export const makeConditionFilterInput = ( name: string, object: ObjectTypeDefinitionNode, ): InputObjectDefinitionWrapper => { + const supportsConditions = true; const input = InputObjectDefinitionWrapper.create(name); const wrappedObject = new ObjectDefinitionWrapper(object); for (let field of wrappedObject.fields) { @@ -55,8 +56,8 @@ export const makeConditionFilterInput = ( 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); + ? ModelResourceIDs.ModelFilterListInputTypeName(field.getTypeName(), !supportsConditions) + : ModelResourceIDs.ModelFilterScalarInputTypeName(field.getTypeName(), !supportsConditions); const inputField = InputFieldWrapper.create(field.name, conditionTypeName, true, field.isList()); input.addField(inputField); } else if (isEnumType) { @@ -80,7 +81,7 @@ export const makeConditionFilterInput = ( export const addModelConditionInputs = (ctx: TransformerTransformSchemaStepContextProvider): void => { const conditionsInput: TypeDefinitionNode[] = ['String', 'Int', 'Float', 'Boolean', 'ID'].map(scalarName => - makeModelScalarFilterInputObject(scalarName, false), + makeModelScalarFilterInputObject(scalarName, true), ); conditionsInput.push(makeAttributeTypeEnum()); conditionsInput.push(makeSizeInputType()); diff --git a/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap b/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap index e689aa3a264..1864c4a1f1f 100644 --- a/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap +++ b/packages/amplify-graphql-searchable-transformer/src/__tests__/__snapshots__/amplify-graphql-searchable-transformer.tests.ts.snap @@ -148,7 +148,7 @@ type Query { listEmployees(filter: ModelEmployeeFilterInput, limit: Int, nextToken: String): ModelEmployeeConnection } -input ModelStringFilterInput { +input ModelStringInput { ne: String eq: String le: String @@ -164,7 +164,7 @@ input ModelStringFilterInput { size: ModelSizeInput } -input ModelIntFilterInput { +input ModelIntInput { ne: Int eq: Int le: Int @@ -176,7 +176,7 @@ input ModelIntFilterInput { attributeType: ModelAttributeTypes } -input ModelFloatFilterInput { +input ModelFloatInput { ne: Float eq: Float le: Float @@ -188,14 +188,14 @@ input ModelFloatFilterInput { attributeType: ModelAttributeTypes } -input ModelBooleanFilterInput { +input ModelBooleanInput { ne: Boolean eq: Boolean attributeExists: Boolean attributeType: ModelAttributeTypes } -input ModelIDFilterInput { +input ModelIDInput { ne: ID eq: ID le: ID @@ -234,15 +234,20 @@ input ModelSizeInput { between: [Int] } +enum ModelSortDirection { + ASC + DESC +} + type ModelEmployeeConnection { items: [Employee] nextToken: String } input ModelEmployeeFilterInput { - id: ModelIDFilterInput - firstName: ModelStringFilterInput - lastName: ModelStringFilterInput + id: ModelIDInput + firstName: ModelStringInput + lastName: ModelStringInput type: EmploymentType and: [ModelEmployeeFilterInput] or: [ModelEmployeeFilterInput] @@ -255,9 +260,9 @@ input ModelEmploymentTypeInput { } input ModelEmployeeConditionInput { - id: ModelIDFilterInput - firstName: ModelStringFilterInput - lastName: ModelStringFilterInput + id: ModelIDInput + firstName: ModelStringInput + lastName: ModelStringInput type: EmploymentType and: [ModelEmployeeConditionInput] or: [ModelEmployeeConditionInput] @@ -439,7 +444,7 @@ type Query { listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection } -input ModelStringFilterInput { +input ModelStringInput { ne: String eq: String le: String @@ -455,7 +460,7 @@ input ModelStringFilterInput { size: ModelSizeInput } -input ModelIntFilterInput { +input ModelIntInput { ne: Int eq: Int le: Int @@ -467,7 +472,7 @@ input ModelIntFilterInput { attributeType: ModelAttributeTypes } -input ModelFloatFilterInput { +input ModelFloatInput { ne: Float eq: Float le: Float @@ -479,14 +484,14 @@ input ModelFloatFilterInput { attributeType: ModelAttributeTypes } -input ModelBooleanFilterInput { +input ModelBooleanInput { ne: Boolean eq: Boolean attributeExists: Boolean attributeType: ModelAttributeTypes } -input ModelIDFilterInput { +input ModelIDInput { ne: ID eq: ID le: ID @@ -525,26 +530,31 @@ input ModelSizeInput { between: [Int] } +enum ModelSortDirection { + ASC + DESC +} + type ModelPostConnection { items: [Post] nextToken: String } input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostFilterInput] or: [ModelPostFilterInput] not: ModelPostFilterInput } input ModelPostConditionInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostConditionInput] or: [ModelPostConditionInput] not: ModelPostConditionInput @@ -1237,7 +1247,7 @@ type SearchableUserConnection { aggregateItems: [SearchableAggregateResult] } -input ModelStringFilterInput { +input ModelStringInput { ne: String eq: String le: String @@ -1253,7 +1263,7 @@ input ModelStringFilterInput { size: ModelSizeInput } -input ModelIntFilterInput { +input ModelIntInput { ne: Int eq: Int le: Int @@ -1265,7 +1275,7 @@ input ModelIntFilterInput { attributeType: ModelAttributeTypes } -input ModelFloatFilterInput { +input ModelFloatInput { ne: Float eq: Float le: Float @@ -1277,14 +1287,14 @@ input ModelFloatFilterInput { attributeType: ModelAttributeTypes } -input ModelBooleanFilterInput { +input ModelBooleanInput { ne: Boolean eq: Boolean attributeExists: Boolean attributeType: ModelAttributeTypes } -input ModelIDFilterInput { +input ModelIDInput { ne: ID eq: ID le: ID @@ -1323,26 +1333,31 @@ input ModelSizeInput { between: [Int] } +enum ModelSortDirection { + ASC + DESC +} + type ModelPostConnection { items: [Post] nextToken: String } input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostFilterInput] or: [ModelPostFilterInput] not: ModelPostFilterInput } input ModelPostConditionInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostConditionInput] or: [ModelPostConditionInput] not: ModelPostConditionInput @@ -1390,16 +1405,16 @@ type ModelUserConnection { } input ModelUserFilterInput { - id: ModelIDFilterInput - name: ModelStringFilterInput + id: ModelIDInput + name: ModelStringInput and: [ModelUserFilterInput] or: [ModelUserFilterInput] not: ModelUserFilterInput } input ModelUserConditionInput { - id: ModelIDFilterInput - name: ModelStringFilterInput + id: ModelIDInput + name: ModelStringInput and: [ModelUserConditionInput] or: [ModelUserConditionInput] not: ModelUserConditionInput @@ -1564,7 +1579,7 @@ type Query { listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection } -input ModelStringFilterInput { +input ModelStringInput { ne: String eq: String le: String @@ -1580,7 +1595,7 @@ input ModelStringFilterInput { size: ModelSizeInput } -input ModelIntFilterInput { +input ModelIntInput { ne: Int eq: Int le: Int @@ -1592,7 +1607,7 @@ input ModelIntFilterInput { attributeType: ModelAttributeTypes } -input ModelFloatFilterInput { +input ModelFloatInput { ne: Float eq: Float le: Float @@ -1604,14 +1619,14 @@ input ModelFloatFilterInput { attributeType: ModelAttributeTypes } -input ModelBooleanFilterInput { +input ModelBooleanInput { ne: Boolean eq: Boolean attributeExists: Boolean attributeType: ModelAttributeTypes } -input ModelIDFilterInput { +input ModelIDInput { ne: ID eq: ID le: ID @@ -1650,26 +1665,31 @@ input ModelSizeInput { between: [Int] } +enum ModelSortDirection { + ASC + DESC +} + type ModelPostConnection { items: [Post] nextToken: String } input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostFilterInput] or: [ModelPostFilterInput] not: ModelPostFilterInput } input ModelPostConditionInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostConditionInput] or: [ModelPostConditionInput] not: ModelPostConditionInput @@ -1835,7 +1855,7 @@ type Query { listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection } -input ModelStringFilterInput { +input ModelStringInput { ne: String eq: String le: String @@ -1851,7 +1871,7 @@ input ModelStringFilterInput { size: ModelSizeInput } -input ModelIntFilterInput { +input ModelIntInput { ne: Int eq: Int le: Int @@ -1863,7 +1883,7 @@ input ModelIntFilterInput { attributeType: ModelAttributeTypes } -input ModelFloatFilterInput { +input ModelFloatInput { ne: Float eq: Float le: Float @@ -1875,14 +1895,14 @@ input ModelFloatFilterInput { attributeType: ModelAttributeTypes } -input ModelBooleanFilterInput { +input ModelBooleanInput { ne: Boolean eq: Boolean attributeExists: Boolean attributeType: ModelAttributeTypes } -input ModelIDFilterInput { +input ModelIDInput { ne: ID eq: ID le: ID @@ -1921,26 +1941,31 @@ input ModelSizeInput { between: [Int] } +enum ModelSortDirection { + ASC + DESC +} + type ModelPostConnection { items: [Post] nextToken: String } input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostFilterInput] or: [ModelPostFilterInput] not: ModelPostFilterInput } input ModelPostConditionInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostConditionInput] or: [ModelPostConditionInput] not: ModelPostConditionInput @@ -2121,7 +2146,7 @@ type Query { listPosts(filter: ModelPostFilterInput, limit: Int, nextToken: String): ModelPostConnection } -input ModelStringFilterInput { +input ModelStringInput { ne: String eq: String le: String @@ -2137,7 +2162,7 @@ input ModelStringFilterInput { size: ModelSizeInput } -input ModelIntFilterInput { +input ModelIntInput { ne: Int eq: Int le: Int @@ -2149,7 +2174,7 @@ input ModelIntFilterInput { attributeType: ModelAttributeTypes } -input ModelFloatFilterInput { +input ModelFloatInput { ne: Float eq: Float le: Float @@ -2161,14 +2186,14 @@ input ModelFloatFilterInput { attributeType: ModelAttributeTypes } -input ModelBooleanFilterInput { +input ModelBooleanInput { ne: Boolean eq: Boolean attributeExists: Boolean attributeType: ModelAttributeTypes } -input ModelIDFilterInput { +input ModelIDInput { ne: ID eq: ID le: ID @@ -2207,26 +2232,31 @@ input ModelSizeInput { between: [Int] } +enum ModelSortDirection { + ASC + DESC +} + type ModelPostConnection { items: [Post] nextToken: String } input ModelPostFilterInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostFilterInput] or: [ModelPostFilterInput] not: ModelPostFilterInput } input ModelPostConditionInput { - id: ModelIDFilterInput - title: ModelStringFilterInput - createdAt: ModelStringFilterInput - updatedAt: ModelStringFilterInput + id: ModelIDInput + title: ModelStringInput + createdAt: ModelStringInput + updatedAt: ModelStringInput and: [ModelPostConditionInput] or: [ModelPostConditionInput] not: ModelPostConditionInput