Skip to content

Commit 5b91afe

Browse files
committed
feat(DataLoader): Added override with DataLoader on .get($findById)
1 parent 66b3fcf commit 5b91afe

9 files changed

+329
-0
lines changed

.babelrc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"env": {
3+
"development": {
4+
"passPerPreset": true,
5+
"presets": [
6+
{ "plugins": [ "transform-runtime" ] },
7+
{
8+
"passPerPreset": false,
9+
"presets": ["es2015"]
10+
}
11+
],
12+
"plugins": [
13+
"syntax-async-functions",
14+
"transform-regenerator",
15+
"transform-class-properties",
16+
"transform-object-rest-spread",
17+
"transform-flow-strip-types"
18+
]
19+
},
20+
"es": {
21+
"presets": [
22+
["es2015", {"modules": false}]
23+
],
24+
"plugins": [
25+
"syntax-async-functions",
26+
["transform-regenerator", {
27+
"async": false
28+
}],
29+
"transform-class-properties",
30+
"transform-object-rest-spread",
31+
"transform-flow-strip-types",
32+
]
33+
}
34+
}
35+
}

lib/composeWithDataLoader.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.composeWithDataLoader = composeWithDataLoader;
7+
8+
var _graphqlCompose = require('graphql-compose');
9+
10+
function composeWithDataLoader(typeComposer) {
11+
12+
if (!(typeComposer instanceof _graphqlCompose.TypeComposer)) {
13+
throw new Error('You should provide TypeComposer instance to composeWithDataLoader method');
14+
}
15+
16+
/**
17+
* get resolvers to add DataLoader to
18+
*/
19+
var count = typeComposer.get('$count');
20+
var findById = typeComposer.get('$findById');
21+
var findByIds = typeComposer.get('$findByIds');
22+
var findMany = typeComposer.get('$findMany');
23+
var findOne = typeComposer.get('$findOne');
24+
console.log(typeComposer.getTypeName());
25+
26+
if (!findById) throw new Error('TypeComposer(' + typeComposer.getTypeName() + ') provided to composeWithRelay ' + 'should have findById resolver.');
27+
if (!findById) throw new Error('TypeComposer(' + typeComposer.getTypeName() + ') provided to composeWithRelay ' + 'should have findById resolver.');
28+
if (!findByIds) throw new Error('TypeComposer(' + typeComposer.getTypeName() + ') provided to composeWithRelay ' + 'should have findByIds resolver.');
29+
if (!findMany) throw new Error('TypeComposer(' + typeComposer.getTypeName() + ') provided to composeWithRelay ' + 'should have findMany resolver.');
30+
if (!findOne) throw new Error('TypeComposer(' + typeComposer.getTypeName() + ') provided to composeWithRelay ' + 'should have findOne resolver.');
31+
32+
return typeComposer;
33+
}

lib/index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.composeWithDataLoader = undefined;
7+
8+
var _composeWithDataLoader = require('./composeWithDataLoader');
9+
10+
exports.default = _composeWithDataLoader.composeWithDataLoader;
11+
exports.composeWithDataLoader = _composeWithDataLoader.composeWithDataLoader;

package.json

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
{
2+
"name": "graphql-compose-dataloader",
3+
"version": "0.0.1",
4+
"description": "Add DataLoader to graphql-composer resolvers.",
5+
"main": "lib/index.js",
6+
"jsnext:main": "es/index.js",
7+
"scripts": {
8+
"build": "npm run build-cjs && npm run build-es",
9+
"build-cjs": "rimraf lib && babel src --ignore __tests__,__mocks__ -d lib",
10+
"build-es": "rimraf es && BABEL_ENV=es babel src --ignore __tests__,__mocks__ -d es",
11+
"link": "yarn link graphql-compose && yarn link",
12+
"unlink": "yarn unlink graphql-compose && yarn add graphql-compose",
13+
"test": "echo \"Error: no test specified\" && exit 1"
14+
},
15+
"keywords": [
16+
"graphql",
17+
"compose",
18+
"schema",
19+
"dataloader",
20+
"graphql-schema",
21+
"graphql-compose"
22+
],
23+
"repository": {
24+
"type": "git",
25+
"url": "git+https://github.com/stoffern/graphql-compose-dataloader.git"
26+
},
27+
"author": "stoffern",
28+
"license": "MIT",
29+
"bugs": {
30+
"url": "https://github.com/stoffern/graphql-compose-dataloader/issues"
31+
},
32+
"homepage": "https://github.com/stoffern/graphql-compose-dataloader#readme",
33+
"dependencies": {
34+
"dataloader": "^1.3.0",
35+
"string-hash": "^1.1.1"
36+
},
37+
"peerDependencies": {
38+
"graphql": ">=0.9.0",
39+
"graphql-compose": ">=1.4.0"
40+
},
41+
"devDependencies": {
42+
"babel-cli": "^6.22.2",
43+
"babel-core": "^6.22.1",
44+
"babel-eslint": "^7.1.1",
45+
"babel-plugin-syntax-async-functions": "6.13.0",
46+
"babel-plugin-transform-class-properties": "^6.22.0",
47+
"babel-plugin-transform-flow-strip-types": "^6.22.0",
48+
"babel-plugin-transform-object-rest-spread": "^6.22.0",
49+
"babel-plugin-transform-regenerator": "^6.22.0",
50+
"babel-plugin-transform-runtime": "^6.22.0",
51+
"babel-preset-es2015": "^6.22.0",
52+
"graphql-compose": "^1.10.0",
53+
"nyc": "^10.1.2",
54+
"rimraf": "2.5.4",
55+
"cz-conventional-changelog": "^1.2.0"
56+
},
57+
"config": {
58+
"commitizen": {
59+
"path": "./node_modules/cz-conventional-changelog"
60+
}
61+
},
62+
"nyc": {
63+
"exclude": [
64+
"**/__mocks__/**",
65+
"**/__tests__/**",
66+
"resources",
67+
"node_modules"
68+
],
69+
"reporter": [
70+
"lcov",
71+
"text"
72+
]
73+
}
74+
}

src/composeWithDataLoader.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { TypeComposer } from 'graphql-compose'
2+
import DataLoader from 'dataloader'
3+
import {
4+
wrapFindById,
5+
wrapFindByIds,
6+
wrapConnection,
7+
wrapFindMany,
8+
} from './resolvers'
9+
10+
import {
11+
dataloaderOptions
12+
} from './definitions'
13+
14+
export function composeWithDataLoader(
15+
typeComposer: TypeComposer,
16+
options: dataloaderOptions = {}
17+
): TypeComposer {
18+
19+
20+
// if (!(typeComposer instanceof TypeComposer)) {
21+
// throw new Error('You should provide TypeComposer instance to composeWithDataLoader method');
22+
// }
23+
24+
/**
25+
* get resolvers to add DataLoader to
26+
*/
27+
typeComposer = wrapFindById(typeComposer, options)
28+
typeComposer = wrapFindByIds(typeComposer, options)
29+
typeComposer = wrapFindMany(typeComposer, options)
30+
typeComposer = wrapConnection(typeComposer, options)
31+
32+
return typeComposer
33+
}

src/definitions.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export type dataloaderOptions = {
2+
cacheExpiration?: number,
3+
debug?: bool,
4+
}

src/index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import {composeWithDataLoader} from './composeWithDataLoader'
2+
3+
export default composeWithDataLoader
4+
export {
5+
composeWithDataLoader
6+
}

src/resolvers.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import DataLoader from 'dataloader'
2+
import hash from 'object-hash'
3+
import SingleContinous from './singleContinous'
4+
5+
6+
export const wrapFindById = function (tc, opt){
7+
let resolver = tc.getResolver('findById')
8+
let loader = new DataLoader( (resolveParamsArray) =>
9+
new Promise( (resolve, reject) => {
10+
if (opt.debug) console.log('New db request (findById)')
11+
let params = resolveParamsArray[0]
12+
delete params.projection;
13+
let res = resolver.resolve(params)
14+
resolve([res])
15+
}),
16+
{ cacheKeyFn: key => key.args._id.toString() })
17+
18+
tc.setResolver(
19+
'findById',
20+
resolver.wrapResolve(fn => rp => {
21+
SingleContinous.run(loader, rp, opt)
22+
return loader.load(rp)
23+
})
24+
)
25+
return tc
26+
}
27+
28+
// export const wrapFindByIds = function (tc, opt){
29+
// let resolver = tc.getResolver('findByIds')
30+
// let loader = new DataLoader( (resolveParamsArray) =>
31+
// new Promise( (resolve, reject) => {
32+
// if (opt.debug) console.log('New db request (findByIds)')
33+
// let params = resolveParamsArray[0]
34+
// params.args._ids = resolveParamsArray.map(params => params.args._id)
35+
// delete params.projection;
36+
// let res = resolver.resolve(params)
37+
// resolve([res])
38+
// }),
39+
// { cacheKeyFn: key => key.args._id.toString() })
40+
41+
// tc.setResolver(
42+
// 'findByIds',
43+
// resolver.wrapResolve(fn => rp => {
44+
// SingleContinous.run(loader, rp, opt)
45+
// return loader.load(rp)
46+
// })
47+
// )
48+
// return tc
49+
// }
50+
51+
// export const wrapConnection = function (tc, opt){
52+
// let resolver = tc.getResolver('connection')
53+
// let loader = new DataLoader( (resolveParamsArray) =>
54+
// new Promise( async (resolve, reject) => {
55+
// console.log('resolveParamsArray')
56+
// console.log(resolveParamsArray[0].rawQuery._id)
57+
// if (opt.debug) console.log('New db request (connection)')
58+
// let params = resolveParamsArray[0]
59+
// delete params.projection;
60+
// let res = await resolver.resolve(params)
61+
// console.log(res)
62+
// console.log(res.edges[0].node)
63+
// resolve([res])
64+
// }),
65+
// { cacheKeyFn: key => {
66+
// let hashKey = hash(key.args)
67+
// return hashKey
68+
// } })
69+
70+
// tc.setResolver(
71+
// 'connection',
72+
// resolver.wrapResolve(fn => rp => {
73+
// SingleContinous.run(loader, rp, opt)
74+
// return loader.load(rp)
75+
// })
76+
// )
77+
// return tc
78+
// }
79+
80+
// export const wrapFindMany = function (tc, opt){
81+
// let resolver = tc.getResolver('findMany')
82+
// let loader = new DataLoader( (resolveParamsArray) =>
83+
// new Promise( (resolve, reject) => {
84+
// if (opt.debug) console.log('New db request (findMany)')
85+
// let params = resolveParamsArray[0]
86+
// delete params.projection;
87+
// let res = resolver.resolve(params)
88+
// resolve(res)
89+
// }),
90+
// { cacheKeyFn: key => {
91+
// let hashKey = hash(key.args)
92+
// return hashKey
93+
// } })
94+
95+
// tc.setResolver(
96+
// 'findMany',
97+
// resolver.wrapResolve(fn => rp => {
98+
// SingleContinous.run(loader, rp, opt)
99+
// return loader.load(rp)
100+
// })
101+
// )
102+
// return tc
103+
// }

src/singleContinous.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import objectHash from 'object-hash'
2+
import stringHash from 'string-hash'
3+
4+
/**
5+
* This class makes shure functions with params only run once
6+
*/
7+
export default new class SingleContinous{
8+
9+
constructor(props) {
10+
this.store = new Map()
11+
this.counter = 1
12+
}
13+
14+
run(loader, rp, opt){
15+
let hashKey = stringHash(JSON.stringify(loader)+JSON.stringify(rp))
16+
17+
if (!this.store.has(hashKey)){
18+
this.store.set(hashKey, 'running')
19+
setTimeout(() => {
20+
let res = loader.clear(rp)
21+
this.store.delete(hashKey)
22+
},opt.cacheExpiration)
23+
}
24+
}
25+
26+
clearAll(){
27+
this.store.clear()
28+
return true
29+
}
30+
}

0 commit comments

Comments
 (0)