Skip to content

Commit

Permalink
feat(data): GraphQL Schema can now be retrieve via ApolloClient instance
Browse files Browse the repository at this point in the history
  • Loading branch information
charlypoly committed Apr 15, 2019
1 parent 8daa050 commit eb0b7e4
Show file tree
Hide file tree
Showing 11 changed files with 264 additions and 117 deletions.
2 changes: 1 addition & 1 deletion lib/core/__tests__/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ describe('Frontier Core', () => {
expect(form.getRegisteredFields()).toContain('todo.name');
expect(form.getRegisteredFields()).toContain('todo.completed');

expect(form.getFieldState('todo.name').value).toEqual('Write tests for Frontier Core')
expect(form.getFieldState('todo.name')!.value).toEqual('Write tests for Frontier Core')
})
})

Expand Down
2 changes: 1 addition & 1 deletion lib/core/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function validateWithSchema (schema: JSONSchema7): (values: object) => object |
const validator = ajv.compile(schema);
return function (values: object) {
const valid = validator(values);
return valid ? {} : formatErrors(validator.errors);
return valid ? {} : formatErrors(validator.errors || []);
}
}

Expand Down
93 changes: 51 additions & 42 deletions lib/data/__tests__/e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { schemaFromGraphQLProps } from '../graphql';

describe('Frontier Data GraphQl', () => {
describe('given a valid GraphQL mutation document', () => {
it('should return the proper Form Schema', () => {
it('should return the proper Form Schema', (done) => {
const schema = require('../../../fixtures/data/tests-jsonschema.json');

const mutation = gql`
Expand All @@ -14,32 +14,34 @@ describe('Frontier Data GraphQl', () => {
}
`;

expect(
schemaFromGraphQLProps({
mutation,
schema
})
).toEqual({
"type": "object",
"properties": {
"todo": {
"type": "object",
"properties": {
"completed": {
"type": "boolean"
schemaFromGraphQLProps({
mutation,
schema,
client: null as any
}).then(schema => {
expect(schema).toEqual({
"type": "object",
"properties": {
"todo": {
"type": "object",
"properties": {
"completed": {
"type": "boolean"
},
"name": {
"type": "string"
}
},
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
},
"required": [
"todo"
]
"required": [
"name"
]
}
},
"required": [
"todo"
]
})
done();
})
})
});
Expand All @@ -49,7 +51,7 @@ describe('Frontier Data GraphQl', () => {
jest.spyOn(global.console, 'warn')
});

it('should return an empty Form Schema and warn the developer', () => {
it('should return an empty Form Schema and warn the developer', (done) => {
const schema = require('../../../fixtures/data/tests-jsonschema.json');

const mutation = gql`
Expand All @@ -60,13 +62,16 @@ describe('Frontier Data GraphQl', () => {
}
`;

expect(
schemaFromGraphQLProps({
mutation,
schema
})
).toEqual({})
expect(global.console.warn).toHaveBeenCalledWith('please provide a mutation document, received a query document')
schemaFromGraphQLProps({
mutation,
schema,
client: null as any
}).then(schema => {
expect(schema).toEqual({})
expect(global.console.warn).toHaveBeenCalledWith('please provide a mutation document, received a query document')

done();
})
})
});

Expand All @@ -75,7 +80,7 @@ describe('Frontier Data GraphQl', () => {
jest.spyOn(global.console, 'warn')
});

it('should return an empty Form Schema and warn the developer', () => {
it('should return an empty Form Schema and warn the developer', (done) => {
const schema = require('../../../fixtures/data/tests-jsonschema.json');

const mutation = gql`
Expand All @@ -86,13 +91,17 @@ describe('Frontier Data GraphQl', () => {
}
`;

expect(
schemaFromGraphQLProps({
mutation,
schema
})
).toEqual({})
expect(global.console.warn).toHaveBeenCalledWith('Unknown mutation update_or_create_todo provided')

schemaFromGraphQLProps({
mutation,
schema,
client: null as any
}).then(schema => {
expect(schema).toEqual({})
expect(global.console.warn).toHaveBeenCalledWith('Unknown mutation update_or_create_todo provided')

done();
})
})
});

Expand Down
61 changes: 36 additions & 25 deletions lib/data/__tests__/schemaFromGraphQLProps.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import gql from 'graphql-tag';
import { schemaFromGraphQLProps } from '../graphql';
import ApolloClient from 'apollo-client';

describe('schemaFromGraphQLProps', () => {
beforeEach(() => {
Expand All @@ -11,15 +12,19 @@ describe('schemaFromGraphQLProps', () => {
});

describe('given a invalid GraphQL props', () => {
it('should return an `null`', () => {
it('should return an `null`', (done) => {
const props: any = {};

expect(schemaFromGraphQLProps(props)).toEqual(null);
schemaFromGraphQLProps(props).then(schema => {
expect(schema).toEqual(null);

done();
});
})
});

describe('given a `schema` and `mutation` GraphQL props', () => {
it('should return a valid From Schema', () => {
it('should return a valid From Schema', (done) => {
const props = {
mutation: gql`
mutation createTodo($todo: TodoInputType!) {
Expand All @@ -28,31 +33,37 @@ describe('schemaFromGraphQLProps', () => {
}
}
`,
schema: require('../../../fixtures/data/tests-jsonschema.json')
schema: require('../../../fixtures/data/tests-jsonschema.json'),
client: null as any
};

expect(schemaFromGraphQLProps(props)).toEqual({
"type": "object",
"properties": {
"todo": {
"type": "object",
"properties": {
"completed": {
"type": "boolean"
schemaFromGraphQLProps(props).then(schema => {
expect(schema).toEqual({
"type": "object",
"properties": {
"todo": {
"type": "object",
"properties": {
"completed": {
"type": "boolean"
},
"name": {
"type": "string"
}
},
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
},
"required": [
"todo"
]
})
"required": [
"name"
]
}
},
"required": [
"todo"
]
})

done();
});

})
});

Expand Down
36 changes: 23 additions & 13 deletions lib/data/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,40 @@
import { JSONSchema7 } from 'json-schema';
import { DocumentNode, FieldNode } from 'graphql';
import { omit, pick, reduce, cloneDeep, has, get } from 'lodash';
import { reduce, cloneDeep, has, get } from 'lodash';
import { ApolloClient } from "apollo-client";
import { introspectionQuery } from './introspectionQuery';
import { fromIntrospectionQuery } from "graphql-2-json-schema";

// Given a GQL client and a mutation, should return a JSON Schema including definitions and the mutation

export type GraphQLClient = { query: () => any };

export interface FrontierDataGraphQLProps {
mutation: DocumentNode;
client?: GraphQLClient; // ApolloClient<any>;
client: ApolloClient<any>;
schema?: JSONSchema7;
}

export type SchemaFromGraphQLPropsReturn = JSONSchema7 | null;
// Given GraphQL data props, return a valid form JSONSchema (or null)
export function schemaFromGraphQLProps(props: FrontierDataGraphQLProps): JSONSchema7 | null {
export function schemaFromGraphQLProps (props: FrontierDataGraphQLProps): Promise<SchemaFromGraphQLPropsReturn> {
if (props.mutation) {
if (props.schema) {
return buildFormSchema(props.schema, props.mutation);
return Promise.resolve(buildFormSchema(props.schema, props.mutation));
} else if (props.client) {
// TODO
return null;
return props.client.query({ query: introspectionQuery }).then(result => {
if (result.errors) {
console.log(`Unable to fetch GraphQL schema: ${result.errors}`);
return null;
} else {
return fromIntrospectionQuery(result.data) as JSONSchema7;
}
})
} else {
return null;
return Promise.resolve(null);
}
} else {
return null;
return Promise.resolve(null);
}
}

Expand Down Expand Up @@ -112,7 +122,7 @@ export function schemaFromGraphQLProps(props: FrontierDataGraphQLProps): JSONSch
// "end": 137
// }
// }
export function getMutationNameFromDocumentNode(mutation: DocumentNode): string | null {
export function getMutationNameFromDocumentNode (mutation: DocumentNode): string | null {
if (mutation.definitions.length > 1) {
console.warn("please provide 1 mutation document")
return null;
Expand All @@ -139,19 +149,19 @@ export function getMutationNameFromDocumentNode(mutation: DocumentNode): string
}

// Given a GraphQL schema JSON Schema and a mutation, return a form schema
export function buildFormSchema(schema: JSONSchema7, mutation: DocumentNode): JSONSchema7 {
export function buildFormSchema (schema: JSONSchema7, mutation: DocumentNode): JSONSchema7 {
const mutationName = getMutationNameFromDocumentNode(mutation);
if (!mutationName) {
return {};
}

const mutationSchema = (schema.properties.Mutation as JSONSchema7).properties[mutationName] as JSONSchema7;
const mutationSchema = (schema.properties!.Mutation as JSONSchema7).properties![mutationName] as JSONSchema7;
if (!mutationSchema) {
console.warn(`Unknown mutation ${mutationName} provided`)
return {};
}

const args = mutationSchema.properties.arguments as JSONSchema7;
const args = mutationSchema.properties!.arguments as JSONSchema7;
if (args && args.properties && Object.keys(args.properties).length > 0) {
return formPropertiesReducer(args, schema);
} else {
Expand All @@ -160,7 +170,7 @@ export function buildFormSchema(schema: JSONSchema7, mutation: DocumentNode): JS
}
}

function formPropertiesReducer(schema, referenceSchema): JSONSchema7 {
function formPropertiesReducer (schema, referenceSchema): JSONSchema7 {
return {
type: 'object',
properties: reduce<JSONSchema7, { [k: string]: any }>(
Expand Down
Loading

0 comments on commit eb0b7e4

Please sign in to comment.