Skip to content

Commit

Permalink
test: add docs and tests for removing fields
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Hayes committed May 12, 2021
1 parent 3251227 commit a3aa90e
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 17 deletions.
34 changes: 34 additions & 0 deletions docs/guide/writing-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,40 @@ Both the root level map, and the `fields.map` maps will only contain entries for
mapping function did not return null. If the mapping function returned null for all fields, the
`mapInputFields` will return null instead of returning a map to indicate no wrapping should occur
### Removing fields and enum values
Plugins can remove fields from objects, interfaces, and input objects, and remove specific values
from enums. To do this, simply return null from the corresponding on\*Config plugin hook:
```ts
onOutputFieldConfig(fieldConfig: GiraphQLOutputFieldConfig<Types>) {
if (fieldConfig.name === 'removeMe') {
return null;
}

return fieldConfig;
}

onInputFieldConfig(fieldConfig: GiraphQLInputFieldConfig<Types>) {
if (fieldConfig.name === 'removeMe') {
return null;
}

return fieldConfig;
}

onEnumValueConfig(valueConfig: GiraphQLEnumValueConfig<Types>) {
if (valueConfig.value === 'removeMe') {
return null;
}

return valueConfig;
}
```
Remocing whole types from the schema needs to be done by transforming the schema during the
`afterBuild` hook. See the `sub-graph` plugin for a more complete example of removing types.
## Useful methods:
- `builder.configStore.onTypeConfig`: Takes a type ref and a callback, and will invoke the callback
Expand Down
30 changes: 14 additions & 16 deletions packages/core/src/types/builder-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,14 @@ export type EnumValueConfigMap<Types extends SchemaTypes> = Record<
GiraphQLSchemaTypes.EnumValueConfig<Types>
>;

export type ShapeFromEnumValues<
Types extends SchemaTypes,
Values extends EnumValues<Types>
> = Values extends readonly string[]
? Values[number]
: Values extends EnumValueConfigMap<Types>
? {
[K in keyof Values]: Values[K]['value'] extends number | string ? Values[K]['value'] : K;
}[keyof Values]
: never;
export type ShapeFromEnumValues<Types extends SchemaTypes, Values extends EnumValues<Types>> =
Values extends readonly string[]
? Values[number]
: Values extends EnumValueConfigMap<Types>
? {
[K in keyof Values]: Values[K]['value'] extends number | string ? Values[K]['value'] : K;
}[keyof Values]
: never;

export type ObjectFieldsShape<Types extends SchemaTypes, Shape> = (
t: GiraphQLSchemaTypes.ObjectFieldBuilder<Types, Shape>,
Expand Down Expand Up @@ -125,7 +123,7 @@ export type FieldOptionsFromKind<
Args extends InputFieldMap,
Kind extends FieldKind,
ResolveShape,
ResolveReturnShape
ResolveReturnShape,
> = GiraphQLSchemaTypes.FieldOptionsByKind<
Types,
ParentShape,
Expand All @@ -140,7 +138,7 @@ export type ObjectTypeOptions<
Types extends SchemaTypes,
Param extends ObjectParam<Types>,
Shape,
Interfaces extends InterfaceParam<Types>[]
Interfaces extends InterfaceParam<Types>[],
> = (Param extends string
? {}
: Param extends ObjectRef<unknown>
Expand All @@ -155,7 +153,7 @@ export type InterfaceTypeOptions<
Types extends SchemaTypes,
Param extends InterfaceParam<Types>,
Shape,
Interfaces extends InterfaceParam<Types>[] = InterfaceParam<Types>[]
Interfaces extends InterfaceParam<Types>[] = InterfaceParam<Types>[],
> = GiraphQLSchemaTypes.InterfaceTypeOptions<Types, Shape, Interfaces> &
(Param extends string
? {}
Expand All @@ -166,7 +164,7 @@ export type InterfaceTypeOptions<
export type EnumTypeOptions<
Types extends SchemaTypes,
Param extends EnumParam,
Values extends EnumValues<Types>
Values extends EnumValues<Types>,
> = Param extends BaseEnum
? Merge<
Omit<GiraphQLSchemaTypes.EnumTypeOptions<Types, Values>, 'values'> & {
Expand All @@ -184,7 +182,7 @@ export type ArgBuilder<Types extends SchemaTypes> = GiraphQLSchemaTypes.InputFie
export type ValidateInterfaces<
Shape,
Types extends SchemaTypes,
Interfaces extends InterfaceParam<Types>
Interfaces extends InterfaceParam<Types>,
> = Interfaces extends InterfaceParam<Types>
? Shape extends OutputShape<Types, Interfaces>
? Interfaces
Expand Down Expand Up @@ -228,7 +226,7 @@ export type CompatibleTypes<
Types extends SchemaTypes,
ParentShape,
Type extends TypeParam<Types>,
Nullable extends FieldNullability<Type>
Nullable extends FieldNullability<Type>,
> = {
[K in keyof ParentShape]-?: ParentShape[K] extends ShapeFromTypeParam<Types, Type, Nullable>
? K
Expand Down
17 changes: 17 additions & 0 deletions packages/core/tests/__snapshots__/plugin.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`plugin example generates expected schema 1`] = `
"type Query {
args(input: TestInput, notRemoved: Boolean, testEnum: TestEnum): Boolean!
notRemoved: Boolean!
}
enum TestEnum {
DONT_REMOVE
}
input TestInput {
notRemoved: Boolean
}
"
`;
8 changes: 8 additions & 0 deletions packages/core/tests/examples/test-plugin/builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import SchemaBuilder from '../../../src';
import TestPlugin from './plugin';

const builder = new SchemaBuilder({
plugins: [TestPlugin],
});

export default builder;
10 changes: 10 additions & 0 deletions packages/core/tests/examples/test-plugin/global-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { FieldNullability, InputFieldMap, SchemaTypes, TypeParam } from '@giraphql/core';
import { GiraphQLTestPlugin } from './plugin';

declare global {
export namespace GiraphQLSchemaTypes {
export interface Plugins<Types extends SchemaTypes> {
test: GiraphQLTestPlugin<Types>;
}
}
}
45 changes: 45 additions & 0 deletions packages/core/tests/examples/test-plugin/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import builder from './builder';

const TestEnum = builder.enumType('TestEnum', {
values: {
REMOVE: {
value: 'removeMe',
},
DONT_REMOVE: {
value: 'dontRemoveMe',
},
},
});

const TestInput = builder.inputType('TestInput', {
fields: (t) => ({
removeMe: t.boolean({}),
notRemoved: t.boolean({}),
}),
});

builder.queryType({
fields: (t) => ({
notRemoved: t.boolean({
resolve: () => true,
}),
removeMe: t.boolean({
resolve: () => true,
}),
args: t.boolean({
args: {
input: t.arg({
type: TestInput,
}),
removeMe: t.arg.boolean({}),
notRemoved: t.arg.boolean({}),
testEnum: t.arg({ type: TestEnum }),
},
resolve: () => true,
}),
}),
});

const schema = builder.toSchema({});

export default schema;
74 changes: 74 additions & 0 deletions packages/core/tests/examples/test-plugin/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { GraphQLFieldResolver, GraphQLSchema, GraphQLTypeResolver } from 'graphql';
import SchemaBuilder, {
BasePlugin,
GiraphQLEnumValueConfig,
GiraphQLInputFieldConfig,
GiraphQLInterfaceTypeConfig,
GiraphQLOutputFieldConfig,
GiraphQLTypeConfig,
GiraphQLUnionTypeConfig,
SchemaTypes,
} from '../../../src';

const pluginName = 'test' as const;

export default pluginName;

export class GiraphQLTestPlugin<Types extends SchemaTypes> extends BasePlugin<Types> {
onTypeConfig(typeConfig: GiraphQLTypeConfig) {
return typeConfig;
}

onOutputFieldConfig(fieldConfig: GiraphQLOutputFieldConfig<Types>) {
if (fieldConfig.name === 'removeMe') {
return null;
}

return fieldConfig;
}

onInputFieldConfig(fieldConfig: GiraphQLInputFieldConfig<Types>) {
if (fieldConfig.name === 'removeMe') {
return null;
}

return fieldConfig;
}

onEnumValueConfig(valueConfig: GiraphQLEnumValueConfig<Types>) {
if (valueConfig.value === 'removeMe') {
return null;
}

return valueConfig;
}

beforeBuild() {}

afterBuild(schema: GraphQLSchema): GraphQLSchema {
return schema;
}

wrapResolve(
resolver: GraphQLFieldResolver<unknown, Types['Context'], object>,
fieldConfig: GiraphQLOutputFieldConfig<Types>,
): GraphQLFieldResolver<unknown, Types['Context'], object> {
return (parent, args, context, info) => resolver(parent, args, context, info) as unknown;
}

wrapSubscribe(
subscribe: GraphQLFieldResolver<unknown, Types['Context'], object> | undefined,
fieldConfig: GiraphQLOutputFieldConfig<Types>,
) {
return subscribe;
}

wrapResolveType(
resolveType: GraphQLTypeResolver<unknown, Types['Context']>,
typeConfig: GiraphQLInterfaceTypeConfig | GiraphQLUnionTypeConfig,
) {
return resolveType;
}
}

SchemaBuilder.registerPlugin(pluginName, GiraphQLTestPlugin);
14 changes: 14 additions & 0 deletions packages/core/tests/examples/test-plugin/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ApolloServer } from 'apollo-server';
import schema from '.';

const server = new ApolloServer({ schema });

server
.listen(8000, (error: unknown) => {
if (error) {
throw error;
}

console.log('🚀 Server started at http://127.0.0.1:8000');
})
.catch(console.error);
8 changes: 8 additions & 0 deletions packages/core/tests/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { lexicographicSortSchema, printSchema } from 'graphql';
import pluginSchema from './examples/test-plugin';

describe('plugin example', () => {
it('generates expected schema', () => {
expect(printSchema(lexicographicSortSchema(pluginSchema))).toMatchSnapshot();
});
});
2 changes: 1 addition & 1 deletion packages/plugin-dataloader/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"graphql": ">=15.1.0"
},
"devDependencies": {
"@giraphql/core": "^2.4.0",
"@giraphql/core": "2.4.0",
"apollo-server": "^2.22.2",
"dataloader": "^2.0.0",
"graphql-tag": "^2.11.0"
Expand Down

0 comments on commit a3aa90e

Please sign in to comment.