Skip to content
This repository has been archived by the owner on Apr 15, 2020. It is now read-only.

Commit

Permalink
fix(transforms): refactor TransformRootFields to allow flexible trans…
Browse files Browse the repository at this point in the history
…form ordering

Fixes #27, now possible because info object is not modified, see 1676ab0
  • Loading branch information
yaacovCR committed Jan 21, 2020
1 parent d4c21fa commit d3919a5
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 84 deletions.
2 changes: 1 addition & 1 deletion src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export function isSubschemaConfig(value: SchemaLikeObject): value is SubschemaCo
export interface IDelegateToSchemaOptions<TContext = { [key: string]: any }> {
schema: GraphQLSchema | SubschemaConfig;
operation?: Operation;
fieldName: string;
fieldName?: string;
returnType?: GraphQLOutputType;
args?: { [key: string]: any };
context?: TContext;
Expand Down
9 changes: 4 additions & 5 deletions src/stitching/delegateToSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export default function delegateToSchema(
rootValue,
info,
operation = getDelegatingOperation(info.parentType, info.schema),
fieldName,
fieldName = info.fieldName,
returnType = info.returnType,
args,
context,
Expand Down Expand Up @@ -117,7 +117,7 @@ export function createDelegatingRequest({
schema: subschema,
info,
operation = getDelegatingOperation(info.parentType, info.schema),
fieldName,
fieldName = info.fieldName,
args,
transforms = [],
skipValidation,
Expand Down Expand Up @@ -175,8 +175,8 @@ export function delegateRequest({
schema: subschema,
rootValue,
info,
operation,
fieldName,
operation = getDelegatingOperation(info.parentType, info.schema),
fieldName = info.fieldName,
returnType = info.returnType,
context,
transforms = [],
Expand Down Expand Up @@ -229,7 +229,6 @@ export function delegateRequest({
// "subscribe" to the subscription result and map the result through the transforms
return mapAsyncIterator<ExecutionResult, any>(subscriptionResult, result => {
const transformedResult = applyResultTransforms(result, transforms);

// wrap with fieldName to return for an additional round of resolutioon
// with payload as rootValue
return {
Expand Down
1 change: 0 additions & 1 deletion src/stitching/resolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ function defaultCreateProxyingResolver(
): GraphQLFieldResolver<any, any> {
return (parent, args, context, info) => delegateToSchema({
schema: subschemaConfig,
fieldName,
context,
info,
});
Expand Down
12 changes: 6 additions & 6 deletions src/test/testAlternateMergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -443,18 +443,18 @@ describe('transform object fields', () => {
}
return true;
}),
new RenameObjectFields((_typeName, fieldName) => {
if (fieldName === 'camel_case') {
return 'camelCase';
}
return fieldName;
}),
new RenameRootFields((_operation, fieldName) => {
if (fieldName === 'allItems') {
return 'items';
}
return fieldName;
}),
new RenameObjectFields((_typeName, fieldName) => {
if (fieldName === 'camel_case') {
return 'camelCase';
}
return fieldName;
}),
]);
});

Expand Down
5 changes: 5 additions & 0 deletions src/transforms/RenameRootFields.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { GraphQLField, GraphQLSchema } from 'graphql';
import { Request } from '../Interfaces';
import { Transform } from './transforms';
import TransformRootFields from './TransformRootFields';

Expand Down Expand Up @@ -28,4 +29,8 @@ export default class RenameRootFields implements Transform {
public transformSchema(originalSchema: GraphQLSchema): GraphQLSchema {
return this.transformer.transformSchema(originalSchema);
}

public transformRequest(originalRequest: Request): Request {
return this.transformer.transformRequest(originalRequest);
}
}
3 changes: 0 additions & 3 deletions src/transforms/TransformObjectFields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ export default class TransformObjectFields implements Transform {

public transformSchema(originalSchema: GraphQLSchema): GraphQLSchema {
this.transformedSchema = visitSchema(originalSchema, {
[VisitSchemaKind.ROOT_OBJECT]: () => {
return undefined;
},
[VisitSchemaKind.OBJECT_TYPE]: (type: GraphQLObjectType) => {
return this.transformFields(type, this.objectFieldTransformer);
}
Expand Down
88 changes: 20 additions & 68 deletions src/transforms/TransformRootFields.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import {
GraphQLObjectType,
GraphQLSchema,
GraphQLField,
GraphQLFieldConfig,
} from 'graphql';
import isEmptyObject from '../utils/isEmptyObject';
import { Request } from '../Interfaces';
import { Transform } from './transforms';
import { visitSchema } from '../utils/visitSchema';
import { VisitSchemaKind } from '../Interfaces';
import { TransformObjectFields } from '.';
import { FieldNodeTransformer } from './TransformObjectFields';

export type RootTransformer = (
operation: 'Query' | 'Mutation' | 'Subscription',
Expand All @@ -22,75 +21,28 @@ export type RootTransformer = (
type RenamedField = { name: string; field?: GraphQLFieldConfig<any, any> };

export default class TransformRootFields implements Transform {
private transform: RootTransformer;
private transformer: TransformObjectFields;

constructor(transform: RootTransformer) {
this.transform = transform;
constructor(rootFieldTransformer: RootTransformer, fieldNodeTransformer?: FieldNodeTransformer) {
const rootToObjectFieldTransformer =
(typeName: string, fieldName: string, field: GraphQLField<any, any>) => {
if (typeName === 'Query' || typeName === 'Mutation' || typeName === 'Subscription') {
return rootFieldTransformer(typeName, fieldName, field);
} else {
return undefined;
}
};
this.transformer = new TransformObjectFields(
rootToObjectFieldTransformer,
fieldNodeTransformer,
);
}

public transformSchema(originalSchema: GraphQLSchema): GraphQLSchema {
return visitSchema(originalSchema, {
[VisitSchemaKind.QUERY]: (type: GraphQLObjectType) => {
return transformFields(
type,
(fieldName: string, field: GraphQLField<any, any>) =>
this.transform('Query', fieldName, field),
);
},
[VisitSchemaKind.MUTATION]: (type: GraphQLObjectType) => {
return transformFields(
type,
(fieldName: string, field: GraphQLField<any, any>) =>
this.transform('Mutation', fieldName, field),
);
},
[VisitSchemaKind.SUBSCRIPTION]: (type: GraphQLObjectType) => {
return transformFields(
type,
(fieldName: string, field: GraphQLField<any, any>) =>
this.transform('Subscription', fieldName, field),
);
},
});
return this.transformer.transformSchema(originalSchema);
}
}

function transformFields(
type: GraphQLObjectType,
transformer: (
fieldName: string,
field: GraphQLField<any, any>,
) =>
| GraphQLFieldConfig<any, any>
| RenamedField
| null
| undefined,
): GraphQLObjectType {
const typeConfig = type.toConfig();
const fields = type.getFields();
const newFields = {};
Object.keys(fields).forEach(fieldName => {
const field = fields[fieldName];
const newField = transformer(fieldName, field);
if (typeof newField === 'undefined') {
newFields[fieldName] = typeConfig.fields[fieldName];
} else if (newField !== null) {
if ((newField as RenamedField).name) {
newFields[(newField as RenamedField).name] =
(newField as RenamedField).field ?
(newField as RenamedField).field :
typeConfig.fields[fieldName];
} else {
newFields[fieldName] = newField;
}
}
});
if (isEmptyObject(newFields)) {
return null;
} else {
return new GraphQLObjectType({
...type,
fields: newFields,
});
public transformRequest(originalRequest: Request): Request {
return this.transformer.transformRequest(originalRequest);
}
}

0 comments on commit d3919a5

Please sign in to comment.