@pothos/plugin-federation
Version:
A Pothos plugin for implementing apollo federation subGraphs
103 lines (90 loc) • 2.79 kB
text/typescript
import {
FieldBuilder,
type InterfaceParam,
type MaybePromise,
ObjectRef,
RootFieldBuilder,
type SchemaTypes,
} from '@pothos/core';
import type { GraphQLResolveInfo } from 'graphql';
import type {
ExternalEntityOptions,
Selection,
SelectionFromShape,
selectionShapeKey,
} from './types';
import { addUsedDirectives, keyDirective, mergeDirectives } from './util';
export const providesMap = new WeakMap<{}, string>();
export class ExternalEntityRef<
Types extends SchemaTypes,
Shape extends object,
Key extends Selection<object>,
> extends ObjectRef<Types, Shape> {
override kind = 'Object' as const;
builder: PothosSchemaTypes.SchemaBuilder<Types>;
private key?: Key | Key[];
private resolveReference?: (
parent: object,
context: Types['Context'],
info: GraphQLResolveInfo,
) => MaybePromise<Shape | null | undefined>;
constructor(
builder: PothosSchemaTypes.SchemaBuilder<Types>,
name: string,
{
key,
resolveReference,
}: {
key?: Key | Key[];
resolveReference?: (
parent: Key[typeof selectionShapeKey],
context: Types['Context'],
info: GraphQLResolveInfo,
) => MaybePromise<Shape | null | undefined>;
},
) {
super(name);
this.builder = builder;
this.key = key;
this.resolveReference = resolveReference;
}
implement<const Interfaces extends InterfaceParam<Types>[]>({
fields,
externalFields,
directives,
...options
}: ExternalEntityOptions<Types, Shape, Interfaces>) {
addUsedDirectives(this.builder, ['extends', 'key']);
this.builder.objectType(this as unknown as ObjectRef<Types, unknown>, {
...(options as {} as PothosSchemaTypes.ObjectTypeOptions<Types, Shape>),
name: this.name,
directives: mergeDirectives(directives as [], [
...(this.key ? keyDirective(this.key) : []),
{ name: 'extends', args: {} },
]) as [],
fields: () => ({
...externalFields?.(
new RootFieldBuilder(this.builder, 'ExternalEntity', 'Object') as never,
),
...fields?.(new FieldBuilder(this.builder, 'ExtendedEntity', 'Object') as never),
}),
extensions: {
...options.extensions,
apollo: {
...(options.extensions?.apollo as {}),
subgraph: {
...(options.extensions?.apollo as { subgraph: {} })?.subgraph,
resolveReference: this.resolveReference,
},
},
},
});
return this;
}
provides<T extends object>(selection: SelectionFromShape<T>) {
const ref = Object.create(this) as ExternalEntityRef<Types, Shape & T, Key>;
providesMap.set(ref, selection);
this.builder.configStore.associateParamWithRef(ref, this);
return ref;
}
}