@pothos/core
Version:
Pothos (formerly GiraphQL) is a plugin based schema builder for creating code-first GraphQL schemas in typescript
197 lines (172 loc) • 7.11 kB
text/typescript
import type {
GraphQLFieldResolver,
GraphQLIsTypeOfFn,
GraphQLSchema,
GraphQLTypeResolver,
} from 'graphql';
import type { BuildCache } from '../build-cache';
import { PothosError } from '../errors';
import type {
PothosEnumValueConfig,
PothosInputFieldConfig,
PothosInterfaceTypeConfig,
PothosObjectTypeConfig,
PothosOutputFieldConfig,
PothosTypeConfig,
PothosUnionTypeConfig,
SchemaTypes,
} from '../types';
import { createContextCache } from '../utils/context-cache';
const runCache = new WeakMap<{}, Map<unknown, unknown>>();
export class BasePlugin<Types extends SchemaTypes, T extends object = object> {
name;
builder;
buildCache;
options;
private requestDataMap = createContextCache<T, Types['Context']>((ctx) =>
this.createRequestData(ctx),
);
constructor(buildCache: BuildCache<Types>, name: keyof PothosSchemaTypes.Plugins<Types>) {
this.name = name;
this.builder = buildCache.builder;
this.buildCache = buildCache;
this.options = buildCache.options;
}
/**
* Called for each type defined with the SchemaBuilder
* @param {PothosTypeConfig} typeConfig - Config object describing the added type
* @return {PothosTypeConfig} Original or updated `typeConfig`
*/
onTypeConfig(typeConfig: PothosTypeConfig): PothosTypeConfig {
return typeConfig;
}
/**
* Called for each field on an Object or Interface type
* @param {PothosOutputFieldConfig} fieldConfig - Config object describing the added field
* @return {PothosOutputFieldConfig} Original or updated `fieldConfig`
*/
onOutputFieldConfig(
fieldConfig: PothosOutputFieldConfig<Types>,
): PothosOutputFieldConfig<Types> | null {
return fieldConfig;
}
/**
* Called for each argument or field on an Input object defined in your schema
* @param {PothosInputFieldConfig} fieldConfig - Config object describing the added field
* @return {PothosInputFieldConfig} Original or updated `fieldConfig`
*/
onInputFieldConfig(
fieldConfig: PothosInputFieldConfig<Types>,
): PothosInputFieldConfig<Types> | null {
return fieldConfig;
}
/**
* Called for each Enum value defined in your schema
* @param {PothosEnumValueConfig} valueConfig - Config object describing the enum value
* @return {PothosEnumValueConfig} Original or updated `valueConfig`
*/
onEnumValueConfig(
valueConfig: PothosEnumValueConfig<Types>,
): PothosEnumValueConfig<Types> | null {
return valueConfig;
}
/**
* Called before builder.toSchema() schema is called
*/
beforeBuild() {}
/**
* Called after all fields and types have been built during `builder.toSchema()`
* @param {GraphQLSchema} schema - the generated schema
* @return {PothosEnumValueConfig} Original or updated `schema`
*/
afterBuild(schema: GraphQLSchema): GraphQLSchema {
return schema;
}
/**
* Called with the resolver for each field in the schema
* @param {GraphQLFieldResolver} resolve - the resolve function
* @param {PothosOutputFieldConfig} fieldConfig - the config object for the field associated with this resolve function
* @return {GraphQLFieldResolver} - Either the original, or a new resolver function to use for this field
*/
wrapResolve(
resolver: GraphQLFieldResolver<unknown, Types['Context'], object>,
_fieldConfig: PothosOutputFieldConfig<Types>,
): GraphQLFieldResolver<unknown, Types['Context'], object> {
return resolver;
}
/**
* Called with the subscribe for each field on the Subscription type
* @param {GraphQLFieldResolver} subscribe - the subscribe function
* @param {PothosOutputFieldConfig} fieldConfig - the config object for the field associated with this subscribe function
* @return {GraphQLFieldResolver} - Either the original, or a new subscribe function to use for this field
*/
wrapSubscribe(
subscribe: GraphQLFieldResolver<unknown, Types['Context'], object> | undefined,
_fieldConfig: PothosOutputFieldConfig<Types>,
): GraphQLFieldResolver<unknown, Types['Context'], object> | undefined {
return subscribe;
}
/**
* Called with resolve or subscribe functions, but wraps outside of argMappers so arg mapping errors can be handled
* @param {GraphQLFieldResolver} resolve - the resolve function
* @param {PothosOutputFieldConfig} fieldConfig - the config object for the field associated with this resolve function
* @return {GraphQLFieldResolver} - Either the original, or a new resolver function to use for this field
*/
wrapArgMappers(
resolver: GraphQLFieldResolver<unknown, Types['Context'], object> | undefined,
_fieldConfig: PothosOutputFieldConfig<Types>,
): GraphQLFieldResolver<unknown, Types['Context'], object> | undefined {
return resolver;
}
/**
* Called with the resolveType for each Interface or Union type
* @param {GraphQLTypeResolver} resolveType - the resolveType function
* @param {PothosInterfaceTypeConfig | PothosUnionTypeConfig} typeConfig - the config object for the Interface or Union type
* @return {GraphQLTypeResolver} - Either the original, or a new resolveType function to use for this field
*/
wrapResolveType(
resolveType: GraphQLTypeResolver<unknown, Types['Context']>,
_typeConfig: PothosInterfaceTypeConfig | PothosUnionTypeConfig,
): GraphQLTypeResolver<unknown, Types['Context']> {
return resolveType;
}
/**
* Called with the isTypeOf for each Object type
* @param {GraphQLTypeResolver} resolveType - the resolveType function
* @param {PothosObjectTypeConfig} typeConfig - the config object for the Interface or Union type
* @return {GraphQLTypeResolver} - Either the original, or a new resolveType function to use for this field
*/
wrapIsTypeOf(
isTypeOf: GraphQLIsTypeOfFn<unknown, Types['Context']> | undefined,
_typeConfig: PothosObjectTypeConfig,
): GraphQLIsTypeOfFn<unknown, Types['Context']> | undefined {
return isTypeOf;
}
protected runUnique<R>(key: unknown, cb: () => R): R {
if (!runCache.has(this.builder)) {
runCache.set(this.builder, new Map<unknown, unknown>());
}
if (!runCache.get(this.builder)!.has(key)) {
const result = cb();
runCache.get(this.builder)!.set(key, result);
return result;
}
return runCache.get(this.builder)!.get(key) as R;
}
/**
* Creates a data object unique to the current request for use by this plugin
* @param {Types['Context']} context - the context object for the current request
* @return {object} - The data object for the current request
*/
protected createRequestData(_context: Types['Context']): T {
throw new PothosError('createRequestData not implemented');
}
/**
* Returns a data object for the current request. requires `createRequestData` to be implemented
* @param {Types['Context']} context - the context object for the current request
* @return {object} - The data object for the current request
*/
protected requestData(context: Types['Context']): T {
return this.requestDataMap(context)!;
}
}