Skip to content

Commit

Permalink
feat(graphql-connection-transformer): allow null key-based connections (
Browse files Browse the repository at this point in the history
#5153)

* feat(graphql-connection-transformer): allow null key-based connections

Remove non-null check from key-based connections. Add early-return to request mapping templates when a specified key is null.

Future work needed to allow pk values to be integers in connections.

* fix: add passing test

Co-authored-by: Josue Ruiz <josurui@amazon.com>
  • Loading branch information
Ross Williams and SwaySway committed Jan 22, 2021
1 parent 5789b26 commit e9c8276
Show file tree
Hide file tree
Showing 3 changed files with 314 additions and 31 deletions.
Expand Up @@ -71,15 +71,14 @@ function validateKeyField(field: FieldDefinitionNode): void {
* @param field: the field to be checked.
*/
function validateKeyFieldConnectionWithKey(field: FieldDefinitionNode, ctx: TransformerContext): void {
const isNonNull = isNonNullType(field.type);
const isAList = isListType(field.type);
const isAScalarOrEnum = isScalarOrEnum(field.type, ctx.getTypeDefinitionsOfKind(Kind.ENUM_TYPE_DEFINITION) as EnumTypeDefinitionNode[]);

// The only valid key fields are single non-null fields.
if (!isAList && isNonNull && isAScalarOrEnum) {
if (!isAList && isAScalarOrEnum) {
return;
}
throw new InvalidDirectiveError(`All fields provided to an @connection must be non-null scalar or enum fields.`);
throw new InvalidDirectiveError(`All fields provided to an @connection must be scalar or enum fields.`);
}

/**
Expand Down
73 changes: 48 additions & 25 deletions packages/graphql-connection-transformer/src/resources.ts
Expand Up @@ -19,6 +19,8 @@ import {
iff,
raw,
Expression,
or,
list,
} from 'graphql-mapping-template';
import {
ResourceConstants,
Expand Down Expand Up @@ -149,7 +151,7 @@ export class ResourceFactory {
// Use Int minvalue as default
keyObj.attributes.push([
sortFieldInfo.primarySortFieldName,
ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNull($ctx.source.${sortFieldInfo.sortFieldName}, "${NONE_INT_VALUE}"))`),
ref(`util.dynamodb.toDynamoDBJson($util.defaultIfNull($ctx.source.${sortFieldInfo.sortFieldName}, ${NONE_INT_VALUE}))`),
]);
}
}
Expand All @@ -160,9 +162,16 @@ export class ResourceFactory {
FieldName: field,
TypeName: type,
RequestMappingTemplate: print(
DynamoDBMappingTemplate.getItem({
key: keyObj,
}),
ifElse(
or([
raw(`$util.isNull($ctx.source.${connectionAttribute})`),
...(sortFieldInfo ? [raw(`$util.isNull($ctx.source.${connectionAttribute})`)] : []),
]),
raw('#return'),
DynamoDBMappingTemplate.getItem({
key: keyObj,
}),
),
),
ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(false)),
}).dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID);
Expand Down Expand Up @@ -209,21 +218,25 @@ export class ResourceFactory {
FieldName: field,
TypeName: type,
RequestMappingTemplate: print(
compoundExpression([
...setup,
DynamoDBMappingTemplate.query({
query: raw('$util.toJson($query)'),
scanIndexForward: ifElse(
ref('context.args.sortDirection'),
ifElse(equals(ref('context.args.sortDirection'), str('ASC')), bool(true), bool(false)),
bool(true),
),
filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()),
limit: ref('limit'),
nextToken: ifElse(ref('context.args.nextToken'), ref('util.toJson($context.args.nextToken)'), nul()),
index: str(`gsi-${connectionName}`),
}),
]),
ifElse(
raw(`$util.isNull($context.source.${idFieldName})`),
compoundExpression([set(ref('result'), obj({ items: list([]) })), raw('#return($result)')]),
compoundExpression([
...setup,
DynamoDBMappingTemplate.query({
query: raw('$util.toJson($query)'),
scanIndexForward: ifElse(
ref('context.args.sortDirection'),
ifElse(equals(ref('context.args.sortDirection'), str('ASC')), bool(true), bool(false)),
bool(true),
),
filter: ifElse(ref('context.args.filter'), ref('util.transform.toDynamoDBFilterExpression($ctx.args.filter)'), nul()),
limit: ref('limit'),
nextToken: ifElse(ref('context.args.nextToken'), ref('util.toJson($context.args.nextToken)'), nul()),
index: str(`gsi-${connectionName}`),
}),
]),
),
),
ResponseMappingTemplate: print(
DynamoDBMappingTemplate.dynamoDBResponse(
Expand Down Expand Up @@ -283,11 +296,15 @@ export class ResourceFactory {
FieldName: field,
TypeName: type,
RequestMappingTemplate: print(
compoundExpression([
DynamoDBMappingTemplate.getItem({
key: keyObj,
}),
]),
ifElse(
or(connectionAttributes.map(ca => raw(`$util.isNull($ctx.source.${ca})`))),
raw('#return'),
compoundExpression([
DynamoDBMappingTemplate.getItem({
key: keyObj,
}),
]),
),
),
ResponseMappingTemplate: print(DynamoDBMappingTemplate.dynamoDBResponse(false)),
}).dependsOn(ResourceConstants.RESOURCES.GraphQLSchemaLogicalID);
Expand Down Expand Up @@ -361,7 +378,13 @@ export class ResourceFactory {
DataSourceName: Fn.GetAtt(ModelResourceIDs.ModelTableDataSourceID(relatedType.name.value), 'Name'),
FieldName: field,
TypeName: type,
RequestMappingTemplate: print(compoundExpression([...setup, queryObj])),
RequestMappingTemplate: print(
ifElse(
raw(`$util.isNull($ctx.source.${connectionAttributes[0]})`),
compoundExpression([set(ref('result'), obj({ items: list([]) })), raw('#return($result)')]),
compoundExpression([...setup, queryObj]),
),
),
ResponseMappingTemplate: print(
DynamoDBMappingTemplate.dynamoDBResponse(
false,
Expand Down

0 comments on commit e9c8276

Please sign in to comment.