Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Count field definition #11

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Added resolver
  • Loading branch information
Tedsterh committed Mar 20, 2022
commit 52db825d3daabb4c0499dad06e072a3ee991ef2b
131 changes: 129 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {
DirectiveWrapper,
IAM_AUTH_ROLE_PARAMETER,
IAM_UNAUTH_ROLE_PARAMETER,
MappingTemplate,
TransformerNestedStack,
TransformerPluginBase,
} from "@aws-amplify/graphql-transformer-core";
Expand All @@ -10,8 +13,10 @@ import {
TransformerTransformSchemaStepContextProvider,
} from "@aws-amplify/graphql-transformer-interfaces";
import * as appsync from "@aws-cdk/aws-appsync";
import { AuthorizationType } from "@aws-cdk/aws-appsync";
import * as iam from "@aws-cdk/aws-iam";
import * as lambda from "@aws-cdk/aws-lambda";
import * as cdk from "@aws-cdk/core";
import {
DirectiveNode,
FieldDefinitionNode,
Expand All @@ -21,12 +26,21 @@ import {
NamedTypeNode,
NonNullTypeNode,
ObjectTypeDefinitionNode,
StringValueNode,
TypeNode,
} from "graphql";
import {
compoundExpression,
Expression,
obj,
printBlock,
qref,
} from "graphql-mapping-template";
import {
makeField,
makeInputValueDefinition,
makeNamedType,
ResolverResourceIDs,
toCamelCase,
toPascalCase,
} from "graphql-transformer-common";
Expand All @@ -43,8 +57,8 @@ export type FieldCountDirectiveConfiguration = {
directive: DirectiveNode;
fields: string[];
fieldNodes: FieldDefinitionNode[];
relatedType: ObjectTypeDefinitionNode;
relatedTypeIndex: FieldDefinitionNode[];
resolverTypeName: ObjectTypeDefinitionNode;
resolverFieldName: string;
countFields: string[];
};

Expand Down Expand Up @@ -86,6 +100,8 @@ export default class CountTransformer
directiveName,
object: parent as ObjectTypeDefinitionNode,
field: field,
resolverTypeName: parent,
resolverFieldName: field.name.value,
directive,
}) as FieldCountDirectiveConfiguration;

Expand Down Expand Up @@ -144,6 +160,8 @@ export default class CountTransformer
};

generateResolvers = (ctx: TransformerContextProvider) => {
const createdResources = new Map<string, any>();

// Path on the local filesystem to the handler zip file
const HANDLER_LOCAL_PATH = path.join(__dirname, "handler.zip");
const stack: TransformerNestedStack = ctx.stackManager.createStack(
Expand Down Expand Up @@ -183,6 +201,107 @@ export default class CountTransformer
stack
);

for (const config of this.fields) {
const {
countFields,
field,
fields,
object,
resolverTypeName,
resolverFieldName,
} = config;

const localFields = fields.length > 0 ? fields : countFields;

// Find the table we want to scan
const tableDataSource = ctx.dataSources.get(
resolverTypeName
) as appsync.DynamoDbDataSource;
const table = tableDataSource.ds
.dynamoDbConfig as appsync.CfnDataSource.DynamoDBConfigProperty;

const dataSource = ctx.api.host.getDataSource(
`${resolverTypeName.name.value}Table`
);

// Allow the lambda to access this table
funcRole.addToPolicy(
new iam.PolicyStatement({
actions: ["dynamodb:Scan"],
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be Query

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, which bit in the policy needed to be query?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well unless I'm mistaken, we need the lambda to be able to query the index. We could scan, but that wouldn't be efficient. So add dynamodb:Query.

effect: iam.Effect.ALLOW,
resources: [
`arn:aws:dynamodb:${table.awsRegion}:${stack.account}:table/${table.tableName}`,
],
})
);

// Create the GraphQL resolvers.
const resolverId = ResolverResourceIDs.ResolverResourceID(
config.resolverTypeName.name.value,
config.resolverFieldName
);
let resolver = createdResources.get(resolverId);

const requestTemplate: Array<Expression> = [
qref(`$ctx.stash.put("typeName", "${config.resolverTypeName}")`),
qref(`$ctx.stash.put("fieldName", "${config.resolverFieldName}")`),
];

const authModes = [
Copy link
Owner

@multimeric multimeric Mar 21, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you import this code from the AuthTransformer module? I assume it's copied from there.

ctx.authConfig.defaultAuthentication,
...(ctx.authConfig.additionalAuthenticationProviders || []),
].map((mode) => mode?.authenticationType);
if (authModes.includes(AuthorizationType.IAM)) {
const authRoleParameter = (
ctx.stackManager.getParameter(
IAM_AUTH_ROLE_PARAMETER
) as cdk.CfnParameter
).valueAsString;
const unauthRoleParameter = (
ctx.stackManager.getParameter(
IAM_UNAUTH_ROLE_PARAMETER
) as cdk.CfnParameter
).valueAsString;
requestTemplate.push(
qref(
`$ctx.stash.put("authRole", "arn:aws:sts::${
cdk.Stack.of(ctx.stackManager.rootStack).account
}:assumed-role/${authRoleParameter}/CognitoIdentityCredentials")`
),
qref(
`$ctx.stash.put("unauthRole", "arn:aws:sts::${
cdk.Stack.of(ctx.stackManager.rootStack).account
}:assumed-role/${unauthRoleParameter}/CognitoIdentityCredentials")`
)
);
}
requestTemplate.push(obj({}));

if (resolver === undefined) {
// TODO: update function to use resolver manager
resolver = ctx.api.host.addResolver(
config.resolverTypeName.name.value,
config.resolverFieldName,
MappingTemplate.inlineTemplateFromString(
printBlock("Stash resolver specific context.")(
compoundExpression(requestTemplate)
)
),
MappingTemplate.s3MappingTemplateFromString(
"$util.toJson($ctx.prev.result)",
`${config.resolverTypeName}.${config.resolverFieldName}.res.vtl`
),
undefined,
undefined,
[],
stack
);
createdResources.set(resolverId, resolver);
}

resolver.pipelineConfig.functions.push(func);
}

for (const model of this.models) {
// Find the table we want to scan
const tableDataSource = ctx.dataSources.get(
Expand Down Expand Up @@ -239,6 +358,14 @@ $util.toJson({
};
}

function getIndexName(directive: DirectiveNode): string | undefined {
for (const argument of directive.arguments!) {
if (argument.name.value === "name") {
return (argument.value as StringValueNode).value;
}
}
}

export function ensureHasCountField(
config: FieldCountDirectiveConfiguration,
ctx: TransformerContextProvider
Expand Down