Skip to content

Commit

Permalink
Revert "Only get Selected fields for 'query' calls" (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
ianhowe76 authored Jun 5, 2018
1 parent 05aa1e1 commit 267dbee
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 126 deletions.
4 changes: 0 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,3 @@
/coverage
/dump
/dev/config.json
.idea
yarn.lock
package-lock.json
.DS_store
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
},
"dependencies": {
"dataloader": "^1.3.0",
"graphql-fields": "^1.0.2",
"https-proxy-agent": "^2.1.1",
"lodash.camelcase": "^4.3.0",
"lodash.chunk": "^4.2.0",
Expand Down
15 changes: 6 additions & 9 deletions src/backref-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,15 @@ function createBackrefFieldConfig (backref, Type) {
skip: {type: GraphQLInt},
limit: {type: GraphQLInt},
},
resolve: (entryId, args, ctx, info) => {
resolve: (entryId, args, ctx) => {
let q = `fields.${backref.fieldId}.sys.id[in]=${entryId}`;
if (args.q) q = q + `&${args.q}`;

return ctx.entryLoader.query(
backref.ctId, {
q,
skip: args.skip,
limit: args.limit,
},
info
);
return ctx.entryLoader.query(backref.ctId, {
q,
skip: args.skip,
limit: args.limit,
})
}
};
}
Expand Down
27 changes: 2 additions & 25 deletions src/entry-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,24 @@ const _get = require('lodash.get');
const chunk = require('lodash.chunk');
const qs = require('querystring');
const DataLoader = require('dataloader');
const graphqlFields = require('graphql-fields');

const INCLUDE_DEPTH = 1;
const CHUNK_SIZE = 70;
// Chunk size may be unreliable. If wrong, may get "Bad Request" from graphQL
const DEFAULT_LIMIT = 50;
const MAX_LIMIT = 1000;
const FORBIDDEN_QUERY_PARAMS = ['skip', 'limit', 'include', 'content_type', 'locale'];
const MAX_FIELDS = 50;
const IGNORE_FIELDS = ['sys','_backrefs', '__typename'];

module.exports = createEntryLoader;

const getSelectedFields = info => {
if (!info) {
return null;
}
const topLevelFields =
Object.keys(graphqlFields(info)).filter(key => !IGNORE_FIELDS.includes(key));

if (topLevelFields.length < 1 || topLevelFields.length > MAX_FIELDS) {
// There is a limit to the number of fields we can select. If too many get everything
return null;
}
const contentfulFields = topLevelFields.map(fieldKey => `fields.${fieldKey}`).join(',');

return `sys,${contentfulFields}`;
};

function createEntryLoader (http) {
const loader = new DataLoader(load);
const assets = {};

return {
get: getOne,
getMany: loader.loadMany.bind(loader),
query: (ctId, args, info) => query(ctId, args, info).then(res => res.items),
query: (ctId, args) => query(ctId, args).then(res => res.items),
count: (ctId, args) => query(ctId, args).then(res => res.total),
queryAll,
getIncludedAsset: id => assets[id],
Expand Down Expand Up @@ -79,7 +60,7 @@ function createEntryLoader (http) {
});
}

function query (ctId, {q = '', skip = 0, limit = DEFAULT_LIMIT} = {}, info) {
function query (ctId, {q = '', skip = 0, limit = DEFAULT_LIMIT} = {}) {
const parsed = qs.parse(q);
Object.keys(parsed).forEach(key => {
if (FORBIDDEN_QUERY_PARAMS.includes(key)) {
Expand All @@ -94,10 +75,6 @@ function createEntryLoader (http) {
content_type: ctId
}, parsed);

const selectedFields = getSelectedFields(info);
if (selectedFields) {
params.select = selectedFields;
}
return http.get('/entries', params).then(prime);
}

Expand Down
4 changes: 2 additions & 2 deletions src/field-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ module.exports = {
function createFieldConfig (Type, field, resolveFn) {
return {
type: Type,
resolve: (entity, _, ctx, info) => {
resolve: (entity, _, ctx) => {
const fieldValue = _get(entity, ['fields', field.id], NOTHING);
if (fieldValue !== NOTHING) {
return resolveFn ? resolveFn(fieldValue, ctx, info) : fieldValue;
return resolveFn ? resolveFn(fieldValue, ctx) : fieldValue;
}
}
};
Expand Down
8 changes: 4 additions & 4 deletions src/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@ function createQueryFields (spaceGraph) {
limit: {type: GraphQLInt},
ids: {type: new GraphQLList(IDType)},
},
resolve: (_, args, ctx, info) => {
const {ids} = args;
resolve: (_, args, ctx) => {
const {ids} = args
if (ids) {
return ctx.entryLoader.getMany(ids, info)
return ctx.entryLoader.getMany(ids)
.then(objs => objs.filter(obj => obj && obj.sys.contentType.sys.id === ct.id))
} else {
return ctx.entryLoader.query(ct.id, args, info);
return ctx.entryLoader.query(ct.id, args)
}
}
};
Expand Down
57 changes: 0 additions & 57 deletions test/entry-loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,63 +65,6 @@ test('entry-loader: querying entries', function (t) {
});
});

test('entry-loader: querying entries with resolve Info', function (t) {
t.plan(3);
const {httpStub, loader} = prepare();
const resolveInfo = {
fieldNodes: [{
selectionSet: {
selections: [
{ name: { value: 'title' } },
{ name: { value: 'slug' } },
]
}
}],
};
loader.query('ctid', {q: 'fields.someNum=123&fields.test[exists]=true'}, resolveInfo)
.then(res => {
t.deepEqual(res, ITEMS);
t.equal(httpStub.get.callCount, 1);
t.deepEqual(httpStub.get.lastCall.args, ['/entries', {
skip: 0,
limit: 50,
include: 1,
content_type: 'ctid',
'fields.someNum': '123',
'fields.test[exists]': 'true',
select: 'sys,fields.title,fields.slug',
}]);
});
});

test('entry-loader: querying entries with only sys field requested', function (t) {
t.plan(3);
const {httpStub, loader} = prepare();
const resolveInfo = {
fieldNodes: [{
selectionSet: {
selections: [
{ name: { value: 'sys' } },
{ name: { value: '__typename' } },
]
}
}],
};
loader.query('ctid', {q: 'fields.someNum=123&fields.test[exists]=true'}, resolveInfo)
.then(res => {
t.deepEqual(res, ITEMS);
t.equal(httpStub.get.callCount, 1);
t.deepEqual(httpStub.get.lastCall.args, ['/entries', {
skip: 0,
limit: 50,
include: 1,
content_type: 'ctid',
'fields.someNum': '123',
'fields.test[exists]': 'true',
}]);
});
});

test('entry-loader: counting entries', function (t) {
t.plan(3);
const {httpStub, loader} = prepare();
Expand Down
30 changes: 6 additions & 24 deletions test/schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ const {
GraphQLSchema,
GraphQLObjectType
} = require('graphql');
const graphqlFields = require('graphql-fields');

const {
createSchema,
Expand Down Expand Up @@ -70,13 +69,11 @@ test('schema: querying generated schema', function (t) {
.then(res => [entryLoader, res]);
};

t.plan(30);
t.plan(22);

testQuery('{ posts { title } }', {query: sinon.stub().resolves([post])})
.then(([entryLoader, res]) => {
t.deepEqual(entryLoader.query.firstCall.args[0], 'postct');
t.deepEqual(entryLoader.query.firstCall.args[1], {});
t.deepEqual(graphqlFields(entryLoader.query.firstCall.args[2]), { title: {} });
t.deepEqual(entryLoader.query.firstCall.args, ['postct', {}]);
t.equal(res.errors, undefined);
t.deepEqual(res.data.posts, [{title: 'Hello world'}]);
});
Expand All @@ -85,12 +82,10 @@ test('schema: querying generated schema', function (t) {
'{ categories(skip: 2, limit: 3, q: "fields.name=test") { name } }',
{query: sinon.stub().resolves([category])}
).then(([entryLoader, res]) => {
t.deepEqual(entryLoader.query.firstCall.args[0], 'catct');
t.deepEqual(
entryLoader.query.firstCall.args[1],
{skip: 2, limit: 3, q: 'fields.name=test'}
entryLoader.query.firstCall.args,
['catct', {skip: 2, limit: 3, q: 'fields.name=test'}]
);
t.deepEqual(graphqlFields(entryLoader.query.firstCall.args[2]), { name: {} });
t.equal(res.errors, undefined);
t.deepEqual(res.data.categories, [{name: 'test'}]);
});
Expand All @@ -110,9 +105,7 @@ test('schema: querying generated schema', function (t) {
'{ posts { title } category(id: "c1") { name } }',
{query: sinon.stub().resolves([post]), get: sinon.stub().resolves(category)}
).then(([entryLoader, res]) => {
t.deepEqual(entryLoader.query.firstCall.args[0], 'postct');
t.deepEqual(entryLoader.query.firstCall.args[1], {});
t.deepEqual(graphqlFields(entryLoader.query.firstCall.args[2]), { title: {} });
t.deepEqual(entryLoader.query.firstCall.args, ['postct', {}]);
t.deepEqual(entryLoader.get.firstCall.args, ['c1', 'catct']);
t.equal(res.errors, undefined);
t.deepEqual(res.data, {posts: [{title: 'Hello world'}], category: {name: 'test'}});
Expand All @@ -123,18 +116,7 @@ test('schema: querying generated schema', function (t) {
{query: sinon.stub().onCall(0).resolves([category]).onCall(1).resolves([post])}
).then(([entryLoader, res]) => {
t.equal(res.errors, undefined);
t.deepEqual(entryLoader.query.firstCall.args[0], 'catct');
t.deepEqual(entryLoader.query.firstCall.args[1], {});
t.deepEqual(
graphqlFields(entryLoader.query.firstCall.args[2]),
{
_backrefs: {
posts__via__category: {
title: {},
},
},
}
);
t.deepEqual(entryLoader.query.firstCall.args, ['catct', {}]);
t.deepEqual(entryLoader.query.lastCall.args[0], 'postct');
t.deepEqual(res.data, {categories: [{_backrefs: {posts__via__category: [{title: 'Hello world'}]}}]});
});
Expand Down

0 comments on commit 267dbee

Please sign in to comment.