Skip to content

Commit adeaeb0

Browse files
committed
feat(createOne, updateById, updateOne): Pass resolveParams to beforeRecordMutate callback
Now you may made some context spicific checks right before apply updates to the document. Eg. check ownership User.find('$updateOne').wrapResolve(next => rp => { rp.beforeRecordMutate = (doc, rp) => { return rp.context.userId === doc.userId ? doc : Promise.reject(new Error('Access denied. You should be owner of this record')); } return next(rp); });
1 parent eaa5fc6 commit adeaeb0

File tree

9 files changed

+44
-28
lines changed

9 files changed

+44
-28
lines changed

.eslintrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"no-underscore-dangle": 0,
66
"no-unused-expressions": 0,
77
"arrow-body-style": 0,
8-
"import/no-extraneous-dependencies": ["error", {"devDependencies": ["*-test.js"]}]
8+
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}]
99
},
1010
"env": {
1111
"mocha": true

src/definition.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
/* eslint-disable */
33

44
import type { TypeComposer } from 'graphql-compose';
5-
import type { ProjectionType } from 'graphql-compose/lib/definition';
65
import type { connectionSortMapOpts as _connectionSortMapOpts} from 'graphql-compose-connection/lib/definition';
76
export type connectionSortMapOpts = _connectionSortMapOpts;
87

@@ -86,7 +85,6 @@ export type MongoseDocument = {
8685
import type {
8786
GraphQLObjectType as _GraphQLObjectType,
8887
GraphQLOutputType as _GraphQLOutputType,
89-
InputObjectConfigFieldMap as _InputObjectConfigFieldMap,
9088
ResolveParams as _ResolveParams,
9189
GraphQLFieldConfigArgumentMap as _GraphQLFieldConfigArgumentMap,
9290
ResolverMWResolveFn as _ResolverMWResolveFn,
@@ -95,16 +93,14 @@ import type {
9593

9694
export type GraphQLObjectType = _GraphQLObjectType;
9795
export type GraphQLOutputType = _GraphQLOutputType;
98-
export type InputObjectConfigFieldMap = _InputObjectConfigFieldMap;
9996
export type GraphQLFieldConfigArgumentMap = _GraphQLFieldConfigArgumentMap;
10097
export type ResolveParams = _ResolveParams;
10198
export type GraphQLResolveInfo = _GraphQLResolveInfo;
10299
export type ResolverMWResolveFn = _ResolverMWResolveFn;
103100
export type ExtendedResolveParams = ResolveParams & {
104101
query: MongooseQuery,
105-
projection: ProjectionType,
106-
beforeQuery(query: mixed): Promise<*>,
107-
beforeRecordMutate(record: mixed): Promise<*>,
102+
beforeQuery?: (query: mixed, rp: ExtendedResolveParams) => Promise<*>,
103+
beforeRecordMutate?: (record: mixed, rp: ExtendedResolveParams) => Promise<*>,
108104
};
109105

110106

src/resolvers/__tests__/createOne-test.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* @flow */
2+
/* eslint-disable no-param-reassign */
23

34
import { expect } from 'chai';
45
import { GraphQLNonNull, GraphQLObjectType } from 'graphql';
@@ -96,16 +97,19 @@ describe('createOne() ->', () => {
9697
expect(result).property('record').instanceof(UserModel);
9798
});
9899

99-
it('should call `beforeRecordMutate` method with created `record` as arg', async () => {
100+
it('should call `beforeRecordMutate` method with created `record` and `resolveParams` as args', async () => {
100101
const result = await createOne(UserModel, UserTypeComposer).resolve({
101102
args: { record: { name: 'NewUser' } },
102-
beforeRecordMutate: (record) => {
103+
context: { ip: '1.1.1.1' },
104+
beforeRecordMutate: (record, rp) => {
103105
record.name = 'OverridedName';
106+
record.someDynamic = rp.context.ip;
104107
return record;
105-
}
108+
},
106109
});
107110
expect(result).property('record').instanceof(UserModel);
108111
expect(result).have.deep.property('record.name', 'OverridedName');
112+
expect(result).have.deep.property('record.someDynamic', '1.1.1.1');
109113
});
110114
});
111115

src/resolvers/__tests__/updateById-test.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* @flow */
2+
/* eslint-disable no-param-reassign */
23

34
import { expect } from 'chai';
45
import {
@@ -152,16 +153,19 @@ describe('updateById() ->', () => {
152153
expect(result.record).instanceof(UserModel);
153154
});
154155

155-
it('should call `beforeRecordMutate` method with founded `record` as arg', async () => {
156+
it('should call `beforeRecordMutate` method with founded `record` and `resolveParams` as args', async () => {
156157
let beforeMutationId;
157158
const result = await updateById(UserModel, UserTypeComposer).resolve({
158159
args: { record: { _id: user1.id } },
159-
beforeRecordMutate: (record) => {
160+
context: { ip: '1.1.1.1' },
161+
beforeRecordMutate: (record, rp) => {
160162
beforeMutationId = record.id;
163+
record.someDynamic = rp.context.ip;
161164
return record;
162-
}
165+
},
163166
});
164167
expect(result.record).instanceof(UserModel);
168+
expect(result).have.deep.property('record.someDynamic', '1.1.1.1');
165169
expect(beforeMutationId).to.equal(user1.id);
166170
});
167171
});

src/resolvers/__tests__/updateOne-test.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* @flow */
2+
/* eslint-disable no-param-reassign */
23

34
import { expect } from 'chai';
45
import { GraphQLNonNull, GraphQLObjectType } from 'graphql';
@@ -177,16 +178,19 @@ describe('updateOne() ->', () => {
177178
expect(result.record).instanceof(UserModel);
178179
});
179180

180-
it('should call `beforeRecordMutate` method with founded `record` as arg', async () => {
181+
it('should call `beforeRecordMutate` method with founded `record` and `resolveParams` as args', async () => {
181182
let beforeMutationId;
182183
const result = await updateOne(UserModel, UserTypeComposer).resolve({
183184
args: { filter: { _id: user1.id } },
184-
beforeRecordMutate: (record) => {
185+
context: { ip: '1.1.1.1' },
186+
beforeRecordMutate: (record, rp) => {
185187
beforeMutationId = record.id;
188+
record.someDynamic = rp.context.ip;
186189
return record;
187190
},
188191
});
189192
expect(result.record).instanceof(UserModel);
193+
expect(result).have.deep.property('record.someDynamic', '1.1.1.1');
190194
expect(beforeMutationId).to.equal(user1.id);
191195
});
192196
});

src/resolvers/createOne.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* @flow */
2-
/* eslint-disable no-param-reassign */
2+
/* eslint-disable no-param-reassign, new-cap */
33

44
import { GraphQLObjectType } from 'graphql';
55
import { Resolver, TypeComposer } from 'graphql-compose';
@@ -59,6 +59,7 @@ export default function createOne(
5959
...(opts && opts.record),
6060
}),
6161
},
62+
// $FlowFixMe
6263
resolve: (resolveParams: ExtendedResolveParams) => {
6364
const recordData = (resolveParams.args && resolveParams.args.record) || {};
6465

@@ -73,14 +74,15 @@ export default function createOne(
7374

7475
// $FlowFixMe
7576
return Promise.resolve(new model(recordData))
76-
.then(doc => {
77+
.then((doc) => {
78+
// $FlowFixMe
7779
if (resolveParams.beforeRecordMutate) {
78-
return resolveParams.beforeRecordMutate(doc);
80+
return resolveParams.beforeRecordMutate(doc, resolveParams);
7981
}
8082
return doc;
8183
})
8284
.then(doc => doc.save())
83-
.then(record => {
85+
.then((record) => {
8486
if (record) {
8587
return {
8688
record,

src/resolvers/helpers/filter.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export const filterHelperArgs = (
5454

5555
if (opts.onlyIndexed) {
5656
const indexedFieldNames = getIndexedFieldNames(model);
57-
Object.keys(typeComposer.getFields()).forEach(fieldName => {
57+
Object.keys(typeComposer.getFields()).forEach((fieldName) => {
5858
if (indexedFieldNames.indexOf(fieldName) === -1) {
5959
removeFields.push(fieldName);
6060
}
@@ -106,17 +106,17 @@ export function filterHelper(resolveParams: ExtendedResolveParams): void {
106106
if (modelFields[key]) {
107107
clearedFilter[key] = filter[key];
108108
}
109-
})
109+
});
110110
if (Object.keys(clearedFilter).length > 0) {
111111
resolveParams.query = resolveParams.query.where(toDottedObject(clearedFilter)); // eslint-disable-line
112112
}
113113

114114
if (filter[OPERATORS_FIELDNAME]) {
115115
const operatorFields = filter[OPERATORS_FIELDNAME];
116-
Object.keys(operatorFields).forEach(fieldName => {
116+
Object.keys(operatorFields).forEach((fieldName) => {
117117
const fieldOperators = Object.assign({}, operatorFields[fieldName]);
118118
const criteria = {};
119-
Object.keys(fieldOperators).forEach(operatorName => {
119+
Object.keys(fieldOperators).forEach((operatorName) => {
120120
criteria[`$${operatorName}`] = fieldOperators[operatorName];
121121
});
122122
if (Object.keys(criteria).length > 0) {
@@ -172,13 +172,13 @@ export function addFieldsWithOperator(
172172
// then fill it up with indexed fields
173173
const indexedFields = getIndexedFieldNames(model);
174174
if (operatorsOpts !== false && Object.keys(operatorsOpts).length === 0) {
175-
indexedFields.forEach(fieldName => {
175+
indexedFields.forEach((fieldName) => {
176176
operatorsOpts[fieldName] = availableOperators; // eslint-disable-line
177177
});
178178
}
179179

180180
const existedFields = inputComposer.getFields();
181-
Object.keys(existedFields).forEach(fieldName => {
181+
Object.keys(existedFields).forEach((fieldName) => {
182182
if (operatorsOpts[fieldName] && operatorsOpts[fieldName] !== false) {
183183
const fields = {};
184184
let operators;
@@ -187,7 +187,7 @@ export function addFieldsWithOperator(
187187
} else {
188188
operators = availableOperators;
189189
}
190-
operators.forEach(operatorName => {
190+
operators.forEach((operatorName) => {
191191
// unwrap from GraphQLNonNull and GraphQLList, if present
192192
const namedType = getNamedType(existedFields[fieldName].type);
193193
if (namedType) {

src/resolvers/updateById.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export default function updateById(
6969
...(opts && opts.record),
7070
}),
7171
},
72+
// $FlowFixMe
7273
resolve: (resolveParams: ExtendedResolveParams) => {
7374
const recordData = (resolveParams.args && resolveParams.args.record) || {};
7475

@@ -94,10 +95,12 @@ export default function updateById(
9495
// So empty projection returns all fields.
9596
resolveParams.projection = {};
9697

98+
// $FlowFixMe
9799
return findByIdResolver.resolve(resolveParams)
98100
.then((doc) => {
101+
// $FlowFixMe
99102
if (resolveParams.beforeRecordMutate) {
100-
return resolveParams.beforeRecordMutate(doc);
103+
return resolveParams.beforeRecordMutate(doc, resolveParams);
101104
}
102105
return doc;
103106
})

src/resolvers/updateOne.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default function updateOne(
8181
}),
8282
...skipHelperArgs(),
8383
},
84+
// $FlowFixMe
8485
resolve: (resolveParams: ExtendedResolveParams) => {
8586
const recordData = (resolveParams.args && resolveParams.args.record) || null;
8687
const filterData = (resolveParams.args && resolveParams.args.filter) || {};
@@ -99,10 +100,12 @@ export default function updateOne(
99100
// So empty projection returns all fields.
100101
resolveParams.projection = {};
101102

103+
// $FlowFixMe
102104
return findOneResolver.resolve(resolveParams)
103105
.then((doc) => {
106+
// $FlowFixMe
104107
if (resolveParams.beforeRecordMutate) {
105-
return resolveParams.beforeRecordMutate(doc);
108+
return resolveParams.beforeRecordMutate(doc, resolveParams);
106109
}
107110
return doc;
108111
})

0 commit comments

Comments
 (0)