Skip to content

Commit

Permalink
add subscribe/resolve wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
stephentuso committed Mar 1, 2019
1 parent 7751281 commit 2509e6f
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 9 deletions.
51 changes: 50 additions & 1 deletion src/builders/buildFieldConfigMap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { AnyConstructor, EmptyConstructor, isEmptyConstructor, Maybe, ObjectLiteral } from '../types';
import { resolveThunk, Thunk } from '../utils/thunk';
import { GraphQLFieldConfigMap, GraphQLFieldResolver } from 'graphql';
import { FieldConfig, FieldConfigMap, FieldResolver } from '../fields';
import { FieldConfig, FieldConfigMap, FieldResolver, FieldSubscriber, SubscriptionFieldConfigMap } from '../fields';
import {
getArgsConfig,
getFieldConfig,
Expand Down Expand Up @@ -34,6 +34,13 @@ type InputConstructorNode<T> = {
children: InputConstructorChildren,
}

const isInSubscribe = Symbol();

type WrappedSubscribePayload<T> = {
[isInSubscribe]: true,
value: T,
}

const buildInputConstructorTree = <T>(InputClass: EmptyConstructor<T>): Maybe<InputConstructorNode<T>> => {
const map = isArgs(InputClass) ? getArgsConfig(InputClass) : getInputFieldConfig(InputClass);
if (!map) {
Expand Down Expand Up @@ -105,6 +112,48 @@ export const buildFieldConfigMap = <TSource, TContext>(
}));
};

const wrapSubscribe = <TSource, TContext, TReturn, TArgs>(
subscribe: FieldSubscriber<TSource, TContext, TReturn, TArgs>,
): FieldSubscriber<TSource, TContext, WrappedSubscribePayload<TReturn>, TArgs> => {
return async function * (...args) {
const iterator = subscribe(...args);
for await (const value of iterator) {
yield {
[isInSubscribe]: true,
value,
}
}
}
}

function wrapSubscriptionResolve<TSource, TContext, TReturn, TArgs>(
resolve?: FieldResolver<TSource, TContext, TReturn, TArgs>,
): FieldResolver<WrappedSubscribePayload<TSource>, TContext, TReturn | TSource, TArgs> {
return (root, ...args) => {
if (!root[isInSubscribe]) {
throw new Error('Subscription field resolve called without subscribe');
}

if (!resolve) {
return root.value;
}

return resolve(root.value, ...args);
}
}

export const buildSubscriptionFieldConfigMap = <TSource, TContext>(
map: SubscriptionFieldConfigMap<TSource, TContext>,
): GraphQLFieldConfigMap<any, TContext> => {
return mapValues(map, (config) => ({
...config,
resolve: wrapSubscriptionResolve(config.resolve),
subscribe: wrapSubscribe(config.subscribe),
type: buildOutputType(config.type, true),
args: config.args ? resolveThunk(getArgs(config.args)) : undefined,
}));
}

const defaultResolver = (key: string) => (source: ObjectLiteral, ...rest: any[]) => {
const resolve = convertResolverMethod(source, key);
if (resolve) {
Expand Down
14 changes: 7 additions & 7 deletions src/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { MaybePromise, EmptyConstructor, MaybeArray, AnyConstructor } from './ty
import { GraphQLOutputType, GraphQLResolveInfo, subscribe } from 'graphql';
import { mergeThunks, resolveThunk, Thunk } from './utils/thunk';
import { isArray } from 'lodash';
import { buildFieldConfigMap } from './builders/buildFieldConfigMap';
import { buildFieldConfigMap, buildSubscriptionFieldConfigMap } from './builders/buildFieldConfigMap';
import Field from './decorators/Field';

export type FieldCreatorConfig<TReturn, TArgs = {}> = {
Expand All @@ -18,7 +18,7 @@ export type FieldResolver<TSource, TContext, TReturn, TArgs = {}> =
(source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo) => MaybePromise<TReturn>;

export type FieldSubscriber<TSource, TContext, TReturn, TArgs = {}> =
(source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo) => AsyncIterator<TReturn>;
(source: TSource, args: TArgs, context: TContext, info: GraphQLResolveInfo) => AsyncIterable<TReturn>;

export type FieldConfig<TSource, TContext, TReturn, TArgs = {}> = FieldCreatorConfig<TReturn, TArgs> & {
resolve?: FieldResolver<TSource, TContext, TReturn, TArgs>,
Expand All @@ -30,7 +30,7 @@ type SubscriptionFieldConfigSimple<
TReturn,
TArgs = {},
> = FieldConfig<TSource, TContext, TReturn, TArgs> & {
subscribe?: FieldSubscriber<TSource, TContext, TReturn, TArgs>,
subscribe: FieldSubscriber<TSource, TContext, TReturn, TArgs>,
};

type SubscriptionFieldConfigWithResolver<
Expand All @@ -41,7 +41,7 @@ type SubscriptionFieldConfigWithResolver<
TArgs = {},
> = FieldConfig<TSource, TContext, TReturn, TArgs> & {
resolve?: FieldResolver<TSubReturn, TContext, TReturn, TArgs>,
subscribe?: FieldSubscriber<TSource, TContext, TSubReturn, TArgs>,
subscribe: FieldSubscriber<TSource, TContext, TSubReturn, TArgs>,
};

export type SubscriptionFieldConfig<TSource, TContext, TReturn, TSubReturn, TArgs = {}> =
Expand Down Expand Up @@ -124,13 +124,13 @@ export const subscriptionFields = <TSource = undefined, TContext = undefined>(
};

export const buildFields = <TSource, TContext>(fields: MaybeArray<Thunk<FieldConfigMap<TSource, TContext>>>) => {
let thunk = isArray(fields) ? mergeThunks(...fields) : fields;
const thunk = isArray(fields) ? mergeThunks(...fields) : fields;
const configMap = resolveThunk(thunk);
return buildFieldConfigMap(configMap);
}

export const buildSubscriptionFields = <TSource, TContext>(fields: MaybeArray<Thunk<SubscriptionFieldConfigMap<TSource, TContext>>>) => {
let thunk = isArray(fields) ? mergeThunks(...fields) : fields;
const thunk = isArray(fields) ? mergeThunks(...fields) : fields;
const configMap = resolveThunk(thunk);
// TODO
return buildSubscriptionFieldConfigMap(configMap);
};
4 changes: 3 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import buildInputObjectType from './builders/buildInputObjectType';
import buildInterfaceType from './builders/buildInterfaceType';
import buildObjectType from './builders/buildObjectType';
import { buildInputType, buildNamedType, buildNamedTypes, buildOutputType, buildType } from './typeHelpers';
import { buildFields, fields } from './fields';
import { buildFields, buildSubscriptionFields, fields, subscriptionFields } from './fields';
import { TSGraphQLBoolean, TSGraphQLFloat, TSGraphQLID, TSGraphQLInt, TSGraphQLString } from './wrappers/scalars';
import scalarType from './wrappers/scalarType';

Expand Down Expand Up @@ -51,5 +51,7 @@ export {
buildType,
fields,
buildFields,
subscriptionFields,
buildSubscriptionFields,
fieldDecoratorForContext,
};

0 comments on commit 2509e6f

Please sign in to comment.