pothos
pothos copied to clipboard
Separate files on building.
Is there any recommendation on how to split the building codes into separate files with Pothos?
|- mutations | |- readArticle.ts | |- updateUser.ts |- querys | |- getUser.ts | |- me.ts
As the definition is long and complicated, I want to split it into multiple files for better maintenance. But I don't have any good idea on how to split it and preserve the typing at the same time.
Here is my current proposal. But I don't like it much. I put all building code and define function into a file so that they are working on the same builder type.
// builder.ts
import SchemaBuilder from '@pothos/core'
import PrismaPlugin from '@pothos/plugin-prisma'
import RelayPlugin from '@pothos/plugin-relay'
import { Prisma } from '@prisma/client'
import type { Locale } from '@prisma/client'
import type PrismaTypes from '~/prisma/pothos-index'
import type { Context } from './type'
export function createBuilder() {
return new SchemaBuilder<{
Context: Context
PrismaTypes: PrismaTypes
Scalars: {
Date: {
Input: Date
Output: Date
}
JSON: {
Input: object
Output: object
}
}
Objects: {
// Me: Me
Locale: Locale
}
}>({
plugins: [RelayPlugin, PrismaPlugin],
prisma: {
client: context => context.prisma,
// Because the prisma client is loaded dynamically, we need to explicitly provide the some information about the prisma schema
dmmf: Prisma.dmmf,
},
relayOptions: {
idFieldName: '_id',
// These will become the defaults in the next major version
clientMutationId: 'omit',
cursorType: 'ID',
},
})
}
type Definition<T extends PothosSchemaTypes.SchemaBuilder<any> = ReturnType<typeof createBuilder>> = (builder: T) => void
export function defineMutationField(...args: Parameters<ReturnType<typeof createBuilder>['mutationField']>): Definition {
return (builder: ReturnType<typeof createBuilder>) => builder.mutationField(...args)
}
export function defineQueryField(...args: Parameters<ReturnType<typeof createBuilder>['queryField']>): Definition {
return (builder: ReturnType<typeof createBuilder>) => builder.queryField(...args)
}
export function addDefinitions(builder: ReturnType<typeof createBuilder>, ...definitions: Definition[]) {
for (const definition of definitions)
definition(builder)
}
for each definition file, for example,
mutations/viewArticle.ts
import { defineMutationField } from '~/server/graphql/builder'
export default defineMutationField('viewArticle', t => t.prismaField({
type: 'Article',
args: {
id: t.arg.int({ required: true }),
},
resolve: (query, parent, args, context) => {
return context.prisma.article.update({
where: { id: args.id },
data: {
viewCount: { increment: 1 },
viewedAt: new Date(),
},
...query,
})
},
}))
finally, in the entry file
schema.ts
import viewArticle from './mutations/viewArticle'
import me from './querys/me'
import { addDefinitions, createBuilder } from './builder'
const builder = createBuilder()
addDefinitions(builder, [
viewArticle,
me,
])
export const schema = builder.toSchema({
directives: [],
})
Seems working, but I don't know if there is any better solution.
Yes there is: https://pothos-graphql.dev/docs/guide/app-layout
Also this guide is helpful on how to mitigate circular references: https://pothos-graphql.dev/docs/guide/circular-references
You can see an example of the pattern mentioned in the guide above here: https://github.com/hayes/pothos/blob/main/examples/complex-app/src/schema/game.ts
going to close this, but let me know if you are still having issues
Experimenting with this myself, I feel like this could be a clean approach.
export const db = new PrismaClient();
interface ISchema {
PrismaTypes: PrismaTypes;
Scalars: {
DateTime: {
Output: Date;
Input: Date;
};
Json: {
Output: Prisma.JsonValue;
Input: Prisma.JsonValue;
};
};
}
export type IBuilder = PothosSchemaTypes.SchemaBuilder<
PothosSchemaTypes.ExtendDefaultTypes<ISchema>
>;
const builder: IBuilder = new SchemaBuilder<ISchema>({
plugins: [PrismaPlugin],
prisma: {
client: db
}
});
// base
models(builder);
queries(db, builder);
mutations(db, builder);
// not really sure yet
builder.queryType({});
builder.mutationType({});
// not really sure yet
builder.addScalarType("Json", JSONObjectResolver, {});
builder.addScalarType("DateTime", DateTimeResolver, {});
export const schema = builder.toSchema({});