Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
Sashko Stubailo committed Aug 17, 2017
1 parent f1e9d7c commit 5b3fe90
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 26 deletions.
13 changes: 12 additions & 1 deletion src/stitching/addSimpleRoutingResolvers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { mapValues, isEmpty } from 'lodash';
import { printSchema, print, GraphQLError } from 'graphql';
import { GraphQLFieldResolver, GraphQLSchema } from 'graphql';
import { GraphQLFieldResolver, GraphQLSchema, GraphQLInterfaceType, GraphQLUnionType } from 'graphql';
import { makeExecutableSchema } from '../schemaGenerator';
import { resolveFromParentTypename } from './resolveFromTypename';

type ResolverMap = { [key: string]: GraphQLFieldResolver<any, any> };

Expand Down Expand Up @@ -41,6 +42,16 @@ export default function addSimpleRoutingResolvers(
resolvers.Mutation = mutationResolvers;
}

// Add interface and union resolveType functions
const typeMap = schema.getTypeMap();
Object.keys(typeMap).forEach((typeName) => {
const type = typeMap[typeName];

if (type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType) {
type.resolveType = (parent) => resolveFromParentTypename(parent, schema);
}
});

return makeExecutableSchema({
typeDefs: printSchema(schema),
resolvers,
Expand Down
26 changes: 4 additions & 22 deletions src/stitching/mergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
} from 'graphql';
import TypeRegistry from './TypeRegistry';
import { SchemaLink } from './types';
import { resolveFromParentTypename } from './resolveFromTypename';

export const ROOT_SCHEMA = '__ROOT__';

Expand Down Expand Up @@ -214,25 +215,6 @@ function recreateCompositeType(
}
}

function resolveFromParentTypename(parent: any, schema: GraphQLSchema) {
const parentTypename: string = parent['__typename'];
if (!parentTypename) {
throw new Error(
'Did not fetch typename for object, unable to resolve interface.',
);
}

const resolvedType = schema.getType(parentTypename);

if (!(resolvedType instanceof GraphQLObjectType)) {
throw new Error(
'__typename did not match an object type: ' + parentTypename,
);
}

return resolvedType;
}

function fieldMapToFieldConfigMap(
fields: GraphQLFieldMap<any, any>,
registry: TypeRegistry,
Expand Down Expand Up @@ -329,7 +311,7 @@ function createForwardingResolver(
type = schema.getMutationType();
}
if (type) {
const document = createDocument(
const graphqlDoc: DocumentNode = createDocument(
registry,
schema,
type,
Expand All @@ -340,7 +322,7 @@ function createForwardingResolver(
info.operation.variableDefinitions,
);

const operationDefinition = document.definitions.find(
const operationDefinition = graphqlDoc.definitions.find(
({ kind }) => kind === Kind.OPERATION_DEFINITION,
);
let variableValues;
Expand All @@ -366,7 +348,7 @@ function createForwardingResolver(

const result = await execute(
schema,
document,
graphqlDoc,
info.rootValue,
context,
variableValues,
Expand Down
20 changes: 20 additions & 0 deletions src/stitching/resolveFromTypename.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { GraphQLObjectType, GraphQLSchema } from 'graphql';

export function resolveFromParentTypename(parent: any, schema: GraphQLSchema) {
const parentTypename: string = parent['__typename'];
if (!parentTypename) {
throw new Error(
'Did not fetch typename for object, unable to resolve interface.',
);
}

const resolvedType = schema.getType(parentTypename);

if (!(resolvedType instanceof GraphQLObjectType)) {
throw new Error(
'__typename did not match an object type: ' + parentTypename,
);
}

return resolvedType;
}
54 changes: 54 additions & 0 deletions src/test/testMergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,60 @@ query {
});
});

it('unions', async () => {
const mergedResult = await graphql(
mergedSchema,
`
query {
Booking_customerById(id: "c1") {
vehicle {
... on Car {
licensePlate
}
}
}
}
`,
);

console.log(mergedResult);
expect(mergedResult.errors).to.be.undefined;
expect(mergedResult).to.have.nested.property('data.firstProperty');
expect(mergedResult).to.have.nested.property('data.secondProperty');
expect(mergedResult).to.have.nested.property('data.booking');

expect(mergedResult.data).to.deep.equal({
firstProperty: {
id: 'p2',
name: 'Another great hotel',
bookings: [
{
id: 'b4',
customer: {
name: 'Exampler Customer',
},
},
],
},
secondProperty: {
id: 'p3',
name: 'BedBugs - The Affordable Hostel',
bookings: [],
},
booking: {
id: 'b1',
customer: {
name: 'Exampler Customer',
},

property: {
id: 'p1',
name: 'Super great hotel',
},
},
});
});

it('deep links', async () => {
const mergedResult = await graphql(
mergedSchema,
Expand Down
43 changes: 40 additions & 3 deletions src/test/testingSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,20 @@ export type Customer = {
email: string;
name: string;
address?: string;
vehicleId?: string;
};

export type Vehicle = {
id: string;
licensePlate?: string;
bikeType?: 'MOUNTAIN' | 'ROAD';
}

export const sampleData: {
Property: { [key: string]: Property };
Booking: { [key: string]: Booking };
Customer: { [key: string]: Customer };
Vehicle: { [key: string]: Vehicle };
} = {
Property: {
p1: {
Expand Down Expand Up @@ -90,11 +98,13 @@ export const sampleData: {
id: 'c1',
email: 'examplec1@example.com',
name: 'Exampler Customer',
vehicleId: 'v1',
},
c2: {
id: 'c2',
email: 'examplec2@example.com',
name: 'Joe Doe',
vehicleId: 'v2',
},
c3: {
id: 'c3',
Expand All @@ -103,6 +113,17 @@ export const sampleData: {
address: 'Esimerkikatu 1 A 77, 99999 Kyyjarvi',
},
},

Vehicle: {
v1: {
id: 'v1',
bikeType: 'MOUNTAIN'
},
v2: {
id: 'v2',
licensePlate: 'GRAPHQL'
}
}
};

const propertyTypeDefs = `
Expand Down Expand Up @@ -166,7 +187,7 @@ const bookingTypeDefs = `
type Bike {
id: ID!
type: BikeType
bikeType: BikeType
}
type Car {
Expand Down Expand Up @@ -251,18 +272,34 @@ const bookingResolvers: IResolvers = {
},

Booking: {
customer(parent) {
customer(parent: Booking) {
return sampleData.Customer[parent.customerId];
},
},

Customer: {
bookings(parent) {
bookings(parent: Customer) {
return values(sampleData.Booking).filter(
(booking: Booking) => booking.customerId === parent.id,
);
},
vehicle(parent: Customer) {
return sampleData.Vehicle[parent.vehicleId];
},
},

Vehicle: {
__resolveType(parent) {
console.log(parent);
if (parent.licensePlate) {
return 'Car';
} else if (parent.bikeType) {
return 'Bike';
} else {
throw new Error('Could not resolve Vehicle type');
}
}
}
};

export const propertySchema: GraphQLSchema = makeExecutableSchema({
Expand Down

0 comments on commit 5b3fe90

Please sign in to comment.