Skip to content

Commit

Permalink
fix: optional id (#339)
Browse files Browse the repository at this point in the history
* fix: optional id

* infer id
  • Loading branch information
ethanve authored Aug 4, 2020
1 parent c8e6b29 commit 38bb939
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/resources/HttpResource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default class HttpResource<
> extends Resource<TContext> {
readonly api: TApi;

_endpoint: Endpoint;
protected readonly _endpoint: Endpoint;

constructor(context: TContext, { endpoint }: HttpResourceOptions) {
super(context);
Expand Down
8 changes: 2 additions & 6 deletions src/resources/Resource.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { Maybe, Obj } from '../utils/typing';

export default abstract class Resource<TContext = any> {
context: TContext;
protected constructor(public readonly context: TContext) {}

constructor(context: TContext) {
this.context = context;
}

abstract get(id: string): Promise<Maybe<Obj>>;
abstract get(id?: string): Promise<Maybe<Obj>>;
}
17 changes: 12 additions & 5 deletions src/types/createResolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import { GraphQLFieldConfig, GraphQLFieldResolver } from 'graphql';

import NodeType from './NodeType';

export default function createResolve<TFields extends string, TContext = any>(
resolve: GraphQLFieldResolver<Record<TFields, any>, TContext>,
fieldNames: TFields[],
): GraphQLFieldConfig<any, TContext>['resolve'] {
export default function createResolve<
TSource,
TContext,
TField extends string
>(
resolve: GraphQLFieldResolver<TSource & Record<TField, unknown>, TContext>,
fieldNames: TField[],
): GraphQLFieldConfig<TSource & Record<TField, unknown>, TContext>['resolve'] {
return async (obj, args, context, info) => {
const nodeType = info.parentType as NodeType<any, Record<TFields, any>>;
const nodeType = info.parentType as NodeType<
any,
TSource & Record<TField, unknown>
>;
for (const fieldName of fieldNames) {
if (obj[fieldName] === undefined) {
// await in a loop is OK here. dataloader makes sure that only
Expand Down
8 changes: 4 additions & 4 deletions test/HttpApi.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ describe('HttpApi', () => {

const keys = range(api.numKeysPerChunk + 5).map(String);

const params = keys.map(key => `saladId=${key}`);
const params = keys.map((key) => `saladId=${key}`);
const chunk1Params = params.slice(0, api.numKeysPerChunk);
const chunk2Params = params.slice(api.numKeysPerChunk);

const data = keys.map(saladId => ({ saladId }));
const data = keys.map((saladId) => ({ saladId }));
const chunk1Data = data.slice(0, api.numKeysPerChunk);
const chunk2Data = data.slice(api.numKeysPerChunk);

Expand All @@ -102,8 +102,8 @@ describe('HttpApi', () => {

const loader = api.createArgLoader('dressings', 'saladId');

expect(await Promise.all(keys.map(key => loader.load(key)))).toEqual(
data.map(item => [item]),
expect(await Promise.all(keys.map((key) => loader.load(key)))).toEqual(
data.map((item) => [item]),
);
});
});
2 changes: 1 addition & 1 deletion test/HttpResource.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('HttpResource', () => {

it('should accept a function as the endpoint', () => {
const resource = new HttpResource(mockContext, {
endpoint: id => `salads/${id || ''}`,
endpoint: (id) => `salads/${id || ''}`,
});

expect(resource.getPath('1')).toEqual('salads/1');
Expand Down
23 changes: 13 additions & 10 deletions test/NodeType.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import mockedFetch from 'node-fetch';

import { HttpResource } from '../src';
import { getConfig, setup } from '../src/config';
import createResolve from '../src/types/createResolve';
import NodeType from '../src/types/NodeType';
import createResolve from '../src/types/createResolve';
import { MockContext, TestHttpApi, TestHttpResource } from './helpers';

describe('NodeType', () => {
Expand Down Expand Up @@ -63,19 +63,21 @@ describe('NodeType', () => {
name: { type: GraphQLString },
resolvedFavoriteColor: {
type: GraphQLString,
resolve: createResolve(obj => obj.favoriteColor, ['favoriteColor']),
resolve: createResolve((obj) => obj.favoriteColor, [
'favoriteColor',
]),
},
resolvedUserId: {
type: GraphQLString,
resolve: o => o.id,
resolve: (o) => o.id,
},
}),
makeId: a => a.id,
createResource: ctx => new WidgetResource(ctx, { endpoint: 'users' }),
makeId: (a) => a.id,
createResource: (ctx) => new WidgetResource(ctx, { endpoint: 'users' }),
localIdFieldName: 'userId',
});

const Widget = new NodeType({
const Widget: NodeType<WidgetResource> = new NodeType({
name: 'Widget',
fields: () => ({
name: { type: GraphQLString },
Expand All @@ -88,7 +90,8 @@ describe('NodeType', () => {
type: User,
},
}),
createResource: ctx => new WidgetResource(ctx, { endpoint: 'widgets' }),
createResource: (ctx) =>
new WidgetResource(ctx, { endpoint: 'widgets' }),
});

schema = new GraphQLSchema({
Expand Down Expand Up @@ -188,7 +191,7 @@ describe('NodeType', () => {
});

it('should createNode', () => {
const type = new NodeType({
const type: NodeType<HttpResource<TestHttpApi>> = new NodeType({
name: 'Foo',
fields: () => ({
foo: {
Expand All @@ -202,7 +205,7 @@ describe('NodeType', () => {
),
},
}),
createResource: ctx => new HttpResource(ctx, { endpoint: 'foo/bar' }),
createResource: (ctx) => new HttpResource(ctx, { endpoint: 'foo/bar' }),
});

expect(type.name).toEqual('Foo');
Expand All @@ -214,7 +217,7 @@ describe('NodeType', () => {
fields: () => ({
foo: { type: GraphQLString },
}),
createResource: ctx => new HttpResource(ctx, { endpoint: 'foo/bar' }),
createResource: (ctx) => new HttpResource(ctx, { endpoint: 'foo/bar' }),

makeId: ({ foo, bar }) => `${foo}/${bar}`,
});
Expand Down

0 comments on commit 38bb939

Please sign in to comment.