Skip to content

Commit 4e312c5

Browse files
committed
working on passing options for helpers via resolver generators
1 parent b630ca1 commit 4e312c5

File tree

18 files changed

+253
-100
lines changed

18 files changed

+253
-100
lines changed

src/definition.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,36 @@ export type ResolverMWResolveFn = _ResolverMWResolveFn;
9191
export type ExtendedResolveParams = ResolveParams & {
9292
query: MongooseQuery,
9393
};
94+
95+
96+
// HELPERS OPTIONS
97+
98+
export type filterHelperArgsOpts = {
99+
filterTypeName?: string,
100+
isRequired?: boolean,
101+
onlyIndexed?: boolean,
102+
model?: MongooseModelT,
103+
requiredFields?: string | string[],
104+
};
105+
106+
export type sortHelperArgsOpts = {
107+
sortTypeName?: string,
108+
};
109+
110+
export type inputHelperArgsOpts = {
111+
inputTypeName?: string,
112+
removeFields?: string | string[],
113+
requiredFields?: string | string[],
114+
isRequired?: boolean,
115+
};
116+
117+
export type limitHelperArgsOpts = {
118+
defaultValue?: number,
119+
};
120+
121+
export type genResolverOpts = {
122+
filter?: filterHelperArgsOpts,
123+
sort?: sortHelperArgsOpts,
124+
input?: inputHelperArgsOpts,
125+
limit?: limitHelperArgsOpts,
126+
}

src/resolvers/__tests__/findOne-test.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ import { expect } from 'chai';
44
import { UserModel } from '../../__mocks__/userModel.js';
55
import findOne from '../findOne';
66
import Resolver from '../../../../graphql-compose/src/resolver/resolver';
7-
import { GraphQLObjectType } from 'graphql';
7+
import { convertModelToGraphQL } from '../../fieldsConverter';
8+
import { GraphQLNonNull } from 'graphql';
89

9-
const UserType = new GraphQLObjectType({
10-
name: 'MockUserType',
11-
});
10+
const UserType = convertModelToGraphQL(UserModel, 'User');
1211

1312
describe('findOne() ->', () => {
1413
let user1;
@@ -52,6 +51,18 @@ describe('findOne() ->', () => {
5251
expect(resolver.hasArg('filter')).to.be.true;
5352
});
5453

54+
it('should have `filter` arg only with indexed fields', async () => {
55+
const result = findOne(UserModel, UserType, { filter: { onlyIndexed: true } });
56+
const filterFields = result.args.filter.type._typeConfig.fields();
57+
expect(filterFields).all.keys(['_id', 'name', 'employment']);
58+
});
59+
60+
it('should have `filter` arg with required `name` field', async () => {
61+
const result = findOne(UserModel, UserType, { filter: { requiredFields: 'name' } });
62+
const filterFields = result.args.filter.type._typeConfig.fields();
63+
expect(filterFields).deep.property('name.type').instanceof(GraphQLNonNull);
64+
});
65+
5566
it('should have `skip` arg', () => {
5667
const resolver = findOne(UserModel, UserType);
5768
expect(resolver.hasArg('skip')).to.be.true;

src/resolvers/count.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,28 @@ import type {
55
MongooseModelT,
66
GraphQLObjectType,
77
ExtendedResolveParams,
8+
genResolverOpts,
89
} from '../definition';
910
import Resolver from '../../../graphql-compose/src/resolver/resolver';
1011
import { GraphQLInt } from 'graphql';
1112

12-
import { filterHelperArgsGen, filterHelper } from './helpers/filter';
13+
import { filterHelperArgs, filterHelper } from './helpers/filter';
1314

14-
export default function count(model: MongooseModelT, gqType: GraphQLObjectType): Resolver {
15+
16+
export default function count(
17+
model: MongooseModelT,
18+
gqType: GraphQLObjectType,
19+
opts?: genResolverOpts,
20+
): Resolver {
1521
return new Resolver({
1622
outputType: GraphQLInt,
1723
name: 'count',
1824
kind: 'query',
1925
args: {
20-
...filterHelperArgsGen(model, {
26+
...filterHelperArgs(gqType, {
2127
filterTypeName: `Filter${gqType.name}Input`,
28+
model,
29+
...(opts && opts.filter),
2230
}),
2331
},
2432
resolve: (resolveParams : ExtendedResolveParams) => {

src/resolvers/createOne.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
/* @flow */
22
/* eslint-disable no-param-reassign */
3-
import { inputHelperArgsGen } from './helpers/input';
3+
import { inputHelperArgs } from './helpers/input';
44
import { GraphQLObjectType } from 'graphql';
55
import GraphQLMongoID from '../types/mongoid';
66

77
import type {
88
MongooseModelT,
99
ExtendedResolveParams,
10+
genResolverOpts,
1011
} from '../definition';
1112
import Resolver from '../../../graphql-compose/src/resolver/resolver';
1213

14+
1315
export default function createOne(
1416
model: MongooseModelT,
1517
gqType: GraphQLObjectType,
18+
opts?: genResolverOpts,
1619
): Resolver {
1720
const resolver = new Resolver({
1821
name: 'createOne',
@@ -32,10 +35,11 @@ export default function createOne(
3235
},
3336
}),
3437
args: {
35-
...inputHelperArgsGen(gqType, {
38+
...inputHelperArgs(gqType, {
3639
inputTypeName: `CreateOne${gqType.name}Input`,
3740
removeFields: ['id', '_id'],
3841
isRequired: true,
42+
...(opts && opts.input),
3943
}),
4044
},
4145
resolve: (resolveParams: ExtendedResolveParams) => {

src/resolvers/findById.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
MongooseModelT,
55
GraphQLObjectType,
66
ExtendedResolveParams,
7+
genResolverOpts,
78
} from '../definition';
89
import Resolver from '../../../graphql-compose/src/resolver/resolver';
910

@@ -14,7 +15,11 @@ import GraphQLMongoID from '../types/mongoid';
1415

1516
import { projectionHelper } from './helpers/projection';
1617

17-
export default function findById(model: MongooseModelT, gqType: GraphQLObjectType): Resolver {
18+
export default function findById(
19+
model: MongooseModelT,
20+
gqType: GraphQLObjectType,
21+
opts?: genResolverOpts // eslint-disable-line no-unused-vars
22+
): Resolver {
1823
return new Resolver({
1924
outputType: gqType,
2025
name: 'findById',

src/resolvers/findByIds.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
MongooseModelT,
55
GraphQLObjectType,
66
ExtendedResolveParams,
7+
genResolverOpts,
78
} from '../definition';
89
import Resolver from '../../../graphql-compose/src/resolver/resolver';
910
import mongoose from 'mongoose';
@@ -15,10 +16,14 @@ import {
1516
import GraphQLMongoID from '../types/mongoid';
1617

1718
import { limitHelperArgs, limitHelper } from './helpers/limit';
18-
import { sortHelperArgsGen, sortHelper } from './helpers/sort';
19+
import { sortHelperArgs, sortHelper } from './helpers/sort';
1920
import { projectionHelper } from './helpers/projection';
2021

21-
export default function findByIds(model: MongooseModelT, gqType: GraphQLObjectType): Resolver {
22+
export default function findByIds(
23+
model: MongooseModelT,
24+
gqType: GraphQLObjectType,
25+
opts?: genResolverOpts
26+
): Resolver {
2227
return new Resolver({
2328
outputType: new GraphQLList(gqType),
2429
name: 'findByIds',
@@ -28,9 +33,12 @@ export default function findByIds(model: MongooseModelT, gqType: GraphQLObjectTy
2833
name: '_ids',
2934
type: new GraphQLNonNull(new GraphQLList(GraphQLMongoID)),
3035
},
31-
...limitHelperArgs,
32-
...sortHelperArgsGen(model, {
36+
...limitHelperArgs({
37+
...(opts && opts.limit),
38+
}),
39+
...sortHelperArgs(model, {
3340
sortTypeName: `Sort${gqType.name}Input`,
41+
...(opts && opts.sort),
3442
}),
3543
},
3644
resolve: (resolveParams : ExtendedResolveParams) => {

src/resolvers/findMany.js

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
MongooseModelT,
66
GraphQLObjectType,
77
ExtendedResolveParams,
8+
genResolverOpts,
89
} from '../definition';
910
import Resolver from '../../../graphql-compose/src/resolver/resolver';
1011
import {
@@ -13,23 +14,33 @@ import {
1314

1415
import { skipHelperArgs, skipHelper } from './helpers/skip';
1516
import { limitHelperArgs, limitHelper } from './helpers/limit';
16-
import { filterHelperArgsGen, filterHelper } from './helpers/filter';
17-
import { sortHelperArgsGen, sortHelper } from './helpers/sort';
17+
import { filterHelperArgs, filterHelper } from './helpers/filter';
18+
import { sortHelperArgs, sortHelper } from './helpers/sort';
1819
import { projectionHelper } from './helpers/projection';
1920

20-
export default function findMany(model: MongooseModelT, gqType: GraphQLObjectType): Resolver {
21+
22+
export default function findMany(
23+
model: MongooseModelT,
24+
gqType: GraphQLObjectType,
25+
opts?: genResolverOpts,
26+
): Resolver {
2127
return new Resolver({
2228
outputType: new GraphQLList(gqType),
2329
name: 'findMany',
2430
kind: 'query',
2531
args: {
26-
...filterHelperArgsGen(model, {
32+
...filterHelperArgs(gqType, {
2733
filterTypeName: `Filter${gqType.name}Input`,
34+
model,
35+
...(opts && opts.filter),
36+
}),
37+
...skipHelperArgs(),
38+
...limitHelperArgs({
39+
...(opts && opts.limit),
2840
}),
29-
...skipHelperArgs,
30-
...limitHelperArgs,
31-
...sortHelperArgsGen(model, {
41+
...sortHelperArgs(model, {
3242
sortTypeName: `Sort${gqType.name}Input`,
43+
...(opts && opts.sort),
3344
}),
3445
},
3546
resolve: (resolveParams : ExtendedResolveParams) => {

src/resolvers/findOne.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,37 @@
44
import Resolver from '../../../graphql-compose/src/resolver/resolver';
55

66
import { skipHelperArgs, skipHelper } from './helpers/skip';
7-
import { filterHelperArgsGen, filterHelper } from './helpers/filter';
8-
import { sortHelperArgsGen, sortHelper } from './helpers/sort';
7+
import { filterHelperArgs, filterHelper } from './helpers/filter';
8+
import { sortHelperArgs, sortHelper } from './helpers/sort';
99
import { projectionHelper } from './helpers/projection';
1010

1111
import type {
1212
MongooseModelT,
1313
GraphQLObjectType,
1414
ExtendedResolveParams,
15+
genResolverOpts,
1516
} from '../definition';
1617

18+
1719
export default function findOne(
1820
model: MongooseModelT,
19-
gqType: GraphQLObjectType
21+
gqType: GraphQLObjectType,
22+
opts?: genResolverOpts,
2023
): Resolver {
2124
return new Resolver({
2225
outputType: gqType,
2326
name: 'findOne',
2427
kind: 'query',
2528
args: {
26-
...filterHelperArgsGen(model, {
29+
...filterHelperArgs(gqType, {
2730
filterTypeName: `Filter${gqType.name}Input`,
31+
model,
32+
...(opts && opts.filter),
2833
}),
29-
...skipHelperArgs,
30-
...sortHelperArgsGen(model, {
34+
...skipHelperArgs(),
35+
...sortHelperArgs(model, {
3136
sortTypeName: `Sort${gqType.name}Input`,
37+
...(opts && opts.sort),
3238
}),
3339
},
3440
resolve: (resolveParams : ExtendedResolveParams) => {

src/resolvers/helpers/filter.js

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,67 @@
11
/* @flow */
2+
/* eslint-disable no-use-before-define */
23

3-
import { GraphQLInt, GraphQLInputObjectType, GraphQLNonNull } from 'graphql/type';
4+
import TypeComposer from '../../../../graphql-compose/src/typeComposer';
5+
import { GraphQLNonNull } from 'graphql/type';
6+
import getIndexesFromModel from '../../utils/getIndexesFromModel';
47
import { toDottedObject } from '../../utils';
58
import type {
69
GraphQLFieldConfigArgumentMap,
710
ExtendedResolveParams,
811
MongooseModelT,
12+
GraphQLObjectType,
13+
filterHelperArgsOpts,
914
} from '../../definition';
1015

11-
export type filterHelperArgsGenOpts = {
12-
filterTypeName: string,
13-
isRequired?: boolean,
14-
};
15-
16-
export const filterHelperArgsGen = (
17-
model: MongooseModelT,
18-
opts: filterHelperArgsGenOpts,
16+
export const filterHelperArgs = (
17+
gqType: GraphQLObjectType,
18+
opts: filterHelperArgsOpts,
1919
): GraphQLFieldConfigArgumentMap => {
2020
if (!opts.filterTypeName) {
2121
throw new Error('You should provide `filterTypeName` in options.');
2222
}
23+
const composer = new TypeComposer(gqType);
24+
25+
const removeFields = [];
26+
if (opts.removeFields) {
27+
if (Array.isArray(opts.removeFields)) {
28+
removeFields.push(...opts.removeFields);
29+
} else {
30+
removeFields.push(opts.removeFields);
31+
}
32+
}
33+
34+
if (opts.onlyIndexed) {
35+
if (!opts.model) {
36+
throw new Error('You should provide `model` in options with mongoose model '
37+
+ 'for deriving index fields.');
38+
}
39+
40+
const indexedFieldNames = getIndexedFieldNames(opts.model);
41+
Object.keys(composer.getFields()).forEach(fieldName => {
42+
if (indexedFieldNames.indexOf(fieldName) === -1) {
43+
removeFields.push(fieldName);
44+
}
45+
});
46+
}
2347

24-
const filterType = new GraphQLInputObjectType({
25-
name: opts.filterTypeName,
26-
fields: {
27-
age: {
28-
name: 'age',
29-
type: GraphQLInt, // TODO just mock, should be changed in future
30-
},
31-
},
32-
});
48+
49+
const inputComposer = composer.getInputTypeComposer().clone(opts.filterTypeName);
50+
inputComposer.removeField(removeFields);
51+
52+
if (opts.requiredFields) {
53+
inputComposer.makeFieldsRequired(opts.requiredFields);
54+
}
3355

3456
return {
3557
filter: {
3658
name: 'filter',
37-
type: opts.isRequired ? new GraphQLNonNull(filterType) : filterType,
38-
description: 'Filter by indexed fields',
59+
type: opts.isRequired
60+
? new GraphQLNonNull(inputComposer.getType())
61+
: inputComposer.getType(),
62+
description: opts.onlyIndexed
63+
? 'Filter only by indexed fields'
64+
: 'Filter by fields',
3965
},
4066
};
4167
};
@@ -46,3 +72,15 @@ export function filterHelper(resolveParams: ExtendedResolveParams): void {
4672
resolveParams.query = resolveParams.query.where(toDottedObject(filter)); // eslint-disable-line
4773
}
4874
}
75+
76+
export function getIndexedFieldNames(model: MongooseModelT): string[] {
77+
const indexes = getIndexesFromModel(model);
78+
79+
const fieldNames = [];
80+
indexes.forEach((indexData) => {
81+
const keys = Object.keys(indexData);
82+
fieldNames.push(keys[0]);
83+
});
84+
85+
return fieldNames;
86+
}

0 commit comments

Comments
 (0)