Generators for Subscriptions #424
Jordan-Eckowitz
started this conversation in
General
Replies: 1 comment
-
Thought I'd share in case anyone else finds this useful. The script below uses import { Project, SyntaxKind } from "ts-morph";
import * as prettier from "prettier";
import { v4 as uuid } from "uuid";
import fs from "fs";
interface Props {
/** Path of the resolver that you'd like to add a subscription method */
resolverFilePath: string;
/** Where to save the generated custom subscription resolver */
outputFilePath: string;
/** TypeGraphQL object type (which defines the resolver schema model) */
objectType: string;
/** TypeGraphQL arguments type (which define the arguments for the resolver mutation method) */
argsType: string;
/** TypeGraphQL type that will be pushed to the publish method */
inputType: string;
/** Class resolver name which contains the mutation for adding the subscription method */
classResolverName: string;
/** Name of the mutation method within the class resolver */
mutationName: string;
/** Name of the subscription that will invoke it in the API */
subscriptionName: string;
}
const createSubscription = async ({
resolverFilePath,
subscriptionName,
objectType,
classResolverName,
mutationName,
argsType,
inputType,
outputFilePath,
}: Props) => {
const IMPORTS = `
import * as TypeGraphQL from "type-graphql";
import type { GraphQLResolveInfo } from "graphql";
import { ${argsType}, ${objectType}, ${inputType} } from "../prisma/generated";
import {
transformInfoIntoPrismaArgs,
getPrismaFromContext,
transformCountFieldIntoSelectRelationsCount,
} from "../prisma/generated/helpers";
`;
const CUSTOM_RESOLVER_NAME = "Custom" + classResolverName;
const TOPIC_ID = uuid();
// initialize ts-morph project
const project = new Project();
// add the resolver source file to the project
const sourceFile = project.addSourceFileAtPath(resolverFilePath);
// remove all existing import declarations
sourceFile.getImportDeclarations().forEach((importDeclaration) => {
importDeclaration.remove();
});
// add the new import declarations
sourceFile.insertText(0, `${IMPORTS}\n\nconst topicID = "${TOPIC_ID}"\n\n`);
// get the class and method declarations
const classDeclaration = sourceFile.getClass(classResolverName);
const methodDeclaration = classDeclaration.getMethod(mutationName);
// add the publish argument to the mutation method with the PubSub decorator and topics argument
methodDeclaration
.addParameter({
name: "publish",
type: `TypeGraphQL.Publisher<${inputType}>`,
})
.addDecorator({ name: "TypeGraphQL.PubSub", arguments: ["topicID"] });
// get the current return statement of the mutation method and its value
const methodReturnStatement = methodDeclaration.getDescendantsOfKind(
SyntaxKind.ReturnStatement
)[0];
const methodReturnValue = methodReturnStatement.getExpression();
// replace the return statement with a variable declaration (so it can be returned after awaiting the publish promise)
methodReturnStatement.replaceWithText(
`const data = await ${methodReturnValue.getText()};\nawait publish(data);\nreturn data;`
);
// add the new subscription method to the class declaration
classDeclaration
.rename(CUSTOM_RESOLVER_NAME)
.addMethod({
name: subscriptionName,
decorators: [
{
name: "TypeGraphQL.Subscription",
arguments: [`{ topics: topicID }`],
},
],
returnType: objectType,
statements: [`return data;`],
})
.addParameter({
name: "data",
type: objectType,
})
.addDecorator({
name: "TypeGraphQL.Root",
arguments: [],
});
// format the code with prettier
const formattedCode = await prettier.format(sourceFile.getText(), {
parser: "typescript",
});
// save the file
fs.writeFileSync(
`${outputFilePath}/${CUSTOM_RESOLVER_NAME}.ts`,
formattedCode
);
};
createSubscription({
resolverFilePath:
"src/prisma/generated/resolvers/crud/User/CreateOneUserResolver.ts",
outputFilePath: "src/resolvers",
objectType: "User",
argsType: "CreateOneUserArgs",
inputType: "UserCreateInput",
classResolverName: "CreateOneUserResolver",
mutationName: "createOneUser",
subscriptionName: "createUserSubscription",
}); |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
This package is fantastic - we're using the CRUD generators extensively and its saved us many dev hours!
The project I'm working on has a major realtime aspect to it and we're currently manually having to add subscriptions to existing CRUD resolvers.
I'm just curious if there is any way to optionally generate subscriptions too? Has anybody tried doing this using the additional decorator enhance map? https://prisma.typegraphql.com/docs/advanced/additional-decorators
Beta Was this translation helpful? Give feedback.
All reactions