Skip to content

Commit 2ff223d

Browse files
oklasnodkz
authored andcommitted
docs: publish info about beforeRecordMutate
1 parent 6265c33 commit 2ff223d

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

README.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ UserTC.addRelation(
182182
}
183183
);
184184
```
185+
185186
### Reusing the same mongoose Schema in embedded object fields
186187
Suppose you have a common structure you use as embedded object in multiple Schemas.
187188
Also suppose you want the structure to have the same GraphQL type across all parent types.
@@ -252,6 +253,74 @@ fragment fullImageData on EmbeddedImage {
252253
}
253254
```
254255

256+
### Access and modify mongoose doc before save
257+
This library provides some amount of ready resolvers for fetch and update data which was mentioned above. And you can [create your own resolver](https://github.com/graphql-compose/graphql-compose) of course. However you can find that add some actions or light modifications of mongoose document directly before save at existing resolvers appears more simple than create new resolver. Some of resolvers accepts *before save hook* wich can be provided in *resolver params* as param named `beforeRecordMutate`. This hook allows to have access and modify mongoose document before save. The resolvers which supports this hook are:
258+
259+
* createOne
260+
* removeById
261+
* removeOne
262+
* updateById
263+
* updateOne
264+
265+
The protype of before save hook:
266+
```js
267+
(record: mixed, rp: ExtendedResolveParams) => Promise<*>,
268+
```
269+
270+
The typical implementation may be like this:
271+
272+
```js
273+
// extend resolve params with hook
274+
rp.beforeRecordMutate = async function(doc, rp) {
275+
doc.userTouchedAt = new Date();
276+
277+
const canMakeUpdate = await performAsyncTask( ...provide data from doc... )
278+
if (!canMakeUpdate) {
279+
throw new Error('Forbidden!');
280+
}
281+
282+
return doc;
283+
}
284+
```
285+
286+
You can provide your implementation directly in type composer:
287+
288+
```js
289+
UserTC.wrapResolverResolve('updateById', next => async rp => {
290+
291+
// extend resolve params with hook
292+
rp.beforeRecordMutate = async (doc, resolveParams) => { ... };
293+
294+
return next(rp);
295+
});
296+
```
297+
298+
or you can create wrappers for example to protect access:
299+
300+
```js
301+
function adminAccess(resolvers) {
302+
Object.keys(resolvers).forEach((k) => {
303+
resolvers[k] = resolvers[k].wrapResolve(next => async rp => {
304+
305+
// extend resolve params with hook
306+
rp.beforeRecordMutate = async function(doc, rp) { ... }
307+
308+
return next(rp)
309+
})
310+
})
311+
return resolvers
312+
}
313+
314+
// and wrap the resolvers
315+
schemaComposer.Mutation.addFields({
316+
createResource: ResourceTC.getResolver('createOne'),
317+
...adminAccess({
318+
updateResource: ResourceTC.getResolver('updateById'),
319+
removeResource: ResourceTC.getResolver('removeById'),
320+
}),
321+
});
322+
```
323+
255324
## Customization options
256325

257326
When we convert model `const UserTC = composeWithMongoose(User, customizationOptions);` you may tune every piece of future derived types and resolvers.

0 commit comments

Comments
 (0)