{"_id":"dataloader","_rev":"4316370","name":"dataloader","description":"A data loading utility to reduce requests to a backend via batching and caching.","dist-tags":{"latest":"2.2.3"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"time":{"modified":"2026-04-07T22:11:15.000Z","created":"2015-09-14T18:22:57.593Z","2.2.3":"2024-12-03T18:28:12.087Z","2.2.2":"2023-02-13T16:47:29.659Z","2.2.1":"2023-02-02T21:40:49.572Z","2.2.0":"2023-02-02T16:10:13.257Z","2.1.0":"2022-04-12T03:31:20.289Z","2.0.0":"2019-11-18T18:33:00.780Z","1.4.0":"2018-01-31T01:38:05.194Z","1.3.0":"2017-02-04T16:58:38.031Z","1.2.0":"2016-04-05T02:50:02.403Z","1.1.0":"2016-01-12T03:27:32.274Z","1.0.0":"2015-09-14T18:22:57.593Z"},"users":{"nelix":true,"hagai.co":true,"alexxnica":true,"dpjayasekara":true,"nickeltobias":true,"rsp":true,"deneboulton":true,"yakumat":true,"xinwangwang":true,"ricardweii":true,"iceriver2":true,"juanf03":true},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"versions":{"2.2.3":{"name":"dataloader","version":"2.2.3","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"MIT","homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"main":"index.js","typings":"index.d.ts","scripts":{"test":"npm run lint && npm run check && npm run testonly","test:ci":"npm run lint && npm run check && npm run testonly -- --coverage","lint":"eslint .","check":"flow check --max-warnings 0","build":"babel src --ignore src/__tests__ --out-dir dist/ ; cp src/index.js dist/index.js.flow ; cp src/index.d.ts dist/","watch":"babel resources/watch.js | node","testonly":"jest src","prerelease":". ./resources/prepublish.sh","release":"changeset publish"},"devDependencies":{"@babel/cli":"7.7.0","@babel/core":"7.7.2","@babel/node":"7.7.0","@babel/preset-env":"7.7.1","@babel/preset-flow":"7.0.0","@changesets/changelog-github":"0.4.6","@changesets/cli":"2.24.3","babel-eslint":"10.0.3","eslint":"6.6.0","eslint-plugin-prettier":"^3.4.1","flow-bin":"0.112.0","jest":"24.9.0","prettier":"^2.8.3","sane":"4.1.0"},"publishConfig":{"access":"public"},"prettier":{"arrowParens":"avoid","singleQuote":true,"trailingComma":"all","overrides":[{"files":"src/**/*.js","options":{"parser":"babel-flow"}}]},"_id":"dataloader@2.2.3","gitHead":"5e851ce7d3ad4e4473fb4782ebfecb6b1290bd81","_nodeVersion":"22.5.1","_npmVersion":"10.8.2","dist":{"shasum":"42d10b4913515f5b37c6acedcb4960d6ae1b1517","size":16497,"noattachment":false,"key":"/dataloader/-/dataloader-2.2.3.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-2.2.3.tgz"},"_npmUser":{"name":"saihaj","email":"saihajpreet.singh@gmail.com"},"directories":{},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader_2.2.3_1733250491899_0.5210331654789884"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2024-12-03T18:28:12.087Z","publish_time":1733250492087,"_source_registry_name":"default","_cnpm_publish_time":1733250492087},"2.2.2":{"name":"dataloader","version":"2.2.2","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"MIT","homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"main":"index.js","typings":"index.d.ts","scripts":{"test":"npm run lint && npm run check && npm run testonly","test:ci":"npm run lint && npm run check && npm run testonly -- --coverage","lint":"eslint .","check":"flow check --max-warnings 0","build":"babel src --ignore src/__tests__ --out-dir dist/ ; cp src/index.js dist/index.js.flow ; cp src/index.d.ts dist/","watch":"babel resources/watch.js | node","testonly":"jest src","prerelease":". ./resources/prepublish.sh","release":"changeset publish"},"devDependencies":{"@babel/cli":"7.7.0","@babel/core":"7.7.2","@babel/node":"7.7.0","@babel/preset-env":"7.7.1","@babel/preset-flow":"7.0.0","@changesets/changelog-github":"0.4.6","@changesets/cli":"2.24.3","babel-eslint":"10.0.3","eslint":"6.6.0","eslint-plugin-prettier":"^3.4.1","flow-bin":"0.112.0","jest":"24.9.0","prettier":"^2.8.3","sane":"4.1.0"},"publishConfig":{"access":"public"},"prettier":{"arrowParens":"avoid","singleQuote":true,"trailingComma":"all","overrides":[{"files":"src/**/*.js","options":{"parser":"babel-flow"}}]},"gitHead":"e286f662657675fa790f33abcd6aa87b5aac2be3","_id":"dataloader@2.2.2","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"shasum":"216dc509b5abe39d43a9b9d97e6e5e473dfbe3e0","size":16331,"noattachment":false,"key":"/dataloader/-/dataloader-2.2.2.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-2.2.2.tgz"},"_npmUser":{"name":"saihaj","email":"saihajpreet.singh@gmail.com"},"directories":{},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader_2.2.2_1676306849489_0.9989681579363396"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2023-02-13T16:47:29.659Z","publish_time":1676306849659,"_cnpm_publish_time":1676306849659},"2.2.1":{"name":"dataloader","version":"2.2.1","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"MIT","homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"main":"index.js","typings":"index.d.ts","scripts":{"test":"npm run lint && npm run check && npm run testonly","test:ci":"npm run lint && npm run check && npm run testonly -- --coverage","lint":"eslint .","check":"flow check --max-warnings 0","build":"babel src --ignore src/__tests__ --out-dir dist/ ; cp src/index.js dist/index.js.flow ; cp src/index.d.ts dist/","watch":"babel resources/watch.js | node","testonly":"jest src","prerelease":". ./resources/prepublish.sh","release":"changeset publish"},"devDependencies":{"@babel/cli":"7.7.0","@babel/core":"7.7.2","@babel/node":"7.7.0","@babel/preset-env":"7.7.1","@babel/preset-flow":"7.0.0","@changesets/changelog-github":"0.4.6","@changesets/cli":"2.24.3","babel-eslint":"10.0.3","eslint":"6.6.0","eslint-plugin-prettier":"^3.4.1","flow-bin":"0.112.0","jest":"24.9.0","prettier":"^2.8.3","sane":"4.1.0"},"publishConfig":{"access":"public"},"prettier":{"arrowParens":"avoid","singleQuote":true,"trailingComma":"all","overrides":[{"files":"src/**/*.js","options":{"parser":"babel-flow"}}]},"gitHead":"6d2efb7dd0363062de255e723c29a781d0ea9937","_id":"dataloader@2.2.1","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"shasum":"f07ab712514313a34b1507a308dbb7dc14bac715","size":16311,"noattachment":false,"key":"/dataloader/-/dataloader-2.2.1.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-2.2.1.tgz"},"_npmUser":{"name":"saihaj","email":"saihajpreet.singh@gmail.com"},"directories":{},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader_2.2.1_1675374049413_0.9709713879314541"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2023-02-02T21:40:49.572Z","publish_time":1675374049572,"_cnpm_publish_time":1675374049572},"2.2.0":{"name":"dataloader","version":"2.2.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"MIT","homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"main":"index.js","typings":"index.d.ts","scripts":{"test":"npm run lint && npm run check && npm run testonly","test:ci":"npm run lint && npm run check && npm run testonly -- --coverage","lint":"eslint .","check":"flow check --max-warnings 0","build":"babel src --ignore src/__tests__ --out-dir dist/ ; cp src/index.js dist/index.js.flow ; cp src/index.d.ts dist/","watch":"babel resources/watch.js | node","testonly":"jest src","prerelease":". ./resources/prepublish.sh","release":"changeset publish"},"devDependencies":{"@babel/cli":"7.7.0","@babel/core":"7.7.2","@babel/node":"7.7.0","@babel/preset-env":"7.7.1","@babel/preset-flow":"7.0.0","@changesets/changelog-github":"0.4.6","@changesets/cli":"2.24.3","babel-eslint":"10.0.3","eslint":"6.6.0","eslint-plugin-prettier":"^3.4.1","flow-bin":"0.112.0","jest":"24.9.0","prettier":"^2.8.3","sane":"4.1.0"},"publishConfig":{"access":"public"},"prettier":{"arrowParens":"avoid","singleQuote":true,"trailingComma":"all","overrides":[{"files":"src/**/*.js","options":{"parser":"babel-flow"}}]},"gitHead":"dfb9d93e76d89e2ae1df2fbdf6345198df3220dc","_id":"dataloader@2.2.0","_nodeVersion":"16.17.0","_npmVersion":"8.15.0","dist":{"shasum":"eeffcc76a1b8b40c3a3103a9acf3b8e5560a203c","size":16309,"noattachment":false,"key":"/dataloader/-/dataloader-2.2.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-2.2.0.tgz"},"_npmUser":{"name":"saihaj","email":"saihajpreet.singh@gmail.com"},"directories":{},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader_2.2.0_1675354213039_0.6975149477871709"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2023-02-02T16:10:13.257Z","publish_time":1675354213257,"_cnpm_publish_time":1675354213257},"2.1.0":{"name":"dataloader","version":"2.1.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"MIT","homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"main":"index.js","typings":"index.d.ts","scripts":{"test":"npm run lint && npm run check && npm run testonly","test:ci":"npm run lint && npm run check && npm run testonly -- --coverage","lint":"eslint src","check":"flow check --max-warnings 0","build":"babel src --ignore src/__tests__ --out-dir dist/ ; cp src/index.js dist/index.js.flow ; cp src/index.d.ts dist/","watch":"babel resources/watch.js | node","testonly":"jest src","prerelease":". ./resources/prepublish.sh","release":"changeset publish"},"devDependencies":{"@babel/cli":"7.7.0","@babel/core":"7.7.2","@babel/node":"7.7.0","@babel/preset-env":"7.7.1","@babel/preset-flow":"7.0.0","@changesets/cli":"^2.22.0","babel-eslint":"10.0.3","eslint":"6.6.0","flow-bin":"0.112.0","jest":"24.9.0","sane":"4.1.0"},"publishConfig":{"access":"public"},"gitHead":"38def91f23c80333ee14fb8a4a98768c9dd700cd","_id":"dataloader@2.1.0","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"shasum":"c69c538235e85e7ac6c6c444bae8ecabf5de9df7","size":15759,"noattachment":false,"key":"/dataloader/-/dataloader-2.1.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-2.1.0.tgz"},"_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"directories":{},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader_2.1.0_1649734280094_0.04464784909669772"},"_hasShrinkwrap":false,"_cnpmcore_publish_time":"2022-04-12T03:33:01.471Z","publish_time":1649734280289,"_cnpm_publish_time":1649734280289},"2.0.0":{"name":"dataloader","version":"2.0.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"MIT","homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/graphql/dataloader.git"},"main":"index.js","typings":"index.d.ts","gitHead":"0c05d28046af19704b67892ef30817b93225d40f","_id":"dataloader@2.0.0","_nodeVersion":"11.13.0","_npmVersion":"6.7.0","dist":{"shasum":"41eaf123db115987e21ca93c005cd7753c55fe6f","size":14956,"noattachment":false,"key":"/dataloader/-/dataloader-2.0.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-2.0.0.tgz"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader_2.0.0_1574101980680_0.5357362827198038"},"_hasShrinkwrap":false,"publish_time":1574101980780,"_cnpm_publish_time":1574101980780},"1.4.0":{"name":"dataloader","version":"1.4.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"BSD-3-Clause","homepage":"https://github.com/facebook/dataloader","bugs":{"url":"https://github.com/facebook/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/facebook/dataloader.git"},"main":"index.js","typings":"index.d.ts","files":["index.js","index.js.flow","index.d.ts","README.md","LICENSE","PATENTS"],"gitHead":"f12608e11e0c90bedf7caeecee30dc717a187558","_id":"dataloader@1.4.0","_npmVersion":"5.6.0","_nodeVersion":"9.4.0","_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"dist":{"shasum":"bca11d867f5d3f1b9ed9f737bd15970c65dff5c8","size":12828,"noattachment":false,"key":"/dataloader/-/dataloader-1.4.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-1.4.0.tgz"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/dataloader-1.4.0.tgz_1517362685118_0.018772097304463387"},"directories":{},"publish_time":1517362685194,"_hasShrinkwrap":false,"_cnpm_publish_time":1517362685194},"1.3.0":{"name":"dataloader","version":"1.3.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"BSD-3-Clause","homepage":"https://github.com/facebook/dataloader","bugs":{"url":"https://github.com/facebook/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/facebook/dataloader.git"},"main":"index.js","options":{"mocha":"--require resources/mocha-bootload src/**/__tests__/**/*.js"},"babel":{"plugins":["transform-async-to-generator","transform-regenerator","transform-class-properties","transform-flow-strip-types","transform-es2015-template-literals","transform-es2015-literals","transform-es2015-function-name","transform-es2015-arrow-functions",["transform-es2015-classes",{"loose":true}],"transform-es2015-shorthand-properties",["transform-es2015-spread",{"loose":true}],"transform-es2015-parameters",["transform-es2015-destructuring",{"loose":true}],"add-module-exports","transform-es2015-block-scoping",["transform-es2015-modules-commonjs",{"loose":true}]]},"scripts":{"test":"npm run lint && npm run check && npm run testonly","testonly":"babel-node ./node_modules/.bin/_mocha $npm_package_options_mocha","lint":"eslint src","check":"flow check","build":"babel src --ignore __tests__ --out-dir dist/ ; cp src/index.js dist/index.js.flow ; cp src/index.d.ts dist/","watch":"babel resources/watch.js | node","cover":"babel-node node_modules/.bin/isparta cover --root src --report html _mocha -- $npm_package_options_mocha","cover:lcov":"babel-node node_modules/.bin/isparta cover --root src --report lcovonly _mocha -- $npm_package_options_mocha","preversion":". ./resources/checkgit.sh && npm test","prepublish":". ./resources/prepublish.sh"},"files":["index.js","index.js.flow","index.d.ts","README.md","LICENSE","PATENTS"],"devDependencies":{"babel-cli":"6.14.0","babel-eslint":"6.1.2","babel-plugin-add-module-exports":"0.2.1","babel-plugin-transform-async-to-generator":"6.8.0","babel-plugin-transform-class-properties":"6.11.5","babel-plugin-transform-es2015-arrow-functions":"6.8.0","babel-plugin-transform-es2015-block-scoping":"6.15.0","babel-plugin-transform-es2015-classes":"6.14.0","babel-plugin-transform-es2015-destructuring":"6.9.0","babel-plugin-transform-es2015-function-name":"6.9.0","babel-plugin-transform-es2015-literals":"6.8.0","babel-plugin-transform-es2015-modules-commonjs":"6.14.0","babel-plugin-transform-es2015-parameters":"6.11.4","babel-plugin-transform-es2015-shorthand-properties":"6.8.0","babel-plugin-transform-es2015-spread":"6.8.0","babel-plugin-transform-es2015-template-literals":"6.8.0","babel-plugin-transform-flow-strip-types":"6.14.0","babel-plugin-transform-regenerator":"6.14.0","chai":"3.5.0","coveralls":"2.11.14","eslint":"3.5.0","eslint-plugin-babel":"3.3.0","flow-bin":"0.32.0","isparta":"4.0.0","mocha":"3.0.2","sane":"1.4.1"},"typings":"index.d.ts","gitHead":"d472a691d83a3f03a7c6afd2b0a7cf59b2b694e3","_id":"dataloader@1.3.0","_shasum":"6fec5be4b30a712e4afd30b86b4334566b97673b","_from":".","_npmVersion":"4.1.2","_nodeVersion":"7.5.0","_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"dist":{"shasum":"6fec5be4b30a712e4afd30b86b4334566b97673b","size":12032,"noattachment":false,"key":"/dataloader/-/dataloader-1.3.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-1.3.0.tgz"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/dataloader-1.3.0.tgz_1486227515924_0.11830397532321513"},"directories":{},"publish_time":1486227518031,"_cnpm_publish_time":1486227518031,"_hasShrinkwrap":false},"1.2.0":{"name":"dataloader","version":"1.2.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"BSD-3-Clause","homepage":"https://github.com/facebook/dataloader","bugs":{"url":"https://github.com/facebook/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/facebook/dataloader.git"},"main":"dist/index.js","options":{"mocha":"--require resources/mocha-bootload src/**/__tests__/**/*.js"},"scripts":{"test":"npm run lint && npm run check && npm run testonly","testonly":"mocha $npm_package_options_mocha","lint":"eslint src","check":"flow check","build":"babel src --ignore __tests__ --out-dir dist/","watch":"babel --optional runtime resources/watch.js | node","cover":"babel-node node_modules/.bin/isparta cover --root src --report html node_modules/.bin/_mocha -- $npm_package_options_mocha","cover:lcov":"babel-node node_modules/.bin/isparta cover --root src --report lcovonly node_modules/.bin/_mocha -- $npm_package_options_mocha","preversion":". ./resources/checkgit.sh && npm test","prepublish":". ./resources/prepublish.sh"},"files":["dist","README.md","LICENSE","PATENTS"],"devDependencies":{"babel":"5.8.21","babel-runtime":"^5.8.x","babel-core":"5.8.22","babel-eslint":"4.1.8","chai":"3.4.1","coveralls":"2.11.6","eslint":"1.10.3","eslint-plugin-babel":"2.2.0","flow-bin":"0.20.1","isparta":"3.0.3","mocha":"2.3.4","sane":"1.3.0"},"gitHead":"5a5693fdd816fa79bc9421b03c76b8b6ecd80870","_id":"dataloader@1.2.0","_shasum":"3f73ea657c492c860c1633348adc55ca9bf2107e","_from":".","_npmVersion":"3.8.3","_nodeVersion":"5.10.0","_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"dist":{"shasum":"3f73ea657c492c860c1633348adc55ca9bf2107e","size":10545,"noattachment":false,"key":"/dataloader/-/dataloader-1.2.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-1.2.0.tgz"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/dataloader-1.2.0.tgz_1459824600200_0.7781732005532831"},"directories":{},"publish_time":1459824602403,"_cnpm_publish_time":1459824602403,"_hasShrinkwrap":false},"1.1.0":{"name":"dataloader","version":"1.1.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"BSD-3-Clause","homepage":"https://github.com/facebook/dataloader","bugs":{"url":"https://github.com/facebook/dataloader/issues"},"repository":{"type":"git","url":"git+ssh://git@github.com/facebook/dataloader.git"},"main":"dist/index.js","options":{"mocha":"--require resources/mocha-bootload src/**/__tests__/**/*.js"},"scripts":{"test":"npm run lint && npm run check && npm run testonly","testonly":"mocha $npm_package_options_mocha","lint":"eslint src","check":"flow check","build":"babel src --ignore __tests__ --out-dir dist/","watch":"babel --optional runtime resources/watch.js | node","cover":"babel-node node_modules/.bin/isparta cover --root src --report html node_modules/.bin/_mocha -- $npm_package_options_mocha","cover:lcov":"babel-node node_modules/.bin/isparta cover --root src --report lcovonly node_modules/.bin/_mocha -- $npm_package_options_mocha","preversion":". ./resources/checkgit.sh && npm test","prepublish":". ./resources/prepublish.sh"},"files":["dist","README.md","LICENSE","PATENTS"],"devDependencies":{"babel":"5.8.21","babel-runtime":"^5.8.x","babel-core":"5.8.22","babel-eslint":"4.1.6","chai":"3.4.1","coveralls":"2.11.6","eslint":"1.10.3","eslint-plugin-babel":"2.2.0","flow-bin":"0.20.1","isparta":"3.0.3","mocha":"2.3.4","sane":"1.3.0"},"gitHead":"c907bb109c49af6b976e0cd2edfd1a9b9ee5f154","_id":"dataloader@1.1.0","_shasum":"6893b1c4104d6f2b7540c73a91ab54e91efd4316","_from":".","_npmVersion":"3.3.12","_nodeVersion":"5.4.0","_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"dist":{"shasum":"6893b1c4104d6f2b7540c73a91ab54e91efd4316","size":10176,"noattachment":false,"key":"/dataloader/-/dataloader-1.1.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-1.1.0.tgz"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"directories":{},"publish_time":1452569252274,"_cnpm_publish_time":1452569252274,"_hasShrinkwrap":false},"1.0.0":{"name":"dataloader","version":"1.0.0","description":"A data loading utility to reduce requests to a backend via batching and caching.","contributors":[{"name":"Lee Byron","email":"lee@leebyron.com","url":"http://leebyron.com/"},{"name":"Daniel Schafer","email":"dschafer@fb.com"},{"name":"Nicholas Schrock","email":"schrockn@fb.com"}],"license":"BSD-3-Clause","homepage":"https://github.com/facebook/dataloader","bugs":{"url":"https://github.com/facebook/dataloader/issues"},"repository":{"type":"git","url":"http://github.com/facebook/dataloader.git"},"main":"dist/index.js","options":{"mocha":"--require resources/mocha-bootload src/**/__tests__/**/*.js"},"scripts":{"test":"npm run lint && npm run check && npm run testonly","testonly":"mocha $npm_package_options_mocha","lint":"eslint src","check":"flow check","build":"babel src --ignore __tests__ --out-dir dist/","watch":"babel --optional runtime resources/watch.js | node","cover":"babel-node node_modules/.bin/isparta cover --root src --report html node_modules/.bin/_mocha -- $npm_package_options_mocha","cover:lcov":"babel-node node_modules/.bin/isparta cover --root src --report lcovonly node_modules/.bin/_mocha -- $npm_package_options_mocha","preversion":". ./resources/checkgit.sh && npm test","_prepublish":". ./resources/prepublish.sh"},"files":["dist","README.md","LICENSE","PATENTS"],"devDependencies":{"babel":"5.8.21","babel-runtime":"^5.8.x","babel-core":"5.8.22","babel-eslint":"4.0.10","chai":"3.2.0","coveralls":"2.11.3","eslint":"1.1.0","eslint-plugin-babel":"^2.1.1","flow-bin":"0.14.0","isparta":"3.0.3","mocha":"2.2.5","sane":"1.1.3"},"gitHead":"30357688913a463300b8860548088bb5c75a6c36","_id":"dataloader@1.0.0","_shasum":"293d969d0ce31ac1df6d6a0522cdada54acf9f9f","_from":".","_npmVersion":"2.7.3","_nodeVersion":"0.10.35","_npmUser":{"name":"leebyron","email":"lee@leebyron.com"},"dist":{"shasum":"293d969d0ce31ac1df6d6a0522cdada54acf9f9f","size":10833,"noattachment":false,"key":"/dataloader/-/dataloader-1.0.0.tgz","tarball":"http://registry.cnpm.dingdandao.com/dataloader/download/dataloader-1.0.0.tgz"},"maintainers":[{"name":"leebyron","email":"lee@leebyron.com"},{"name":"saihaj","email":""}],"directories":{},"publish_time":1442254977593,"_cnpm_publish_time":1442254977593,"_hasShrinkwrap":false}},"readme":"# DataLoader\n\nDataLoader is a generic utility to be used as part of your application's data\nfetching layer to provide a simplified and consistent API over various remote\ndata sources such as databases or web services via batching and caching.\n\n[![Build Status](https://github.com/graphql/dataloader/actions/workflows/validation.yml/badge.svg)](https://github.com/graphql/dataloader/actions/workflows/validation.yml)\n[![Coverage Status](https://coveralls.io/repos/graphql/dataloader/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql/dataloader?branch=main)\n\nA port of the \"Loader\" API originally developed by [@schrockn][] at Facebook in\n2010 as a simplifying force to coalesce the sundry key-value store back-end\nAPIs which existed at the time. At Facebook, \"Loader\" became one of the\nimplementation details of the \"Ent\" framework, a privacy-aware data entity\nloading and caching layer within web server product code. This ultimately became\nthe underpinning for Facebook's GraphQL server implementation and type\ndefinitions.\n\nDataLoader is a simplified version of this original idea implemented in\nJavaScript for Node.js services. DataLoader is often used when implementing a\n[graphql-js][] service, though it is also broadly useful in other situations.\n\nThis mechanism of batching and caching data requests is certainly not unique to\nNode.js or JavaScript, it is also the primary motivation for\n[Haxl](https://github.com/facebook/Haxl), Facebook's data loading library\nfor Haskell. More about how Haxl works can be read in this [blog post](https://code.facebook.com/posts/302060973291128/open-sourcing-haxl-a-library-for-haskell/).\n\nDataLoader is provided so that it may be useful not just to build GraphQL\nservices for Node.js but also as a publicly available reference implementation\nof this concept in the hopes that it can be ported to other languages. If you\nport DataLoader to another language, please open an issue to include a link from\nthis repository.\n\n## Getting Started\n\nFirst, install DataLoader using npm.\n\n```sh\nnpm install --save dataloader\n```\n\nTo get started, create a `DataLoader`. Each `DataLoader` instance represents a\nunique cache. Typically instances are created per request when used within a\nweb-server like [express][] if different users can see different things.\n\n> Note: DataLoader assumes a JavaScript environment with global ES6 `Promise`\n> and `Map` classes, available in all supported versions of Node.js.\n\n## Batching\n\nBatching is not an advanced feature, it's DataLoader's primary feature.\nCreate loaders by providing a batch loading function.\n\n```js\nconst DataLoader = require('dataloader');\n\nconst userLoader = new DataLoader(keys => myBatchGetUsers(keys));\n```\n\nA batch loading function accepts an Array of keys, and returns a Promise which\nresolves to an Array of values[<sup>\\*</sup>](#batch-function).\n\nThen load individual values from the loader. DataLoader will coalesce all\nindividual loads which occur within a single frame of execution (a single tick\nof the event loop) and then call your batch function with all requested keys.\n\n```js\nconst user = await userLoader.load(1);\nconst invitedBy = await userLoader.load(user.invitedByID);\nconsole.log(`User 1 was invited by ${invitedBy}`);\n\n// Elsewhere in your application\nconst user = await userLoader.load(2);\nconst lastInvited = await userLoader.load(user.lastInvitedID);\nconsole.log(`User 2 last invited ${lastInvited}`);\n```\n\nA naive application may have issued four round-trips to a backend for the\nrequired information, but with DataLoader this application will make at most\ntwo.\n\nDataLoader allows you to decouple unrelated parts of your application without\nsacrificing the performance of batch data-loading. While the loader presents an\nAPI that loads individual values, all concurrent requests will be coalesced and\npresented to your batch loading function. This allows your application to safely\ndistribute data fetching requirements throughout your application and maintain\nminimal outgoing data requests.\n\n#### Batch Function\n\nA batch loading function accepts an Array of keys, and returns a Promise which\nresolves to an Array of values or Error instances. The loader itself is provided\nas the `this` context.\n\n```js\nasync function batchFunction(keys) {\n  const results = await db.fetchAllKeys(keys);\n  return keys.map(key => results[key] || new Error(`No result for ${key}`));\n}\n\nconst loader = new DataLoader(batchFunction);\n```\n\nThere are a few constraints this function must uphold:\n\n- The Array of values must be the same length as the Array of keys.\n- Each index in the Array of values must correspond to the same index in the Array of keys.\n\nFor example, if your batch function was provided the Array of keys: `[ 2, 9, 6, 1 ]`,\nand loading from a back-end service returned the values:\n\n```js\n{ id: 9, name: 'Chicago' }\n{ id: 1, name: 'New York' }\n{ id: 2, name: 'San Francisco' }\n```\n\nOur back-end service returned results in a different order than we requested, likely\nbecause it was more efficient for it to do so. Also, it omitted a result for key `6`,\nwhich we can interpret as no value existing for that key.\n\nTo uphold the constraints of the batch function, it must return an Array of values\nthe same length as the Array of keys, and re-order them to ensure each index aligns\nwith the original keys `[ 2, 9, 6, 1 ]`:\n\n```js\n[\n  { id: 2, name: 'San Francisco' },\n  { id: 9, name: 'Chicago' },\n  null, // or perhaps `new Error()`\n  { id: 1, name: 'New York' },\n];\n```\n\n#### Batch Scheduling\n\nBy default DataLoader will coalesce all individual loads which occur within a\nsingle frame of execution before calling your batch function with all requested\nkeys. This ensures no additional latency while capturing many related requests\ninto a single batch. In fact, this is the same behavior used in Facebook's\noriginal PHP implementation in 2010. See `enqueuePostPromiseJob` in the\n[source code][] for more details about how this works.\n\nHowever sometimes this behavior is not desirable or optimal. Perhaps you expect\nrequests to be spread out over a few subsequent ticks because of an existing use\nof `setTimeout`, or you just want manual control over dispatching regardless of\nthe run loop. DataLoader allows providing a custom batch scheduler to provide\nthese or any other behaviors.\n\nA custom scheduler is provided as `batchScheduleFn` in options. It must be a\nfunction which is passed a callback and is expected to call that callback in the\nimmediate future to execute the batch request.\n\nAs an example, here is a batch scheduler which collects all requests over a\n100ms window of time (and as a consequence, adds 100ms of latency):\n\n```js\nconst myLoader = new DataLoader(myBatchFn, {\n  batchScheduleFn: callback => setTimeout(callback, 100),\n});\n```\n\nAs another example, here is a manually dispatched batch scheduler:\n\n```js\nfunction createScheduler() {\n  let callbacks = [];\n  return {\n    schedule(callback) {\n      callbacks.push(callback);\n    },\n    dispatch() {\n      callbacks.forEach(callback => callback());\n      callbacks = [];\n    },\n  };\n}\n\nconst { schedule, dispatch } = createScheduler();\nconst myLoader = new DataLoader(myBatchFn, { batchScheduleFn: schedule });\n\nmyLoader.load(1);\nmyLoader.load(2);\ndispatch();\n```\n\n## Caching\n\nDataLoader provides a memoization cache for all loads which occur in a single\nrequest to your application. After `.load()` is called once with a given key,\nthe resulting value is cached to eliminate redundant loads.\n\n#### Caching Per-Request\n\nDataLoader caching _does not_ replace Redis, Memcache, or any other shared\napplication-level cache. DataLoader is first and foremost a data loading mechanism,\nand its cache only serves the purpose of not repeatedly loading the same data in\nthe context of a single request to your Application. To do this, it maintains a\nsimple in-memory memoization cache (more accurately: `.load()` is a memoized function).\n\nAvoid multiple requests from different users using the DataLoader instance, which\ncould result in cached data incorrectly appearing in each request. Typically,\nDataLoader instances are created when a Request begins, and are not used once the\nRequest ends.\n\nFor example, when using with [express][]:\n\n```js\nfunction createLoaders(authToken) {\n  return {\n    users: new DataLoader(ids => genUsers(authToken, ids)),\n  };\n}\n\nconst app = express();\n\napp.get('/', function (req, res) {\n  const authToken = authenticateUser(req);\n  const loaders = createLoaders(authToken);\n  res.send(renderPage(req, loaders));\n});\n\napp.listen();\n```\n\n#### Caching and Batching\n\nSubsequent calls to `.load()` with the same key will result in that key not\nappearing in the keys provided to your batch function. _However_, the resulting\nPromise will still wait on the current batch to complete. This way both cached\nand uncached requests will resolve at the same time, allowing DataLoader\noptimizations for subsequent dependent loads.\n\nIn the example below, User `1` happens to be cached. However, because User `1`\nand `2` are loaded in the same tick, they will resolve at the same time. This\nmeans both `user.bestFriendID` loads will also happen in the same tick which\nresults in two total requests (the same as if User `1` had not been cached).\n\n```js\nuserLoader.prime(1, { bestFriend: 3 });\n\nasync function getBestFriend(userID) {\n  const user = await userLoader.load(userID);\n  return await userLoader.load(user.bestFriendID);\n}\n\n// In one part of your application\ngetBestFriend(1);\n\n// Elsewhere\ngetBestFriend(2);\n```\n\nWithout this optimization, if the cached User `1` resolved immediately, this\ncould result in three total requests since each `user.bestFriendID` load would\nhappen at different times.\n\n#### Clearing Cache\n\nIn certain uncommon cases, clearing the request cache may be necessary.\n\nThe most common example when clearing the loader's cache is necessary is after\na mutation or update within the same request, when a cached value could be out of\ndate and future loads should not use any possibly cached value.\n\nHere's a simple example using SQL UPDATE to illustrate.\n\n```js\n// Request begins...\nconst userLoader = new DataLoader(...);\n\n// And a value happens to be loaded (and cached).\nconst user = await userLoader.load(4);\n\n// A mutation occurs, invalidating what might be in cache.\nawait sqlRun('UPDATE users WHERE id=4 SET username=\"zuck\"');\nuserLoader.clear(4);\n\n// Later the value load is loaded again so the mutated data appears.\nconst user = await userLoader.load(4);\n\n// Request completes.\n```\n\n#### Caching Errors\n\nIf a batch load fails (that is, a batch function throws or returns a rejected\nPromise), then the requested values will not be cached. However if a batch\nfunction returns an `Error` instance for an individual value, that `Error` will\nbe cached to avoid frequently loading the same `Error`.\n\nIn some circumstances you may wish to clear the cache for these individual Errors:\n\n```js\ntry {\n  const user = await userLoader.load(1);\n} catch (error) {\n  if (/* determine if the error should not be cached */) {\n    userLoader.clear(1);\n  }\n  throw error\n}\n```\n\n#### Disabling Cache\n\nIn certain uncommon cases, a DataLoader which _does not_ cache may be desirable.\nCalling `new DataLoader(myBatchFn, { cache: false })` will ensure that every\ncall to `.load()` will produce a _new_ Promise, and requested keys will not be\nsaved in memory.\n\nHowever, when the memoization cache is disabled, your batch function will\nreceive an array of keys which may contain duplicates! Each key will be\nassociated with each call to `.load()`. Your batch loader should provide a value\nfor each instance of the requested key.\n\nFor example:\n\n```js\nconst myLoader = new DataLoader(\n  keys => {\n    console.log(keys);\n    return someBatchLoadFn(keys);\n  },\n  { cache: false },\n);\n\nmyLoader.load('A');\nmyLoader.load('B');\nmyLoader.load('A');\n\n// > [ 'A', 'B', 'A' ]\n```\n\nMore complex cache behavior can be achieved by calling `.clear()` or `.clearAll()`\nrather than disabling the cache completely. For example, this DataLoader will\nprovide unique keys to a batch function due to the memoization cache being\nenabled, but will immediately clear its cache when the batch function is called\nso later requests will load new values.\n\n```js\nconst myLoader = new DataLoader(keys => {\n  myLoader.clearAll();\n  return someBatchLoadFn(keys);\n});\n```\n\n#### Custom Cache\n\nAs mentioned above, DataLoader is intended to be used as a per-request cache.\nSince requests are short-lived, DataLoader uses an infinitely growing [Map][] as\na memoization cache. This should not pose a problem as most requests are\nshort-lived and the entire cache can be discarded after the request completes.\n\nHowever this memoization caching strategy isn't safe when using a long-lived\nDataLoader, since it could consume too much memory. If using DataLoader in this\nway, you can provide a custom Cache instance with whatever behavior you prefer,\nas long as it follows the same API as [Map][].\n\nThe example below uses an LRU (least recently used) cache to limit total memory\nto hold at most 100 cached values via the [lru_map][] npm package.\n\n```js\nimport { LRUMap } from 'lru_map';\n\nconst myLoader = new DataLoader(someBatchLoadFn, {\n  cacheMap: new LRUMap(100),\n});\n```\n\nMore specifically, any object that implements the methods `get()`, `set()`,\n`delete()` and `clear()` methods can be provided. This allows for custom Maps\nwhich implement various [cache algorithms][] to be provided.\n\n## API\n\n#### class DataLoader\n\nDataLoader creates a public API for loading data from a particular\ndata back-end with unique keys such as the `id` column of a SQL table or\ndocument name in a MongoDB database, given a batch loading function.\n\nEach `DataLoader` instance contains a unique memoized cache. Use caution when\nused in long-lived applications or those which serve many users with different\naccess permissions and consider creating a new instance per web request.\n\n##### `new DataLoader(batchLoadFn [, options])`\n\nCreate a new `DataLoader` given a batch loading function and options.\n\n- _batchLoadFn_: A function which accepts an Array of keys, and returns a\n  Promise which resolves to an Array of values.\n\n- _options_: An optional object of options:\n\n| Option Key        | Type     | Default                                   | Description                                                                                                                                                                                |\n| ----------------- | -------- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n| `batch`           | Boolean  | `true`                                    | Set to `false` to disable batching, invoking `batchLoadFn` with a single load key. This is equivalent to setting `maxBatchSize` to `1`.                                                    |\n| `maxBatchSize`    | Number   | `Infinity`                                | Limits the number of items that get passed in to the `batchLoadFn`. May be set to `1` to disable batching.                                                                                 |\n| `batchScheduleFn` | Function | See [Batch scheduling](#batch-scheduling) | A function to schedule the later execution of a batch. The function is expected to call the provided callback in the immediate future.                                                     |\n| `cache`           | Boolean  | `true`                                    | Set to `false` to disable memoization caching, creating a new Promise and new key in the `batchLoadFn` for every load of the same key. This is equivalent to setting `cacheMap` to `null`. |\n| `cacheKeyFn`      | Function | `key => key`                              | Produces cache key for a given load key. Useful when objects are keys and two objects should be considered equivalent.                                                                     |\n| `cacheMap`        | Object   | `new Map()`                               | Instance of [Map][] (or an object with a similar API) to be used as cache. May be set to `null` to disable caching.                                                                        |\n| `name`            | String   | `null`                                    | The name given to this `DataLoader` instance. Useful for APM tools.                                                                                                                        |\n\n##### `load(key)`\n\nLoads a key, returning a `Promise` for the value represented by that key.\n\n- _key_: A key value to load.\n\n##### `loadMany(keys)`\n\nLoads multiple keys, promising an array of values:\n\n```js\nconst [a, b] = await myLoader.loadMany(['a', 'b']);\n```\n\nThis is similar to the more verbose:\n\n```js\nconst [a, b] = await Promise.all([myLoader.load('a'), myLoader.load('b')]);\n```\n\nHowever it is different in the case where any load fails. Where\nPromise.all() would reject, loadMany() always resolves, however each result\nis either a value or an Error instance.\n\n```js\nvar [a, b, c] = await myLoader.loadMany(['a', 'b', 'badkey']);\n// c instanceof Error\n```\n\n- _keys_: An array of key values to load.\n\n##### `clear(key)`\n\nClears the value at `key` from the cache, if it exists. Returns itself for\nmethod chaining.\n\n- _key_: A key value to clear.\n\n##### `clearAll()`\n\nClears the entire cache. To be used when some event results in unknown\ninvalidations across this particular `DataLoader`. Returns itself for\nmethod chaining.\n\n##### `prime(key, value)`\n\nPrimes the cache with the provided key and value. If the key already exists, no\nchange is made. (To forcefully prime the cache, clear the key first with\n`loader.clear(key).prime(key, value)`.) Returns itself for method chaining.\n\nTo prime the cache with an error at a key, provide an Error instance.\n\n## Using with GraphQL\n\nDataLoader pairs nicely well with [GraphQL][graphql-js]. GraphQL fields are\ndesigned to be stand-alone functions. Without a caching or batching mechanism,\nit's easy for a naive GraphQL server to issue new database requests each time a\nfield is resolved.\n\nConsider the following GraphQL request:\n\n```\n{\n  me {\n    name\n    bestFriend {\n      name\n    }\n    friends(first: 5) {\n      name\n      bestFriend {\n        name\n      }\n    }\n  }\n}\n```\n\nNaively, if `me`, `bestFriend` and `friends` each need to request the backend,\nthere could be at most 13 database requests!\n\nWhen using DataLoader, we could define the `User` type using the\n[SQLite](examples/SQL.md) example with clearer code and at most 4 database requests,\nand possibly fewer if there are cache hits.\n\n```js\nconst UserType = new GraphQLObjectType({\n  name: 'User',\n  fields: () => ({\n    name: { type: GraphQLString },\n    bestFriend: {\n      type: UserType,\n      resolve: user => userLoader.load(user.bestFriendID),\n    },\n    friends: {\n      args: {\n        first: { type: GraphQLInt },\n      },\n      type: new GraphQLList(UserType),\n      resolve: async (user, { first }) => {\n        const rows = await queryLoader.load([\n          'SELECT toID FROM friends WHERE fromID=? LIMIT ?',\n          user.id,\n          first,\n        ]);\n        return rows.map(row => userLoader.load(row.toID));\n      },\n    },\n  }),\n});\n```\n\n## Common Patterns\n\n### Creating a new DataLoader per request.\n\nIn many applications, a web server using DataLoader serves requests to many\ndifferent users with different access permissions. It may be dangerous to use\none cache across many users, and is encouraged to create a new DataLoader\nper request:\n\n```js\nfunction createLoaders(authToken) {\n  return {\n    users: new DataLoader(ids => genUsers(authToken, ids)),\n    cdnUrls: new DataLoader(rawUrls => genCdnUrls(authToken, rawUrls)),\n    stories: new DataLoader(keys => genStories(authToken, keys)),\n  };\n}\n\n// When handling an incoming web request:\nconst loaders = createLoaders(request.query.authToken);\n\n// Then, within application logic:\nconst user = await loaders.users.load(4);\nconst pic = await loaders.cdnUrls.load(user.rawPicUrl);\n```\n\nCreating an object where each key is a `DataLoader` is one common pattern which\nprovides a single value to pass around to code which needs to perform\ndata loading, such as part of the `rootValue` in a [graphql-js][] request.\n\n### Loading by alternative keys.\n\nOccasionally, some kind of value can be accessed in multiple ways. For example,\nperhaps a \"User\" type can be loaded not only by an \"id\" but also by a \"username\"\nvalue. If the same user is loaded by both keys, then it may be useful to fill\nboth caches when a user is loaded from either source:\n\n```js\nconst userByIDLoader = new DataLoader(async ids => {\n  const users = await genUsersByID(ids);\n  for (let user of users) {\n    usernameLoader.prime(user.username, user);\n  }\n  return users;\n});\n\nconst usernameLoader = new DataLoader(async names => {\n  const users = await genUsernames(names);\n  for (let user of users) {\n    userByIDLoader.prime(user.id, user);\n  }\n  return users;\n});\n```\n\n### Freezing results to enforce immutability\n\nSince DataLoader caches values, it's typically assumed these values will be\ntreated as if they were immutable. While DataLoader itself doesn't enforce\nthis, you can create a higher-order function to enforce immutability\nwith Object.freeze():\n\n```js\nfunction freezeResults(batchLoader) {\n  return keys => batchLoader(keys).then(values => values.map(Object.freeze));\n}\n\nconst myLoader = new DataLoader(freezeResults(myBatchLoader));\n```\n\n### Batch functions which return Objects instead of Arrays\n\nDataLoader expects batch functions which return an Array of the same length as\nthe provided keys. However this is not always a common return format from other\nlibraries. A DataLoader higher-order function can convert from one format to another. The example below converts a `{ key: value }` result to the format\nDataLoader expects.\n\n```js\nfunction objResults(batchLoader) {\n  return keys =>\n    batchLoader(keys).then(objValues =>\n      keys.map(key => objValues[key] || new Error(`No value for ${key}`)),\n    );\n}\n\nconst myLoader = new DataLoader(objResults(myBatchLoader));\n```\n\n## Common Back-ends\n\nLooking to get started with a specific back-end? Try the [loaders in the examples directory](/examples).\n\n## Other Implementations\n\nListed in alphabetical order\n\n- Elixir\n  - [dataloader](https://github.com/absinthe-graphql/dataloader)\n- Golang\n  - [Dataloader](https://github.com/nicksrandall/dataloader)\n- Java\n  - [java-dataloader](https://github.com/graphql-java/java-dataloader)\n- .Net\n  - [GraphQL .NET DataLoader](https://graphql-dotnet.github.io/docs/guides/dataloader/)\n  - [Green Donut](https://github.com/ChilliCream/graphql-platform?tab=readme-ov-file#green-donut)\n- Perl\n  - [perl-DataLoader](https://github.com/richardjharris/perl-DataLoader)\n- PHP\n  - [DataLoaderPHP](https://github.com/overblog/dataloader-php)\n- Python\n  - [aiodataloader](https://github.com/syrusakbary/aiodataloader)\n- ReasonML\n  - [bs-dataloader](https://github.com/ulrikstrid/bs-dataloader)\n- Ruby\n  - [BatchLoader](https://github.com/exaspark/batch-loader)\n  - [Dataloader](https://github.com/sheerun/dataloader)\n  - [GraphQL Batch](https://github.com/Shopify/graphql-batch)\n- Rust\n  - [Dataloader](https://github.com/cksac/dataloader-rs)\n- Swift\n  - [SwiftDataLoader](https://github.com/kimdv/SwiftDataLoader)\n- C++\n  - [cppdataloader](https://github.com/jafarlihi/cppdataloader)\n\n## Video Source Code Walkthrough\n\n**DataLoader Source Code Walkthrough (YouTube):**\n\nA walkthrough of the DataLoader v1 source code. While the source has changed\nsince this video was made, it is still a good overview of the rationale of\nDataLoader and how it works.\n\n<a href=\"https://youtu.be/OQTnXNCDywA\" target=\"_blank\" alt=\"DataLoader Source Code Walkthrough\"><img src=\"https://img.youtube.com/vi/OQTnXNCDywA/0.jpg\" /></a>\n\n[@schrockn]: https://github.com/schrockn\n[Map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map\n[graphql-js]: https://github.com/graphql/graphql-js\n[cache algorithms]: https://en.wikipedia.org/wiki/Cache_algorithms\n[express]: http://expressjs.com/\n[babel/polyfill]: https://babeljs.io/docs/usage/polyfill/\n[lru_map]: https://github.com/rsms/js-lru\n[source code]: https://github.com/graphql/dataloader/blob/main/src/index.js\n\n# Contributing to this repo\n\nThis repository is managed by EasyCLA. Project participants must sign the free ([GraphQL Specification Membership agreement](https://preview-spec-membership.graphql.org) before making a contribution. You only need to do this one time, and it can be signed by [individual contributors](http://individual-spec-membership.graphql.org/) or their [employers](http://corporate-spec-membership.graphql.org/).\n\nTo initiate the signature process please open a PR against this repo. The EasyCLA bot will block the merge if we still need a membership agreement from you.\n\nYou can find [detailed information here](https://github.com/graphql/graphql-wg/tree/main/membership). If you have issues, please email [operations@graphql.org](mailto:operations@graphql.org).\n\nIf your company benefits from GraphQL and you would like to provide essential financial support for the systems and people that power our community, please also consider membership in the [GraphQL Foundation](https://foundation.graphql.org/join).\n","_attachments":{},"homepage":"https://github.com/graphql/dataloader","bugs":{"url":"https://github.com/graphql/dataloader/issues"},"license":"MIT"}