From b6f66849118a26902fdcac21f0e361020796a00b Mon Sep 17 00:00:00 2001 From: Andras Toth Date: Fri, 6 Nov 2015 08:25:59 +0100 Subject: [PATCH] fix(schema): add arguments to connections based on the fields of the type --- src/e2e.spec.js | 22 ++++++++++++++++++++++ src/query/query.js | 4 +--- src/schema/schema.js | 27 +++++++++++---------------- src/type/type.js | 42 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/src/e2e.spec.js b/src/e2e.spec.js index 54e4f2d..5146fca 100644 --- a/src/e2e.spec.js +++ b/src/e2e.spec.js @@ -223,6 +223,28 @@ describe('e2e', () => { {node: {name: 'Bar'}} ]); }); + + it('should filter connections by arguments', async function Test() { + const result = await graphql(schema, `{ + viewer { + users(name: "Foo") { + count + edges { + node { + name + } + } + } + } + }`); + + const {users} = result.data.viewer; + expect(users.count).to.be.eql(1); + + expect(users.edges).to.containSubset([ + {node: {name: 'Foo'}} + ]); + }); }); describe('mutations', () => { diff --git a/src/query/query.js b/src/query/query.js index 4b6c7bc..1e8b766 100644 --- a/src/query/query.js +++ b/src/query/query.js @@ -255,7 +255,7 @@ async function connectionFromModel(graffitiModel, args, info) { return emptyConnection(); } - const {before, after, first, last, id} = args; + const {before, after, first, last, id, ...selector} = args; const begin = getId(after); const end = getId(before); @@ -263,8 +263,6 @@ async function connectionFromModel(graffitiModel, args, info) { const offset = (first - last) || 0; const limit = last || first; - const selector = {}; - if (id) { selector.id = id; } diff --git a/src/schema/schema.js b/src/schema/schema.js index ec621e2..0aa67e2 100644 --- a/src/schema/schema.js +++ b/src/schema/schema.js @@ -5,7 +5,6 @@ import { GraphQLID, GraphQLObjectType, GraphQLSchema, - GraphQLScalarType, GraphQLBoolean, GraphQLFloat } from 'graphql'; @@ -16,7 +15,13 @@ import { globalIdField } from 'graphql-relay'; import {getModels} from './../model'; -import {getTypes, GraphQLViewer, nodeInterface} from './../type'; +import { + getTypes, + GraphQLViewer, + nodeInterface, + getTypeFields, + getArguments +} from './../type'; import { idToCursor, getIdFetcher, @@ -56,17 +61,7 @@ function getPluralQueryField(graffitiModel, type) { return { [pluralName]: { type: new GraphQLList(type), - args: reduce(type._typeConfig.fields(), (args, field) => { - if (field.type instanceof GraphQLNonNull && field.name !== 'id') { - field.type = field.type.ofType; - } - - if (field.type instanceof GraphQLScalarType) { - args[field.name] = field; - } - - return args; - }, { + args: getArguments(type, { id: { type: new GraphQLList(GraphQLID), description: `The ID of a ${name}` @@ -100,7 +95,7 @@ function getConnectionField(graffitiModel, type) { return { [pluralName]: { - args: connectionArgs, + args: getArguments(type, connectionArgs), type: connectionType, resolve: (rootValue, args, info) => connectionFromModel(graffitiModel, args, info) } @@ -110,7 +105,7 @@ function getConnectionField(graffitiModel, type) { function getMutationField(graffitiModel, type, viewer) { const {name} = type; - const fields = type._typeConfig.fields(); + const fields = getTypeFields(type); const inputFields = reduce(fields, (inputFields, field) => { if (field.type instanceof GraphQLObjectType) { if (field.type.name.endsWith('Connection')) { @@ -122,7 +117,7 @@ function getMutationField(graffitiModel, type, viewer) { // TODO support objects // else { - // args = {...args, ...field.type._typeConfig.fields()}; + // args = {...args, ...getTypeFields(field.type)}; // } } diff --git a/src/type/type.js b/src/type/type.js index 2c577aa..4aee184 100644 --- a/src/type/type.js +++ b/src/type/type.js @@ -1,5 +1,8 @@ -import {reduce, forEach} from 'lodash'; - +import { + reduce, + forEach, + isFunction +} from 'lodash'; import { globalIdField, connectionArgs, @@ -13,7 +16,8 @@ import { GraphQLID, GraphQLList, GraphQLObjectType, - GraphQLNonNull + GraphQLNonNull, + GraphQLScalarType } from 'graphql/type'; import GraphQLDate from './custom/date'; import GraphQLBuffer from './custom/buffer'; @@ -63,6 +67,30 @@ function stringToGraphQLType(type) { } } +function getTypeFields(type) { + const fields = type._typeConfig.fields; + return isFunction(fields) ? fields() : fields; +} + +function setTypeFields(type, fields) { + type._typeConfig.fields = () => fields; +} + +function getArguments(type, args = {}) { + const fields = getTypeFields(type); + return reduce(fields, (args, field) => { + if (field.type instanceof GraphQLNonNull && field.name !== 'id') { + field.type = field.type.ofType; + } + + if (field.type instanceof GraphQLScalarType) { + args[field.name] = field; + } + + return args; + }, args); +} + // holds references to fields that later has to be resolved const resolveReference = {}; @@ -149,7 +177,7 @@ function getTypes(graffitiModels) { forEach(resolveReference, (fields, typeName) => { const type = types[typeName]; if (type) { - const typeFields = type._typeConfig.fields(); + const typeFields = getTypeFields(type); forEach(fields, (field, fieldName) => { if (field.args === connectionArgs) { // it's a connection @@ -167,7 +195,7 @@ function getTypes(graffitiModels) { typeFields[fieldName] = field; }); - type._typeConfig.fields = () => typeFields; + setTypeFields(type, typeFields); } }); @@ -181,5 +209,7 @@ export default { getType, getTypes, addType, - nodeInterface + nodeInterface, + getTypeFields, + getArguments };