{"id":20519423,"url":"https://github.com/tobkle/create-graphql-server-query-arguments","last_synced_at":"2026-01-23T16:36:41.453Z","repository":{"id":119549508,"uuid":"102219451","full_name":"tobkle/create-graphql-server-query-arguments","owner":"tobkle","description":"build query arguments for filter, orderBy etc.","archived":false,"fork":false,"pushed_at":"2017-09-08T08:40:14.000Z","size":1352,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-29T18:48:43.385Z","etag":null,"topics":["backend-server","expressjs","filter","generator","graphql","graphql-server","mongodb","nodejs","orderby","resolver","schema-generation"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tobkle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-09-02T19:39:26.000Z","updated_at":"2019-05-06T14:24:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"bcce5a4a-4ed4-4be1-82e7-d8ddff51fccb","html_url":"https://github.com/tobkle/create-graphql-server-query-arguments","commit_stats":{"total_commits":33,"total_committers":2,"mean_commits":16.5,"dds":"0.030303030303030276","last_synced_commit":"0e31a83f46621078dae208c78b263cb32664d5cd"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/tobkle/create-graphql-server-query-arguments","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobkle%2Fcreate-graphql-server-query-arguments","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobkle%2Fcreate-graphql-server-query-arguments/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobkle%2Fcreate-graphql-server-query-arguments/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobkle%2Fcreate-graphql-server-query-arguments/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tobkle","download_url":"https://codeload.github.com/tobkle/create-graphql-server-query-arguments/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tobkle%2Fcreate-graphql-server-query-arguments/sbom","scorecard":{"id":890954,"data":{"date":"2025-08-11","repo":{"name":"github.com/tobkle/create-graphql-server-query-arguments","commit":"0e31a83f46621078dae208c78b263cb32664d5cd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.7,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":0,"reason":"96 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-8462-q7x7-g2x4","Warn: Project is vulnerable to: GHSA-4jwp-vfvf-657p","Warn: Project is vulnerable to: GHSA-v8w9-2789-6hhr","Warn: Project is vulnerable to: GHSA-p84x-5xx8-hff9","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-p28h-cc7q-c4fg","Warn: Project is vulnerable to: GHSA-9vvw-cc9w-f27h","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-hr2v-3952-633q","Warn: Project is vulnerable to: GHSA-h6ch-v84p-w6p9","Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3","Warn: Project is vulnerable to: MAL-2023-462","Warn: Project is vulnerable to: GHSA-xf7w-r453-m56c","Warn: Project is vulnerable to: GHSA-4q6p-r6v2-jvc5","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-qh2h-chj9-jffq","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-44pw-h2cw-w3vq","Warn: Project is vulnerable to: GHSA-jp4x-w63m-7wgm","Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37","Warn: Project is vulnerable to: GHSA-4hpf-3wq7-5rpr","Warn: Project is vulnerable to: GHSA-f522-ffg8-j8r6","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-896r-f27r-55mw","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-282f-qqgm-c34q","Warn: Project is vulnerable to: GHSA-8v5f-hp78-jgxq","Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-2m96-9w4j-wgv7","Warn: Project is vulnerable to: GHSA-h726-x36v-rx45","Warn: Project is vulnerable to: GHSA-7px7-7xjx-hxm8","Warn: Project is vulnerable to: GHSA-x5pg-88wf-qq4p","Warn: Project is vulnerable to: GHSA-p9wx-2529-fp83","Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj","Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf","Warn: Project is vulnerable to: GHSA-f9cm-qmx5-m98h","Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-mh5c-679w-hh4r","Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g","Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr","Warn: Project is vulnerable to: GHSA-6394-6h9h-cfjg","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-g6ww-v8xp-vmwg","Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp","Warn: Project is vulnerable to: GHSA-6g33-f262-xjp4","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-2m39-62fm-q8r3","Warn: Project is vulnerable to: GHSA-mf6x-7mm4-x2g7","Warn: Project is vulnerable to: GHSA-mxhp-79qh-mcx6","Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m","Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9","Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh","Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v","Warn: Project is vulnerable to: GHSA-g7q5-pjjr-gqvp","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-xc7v-wxcw-j472","Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v","Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx","Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p","Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3","Warn: Project is vulnerable to: GHSA-332q-7ff2-57h2","Warn: Project is vulnerable to: GHSA-cf4h-3jhx-xvhq"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T11:48:56.102Z","repository_id":119549508,"created_at":"2025-08-24T11:48:56.103Z","updated_at":"2025-08-24T11:48:56.103Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28695596,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T15:57:05.722Z","status":"ssl_error","status_checked_at":"2026-01-23T15:56:27.656Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["backend-server","expressjs","filter","generator","graphql","graphql-server","mongodb","nodejs","orderby","resolver","schema-generation"],"created_at":"2024-11-15T22:13:29.979Z","updated_at":"2026-01-23T16:36:41.428Z","avatar_url":"https://github.com/tobkle.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![npm version](https://badge.fury.io/js/create-graphql-server-query-arguments.svg)](http://badge.fury.io/js/create-graphql-server-query-arguments) [![Build Status](https://travis-ci.org/tobkle/create-graphql-server-query-arguments.svg?branch=master)](https://travis-ci.org/tobkle/create-graphql-server-query-arguments) [![Coverage Status](https://coveralls.io/repos/github/tobkle/create-graphql-server-query-arguments/badge.svg?branch=master)](https://coveralls.io/github/tobkle/create-graphql-server-query-arguments?branch=master)\n\n# create-graphql-server-query-arguments\n\nBuild query arguments for filter and orderBy MongoDB queries.\n\nAdded 60 test cases, which pass against my local create-graphql-server instance.\nThese tests are referenced in create-graphql-server test runs later.\n\nTODO:\n* There can be more test cases, with complex queries and a critical review of the tests. Add them to (src/index-test-cases.js).\n* Implement a test app within the package, to run these test cases against. Used so far my local server to test with. \n\n## Purpose\nYou build a GraphQL server with the npm package \"create-graphql-server\", which serves as a backend to web applications. This \"create-graphql-server\" generates schemas, resolvers and models for an express-js server.\n\nAs soon as you are building the web application on top of this server, you want to access this backend server with specific GraphQL queries. Sometimes you want to set filters, to get just filtered records. Sometimes you want to sort data by different fields in ascending or descending order. Sometimes you want just pages of data with the first ten data records, or just the second page after the first ten records and so on.\n\nIn order to enable such accesses to your GraphQL server backend, the schema needs to provide query arguments such as: \n* filter\n* orderBy\n* limit\n* skip\n\nTODO: as enhanced version of limit and skip:\n* first \n* before \n* last\n* after\n\nAdditionally, your data model must know, how to map these query arguments into valid database queries for the mongoDB database.\n\nThat's the purpose of this module. \n* it provides a function for the schema generator, to generate additional query arguments\n* it provides a function for basic types for all arguments later\n* it provides a function for the data model, to map query arguments, into a database query\n\nGraphQL query argument to mongoDB mapper:\n```javascript\nconst { baseQuery, sortQuery, skip, limit} = prepareQueries( query_arguments )\n```\n\nGraphQL schema Query argument generator:\n```javascript\nbuildRequiredTypes();\n```\n\nGraphQL schema Query argument generator:\n```javascript\nconst enhancedOutputSchema = enhanceSchemaWithQueryArguments( inputSchema );\n```\n\nIt provides the following query arguments:\n\n### orderBy\nAll fields of the type definitions are automatically added to the orderBy sort field selection, except for associations to other types.\n\n### limit\nA limit argument is added, to choose the number of documents/records the query should return.\n\n### skip\nA skip argument is added, to skip a number of found records, not to be returned by the query.\n\n### filter\nThe following filter query arguments are added to list types, which you can use to build complex queries:\n* eq \n* all\n* ne\n* in\n* nin\n* lt\n* lte\n* gt\n* gte\n* regex\n* contains\n* starts_with\n* ends_with\n* not_contains\n* not_starts_with\n* not_ends_with\n* not_in\n* exists\n* not \n* type\n* AND\n* NOR\n* OR\n\n## Installation\n\n### Installation Part 1 -- add the module to create-graphql-server project\n\nThe create-graphql-server generator actually consists out of three parts:\n1. root directory, the generator with directory \"generate\" and its according \"package.json\"\n2. skel directory, contains the skeleton of the future \"to-be-generated-app\", also with its \"package.json\"\n3. test/output-app directory, contains a generated test application, which is like the app in skel, but with already generated parts. This is used for test runs, to check, if it produces valid code.\n\nIn order to get the whole up and running, we have to consider all three parts.\n\nIn the \"root\" directory:\n```bash\nyarn add create-graphql-server-query-arguments\n```\n\nIn the \"test/output-app\" directory\n```bash\nyarn add create-graphql-server-query-arguments\n```\n\nIn the \"skel/package.json\", we have to update only the package.json, that it looks the same like in \"test/output-app\". Just copy the package.json like so and replace \u003cpath\u003e with your create-graphql-server directory path (use pwd, to find out).\n```bash\ncp \u003cpath\u003e/test/output-app/package.json \u003cpath\u003e/skel/package.json\n```\n\n### Installation Part 2 -- add it to the server for the mongoDB accesses\nAdd this module to your express server in \"create-graphql-server/skel/server/index.js\" and also in the \"test/output-app/server/index.js\" and provide it to your data model by:\n```javascript\n...\nimport { prepareQueries } from 'create-graphql-server-query-arguments';\n...\n```\n\n... further below in both files, also add it it your your data model context...\n```javascript\n...\napp.use('/graphql', (req, res, next) =\u003e {\n  passport.authenticate('jwt', { session: false }, (err, me) =\u003e {\n    req.context = addModelsToContext({\n      db, pubsub, me, UserCollection, log, prepareQueries    // \u003c===\n    });\n    graphqlExpress(() =\u003e {\n\t\t...\n    })\n  });\n})\n...\n```\n\nNow you can access it in your data models with \"this.context.prepareQueries\", e.g. in your \"model/User.js\":\n```javascript\nfind(args, me, resolver) {\n  const { baseQuery, sortQuery, skip, limit} = this.context.prepareQueries( args ); // \u003c===\n  const authQuery = queryForRoles(/* auth logic here */);\n  const finalQuery = { ...baseQuery, ...authQuery };\n  return this.collection\n    .find(finalQuery)\n    .sort(sortQuery)\n    .skip(skip)\n    .limit(limit)\n    .toArray();\n}\n```\nBe sure, that also the resolver(s) pass on all \"args\" to your model method \"find\".\n\nIf you forget to sync your changes in both the \"skel\" directory and your \"test/output-app\" directory, your test runs will fail. It compares the generated app files from \"skel\" with those in the \"output-app\" files.\n\n### Installation Part 3 -- General Type Definitions for all arguments, but can be defined only once\n\nAdd to files \"skel/schema/index.js\" and \"test/output-app/schema/index.js\":\n```javascript\n...\nimport { buildRequiredTypes } from 'create-graphql-server-query-arguments'; // \u003c=== add this line\n...\nconst typeDefs = [`\n  scalar ObjID\n  type Query {\n    # A placeholder, please ignore\n    __placeholder: Int\n  }\n  type Mutation {\n    # A placeholder, please ignore\n    __placeholder: Int\n  }\n  type Subscription {\n    # A placeholder, please ignore\n    __placeholder: Int\n  }\n`];\n\ntypeDefs.push(buildRequiredTypes()); // \u003c=== add this line\n\nexport default typeDefs;\n...\n```\nCaution: Do the same again in the \"test/output-app/schema/index.js\" to have proper test runs.\n\n### Installation Part 4 -- Generator for Schema for individual argument type definitions\nAdd to file \"generate/schema/index.js\" the following statements:\n\nIf you don't have installed \"create-graphql-server-authorization\", use this:\n```javascript\n...\nimport { \n\tenhanceSchemaWithQueryArguments \n} from 'create-graphql-server-query-arguments'; // \u003c== here\n...\n...\n  \t// if you have NOT installed create-graphql-server-authorization add this:\n  \tconst outputSchemaWithArguments = enhanceSchemaWithQueryArguments(outputSchema); // \u003c== here\n    \n\treturn outputSchemaWithArguments;  // \u003c== here\n}\n```\n\nIf you have installed also \"create-graphql-server-authorization\", use this instead:\n```javascript\n...\n...\n  // if you have also create-graphql-server-authorization installed use this:\n  const outputSchemaWithAuth = enhanceSchemaForAuthorization(outputSchema);\n  const outputSchemaWithArguments = enhanceSchemaWithQueryArguments(outputSchemaWithAuth);   // \u003c== here\n  \n  return outputSchemaWithArguments;   // \u003c== here\n}\n```\n\nAdd those types to your outputSchema.\n\n### Installation Part 5 --- adjust model and resolver templates\nIn \"generate/model/templates\" and \"generate/resolvers/templates\" adjust the templates: \"default_default.template\" and \"default_user.template\". (If you use create-graphql-server-authorization as well, you have to create additionally the following two files: \"authorize_default.template\" and \"authorize_user.template\").\n\n### Adjust \"generate/model/templates/default/default_default.template\"\nfrom...\n```javascript\n...\n\tfind({ lastCreatedAt = 0, limit = 10, baseQuery = {} }) {\n\t  const finalQuery = { ...baseQuery, createdAt: { $gt: lastCreatedAt } };\n\t  return this.collection\n\t    .find(finalQuery)\n\t    .sort({ createdAt: 1 })\n\t    .limit(limit)\n\t    .toArray();\n\t}\n...\n```\n\n...to...\n```javascript\n...\n\tfind(args) {\n\t  const { baseQuery, sortQuery, skip, limit} = this.context.prepareQueries( args );\n\t  const finalQuery = { ...baseQuery };\n\t  this.context.log.debug(`\\n\\n${resolver} DB-Query:\\n\\n`, JSON.stringify(finalQuery, null, 2), '\\nsort:', sortQuery,'\\nskip:', skip, '\\nlimit:', limit, '\\n','\\n');\n\t  return this.collection\n\t    .find(finalQuery)\n\t    .sort(sortQuery)\n\t    .skip(skip)\n\t    .limit(limit)\n\t    .toArray();\n\t}\n...\n```\n\n### Adjust \"generate/model/templates/user/default_user.template\"\nfrom....\n```javascript\n...\n\tfind({ lastCreatedAt = 0, limit = 10, baseQuery = {} }{{#if authorize}}, me, resolver{{/if}}) {\n\t  const finalQuery = { ...baseQuery, createdAt: { $gt: lastCreatedAt } };\n\t  return this.collection\n\t    .find(finalQuery)\n\t    .sort({ createdAt: 1 })\n\t    .limit(limit)\n\t    .toArray();\n\t}\n...\n```\n\n...to...\n```javascript\n...\n\tfind(args) {\n\t  const { baseQuery, sortQuery, skip, limit} = this.context.prepareQueries( args );\n\t  const finalQuery = { ...baseQuery  };\n\t  this.context.log.debug(`\\n\\n${resolver} DB-Query:\\n\\n`, JSON.stringify(finalQuery, null, 2), '\\nsort:', sortQuery,'\\nskip:', skip, '\\nlimit:', limit, '\\n','\\n');\n\t  return this.collection\n\t    .find(finalQuery)\n\t    .sort(sortQuery)\n\t    .skip(skip)\n\t    .limit(limit)\n\t    .toArray();\n\t}\n...\n```\n\n### Change \"generate/resolvers/templates/default/default_default.template\"\nfrom...\n```javascript\n...\nQuery: {\n  {{typeName}}s(root, { lastCreatedAt, limit }, { {{TypeName}}, me }) {\n    return {{TypeName}}.find({ lastCreatedAt, limit }, me, '{{typeName}}s');\n  },\n...\n```\n\n...to...\n```javascript\n...\nQuery: {\n\t{{typeName}}s(root, args, { {{TypeName}}, me }) {\n\t  return {{TypeName}}.find(args, me, '{{typeName}}s');\n\t},\n...\n```\n\n## With Authorization create-graphql-server-authorization\n**OPTIONAL:**\nIf you are using create-graphql-server-authorization as well, you have to create additional files:\n\nAdd \"generate/model/templates/default/authorize_default.template\":\n```javascript\n/* eslint-disable prettier */\nimport {\n  queryForRoles,\n  onAuthRegisterLoader,\n  authlog,\n  checkAuthDoc\n} from 'create-graphql-server-authorization';\n\nexport default class {{TypeName}} {\n  constructor(context) {\n    this.context = context;\n    this.collection = context.db.collection('{{typeName}}');\n    this.pubsub = context.pubsub;\n    const { me, {{User}} } = context;\n    queryForRoles(\n      me,\n      {{{userRoles.readOne}}},\n      {{{docRoles.readOne}}},\n      { {{User}} },\n      onAuthRegisterLoader('{{typeName}} findOneById', 'readOne', me, this)\n    );\n  }\n\n  async findOneById(id, me, resolver) {\n    const log = authlog(resolver, 'readOne', me);\n    if (!this.authorizedLoader) {\n      log.error('not authorized');\n      return null;\n    }\n    return await this.authorizedLoader.load(id);\n  }\n\n  find(args, me, resolver) {\n    const { baseQuery, sortQuery, skip, limit} = this.context.prepareQueries( args );\n    const authQuery = queryForRoles(\n      me,\n      {{{userRoles.readMany}}},\n      {{{docRoles.readMany}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'readMany', me)\n    );\n    const finalQuery = { ...baseQuery, ...authQuery };\n    this.context.log.debug(`\\n\\n${resolver} DB-Query:\\n\\n`, JSON.stringify(finalQuery, null, 2), '\\nsort:', sortQuery,'\\nskip:', skip, '\\nlimit:', limit, '\\n','\\n');\n    return this.collection\n      .find(finalQuery)\n      .sort(sortQuery)\n      .skip(skip)\n      .limit(limit)\n      .toArray();\n  }\n{{#each singularFields}}\n{{\u003e defaultSingularField }}\n{{/each}}\n{{#each paginatedFields}}\n{{\u003e defaultPaginatedField }}\n{{/each}}\n\n  createdBy({{typeName}}, me, resolver) {\n    return this.context.{{User}}.findOneById({{typeName}}.createdById, me, resolver);\n  }\n\n  updatedBy({{typeName}}, me, resolver) {\n    return this.context.{{User}}.findOneById({{typeName}}.updatedById, me, resolver);\n  }\n\n  async insert(doc, me, resolver) {\n    const docToInsert = Object.assign({}, doc, {\n      createdAt: Date.now(),\n      updatedAt: Date.now(),\n      createdById: (me \u0026\u0026 me._id) ? me._id : 'unknown',\n      updatedById: (me \u0026\u0026 me._id) ? me._id : 'unknown',\n    });\n    checkAuthDoc(\n      docToInsert,\n      me,\n      {{{userRoles.create}}},\n      {{{docRoles.create}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'create', me)\n    );\n    const id = (await this.collection.insertOne(docToInsert)).insertedId;\n    if (!id) {\n      throw new Error(`insert {{typeName}} not possible.`);\n    }\n    this.context.log.debug(`inserted {{typeName}} ${id}.`);\n    const insertedDoc = this.findOneById(id, me, 'pubsub {{typeName}}Inserted');\n    this.pubsub.publish('{{typeName}}Inserted', insertedDoc);\n    return insertedDoc;\n  }\n\n  async updateById(id, doc, me, resolver) {\n    const docToUpdate = {\n      $set: Object.assign({}, doc, {\n        updatedAt: Date.now(),\n        updatedById: me \u0026\u0026 me._id ? me._id : 'unknown'\n      })\n    };\n    const baseQuery = { _id: id };\n    const authQuery = queryForRoles(\n      me,\n      {{{userRoles.update}}},\n      {{{docRoles.update}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'update', me)\n    );\n    const finalQuery = { ...baseQuery, ...authQuery };\n    const result = await this.collection.updateOne(finalQuery, docToUpdate);\n    if (result.result.ok !== 1 || result.result.n !== 1) {\n      throw new Error(`update {{typeName}} not possible for ${id}.`);\n    }\n    this.context.log.debug(`updated {{typeName}} ${id}.`);\n    this.authorizedLoader.clear(id);\n    const updatedDoc = this.findOneById(id, me, 'pubsub {{typeName}}Updated');\n    this.pubsub.publish('{{typeName}}Updated', updatedDoc);\n    return updatedDoc;\n  }\n\n  async removeById(id, me, resolver) {\n    const baseQuery = { _id: id };\n    const authQuery = queryForRoles(\n      me,\n      {{{userRoles.delete}}},\n      {{{docRoles.delete}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'delete', me)\n    );\n    const finalQuery = { ...baseQuery, ...authQuery };\n    const result = await this.collection.remove(finalQuery);\n    if (result.result.ok !== 1 || result.result.n !== 1) {\n      throw new Error(`remove {{typeName}} not possible for ${id}.`);\n    }\n    this.context.log.debug(`removed {{typeName}} ${id}.`);\n    this.authorizedLoader.clear(id);\n    this.pubsub.publish('{{typeName}}Removed', id);\n    return result;\n  }\n}\n\n```\n\nAdjust \"generate/model/templates/user/authorize_user.template\":\n```javascript\n/* eslint-disable prettier */\nimport {\n  queryForRoles,\n  onAuthRegisterLoader,\n  authlog,\n  checkAuthDoc,\n  protectFields\n} from 'create-graphql-server-authorization';\nimport bcrypt from 'bcrypt';\nconst SALT_ROUNDS = 10;\n\nexport default class {{TypeName}} {\n  constructor(context) {\n    this.context = context;\n    this.collection = context.db.collection('{{typeName}}');\n    this.pubsub = context.pubsub;\n    this.authRole = {{User}}.authRole;\n    const { me } = context;\n    queryForRoles(\n      me,\n      {{{userRoles.readOne}}},\n      {{{docRoles.readOne}}},\n      { {{User}} },\n      onAuthRegisterLoader('{{typeName}} findOneById', 'readOne', me, this)\n    );\n  }\n\n  static authRole({{typeName}}) {\n    return {{typeName}} \u0026\u0026 {{typeName}}.{{roleField}} ? {{typeName}}.{{roleField}} : null;\n  }\n\n  async findOneById(id, me, resolver) {\n    const log = authlog(resolver, 'readOne', me);\n    if (!this.authorizedLoader) {\n      log.error('not authorized');\n      return null;\n    }\n    return await this.authorizedLoader.load(id);\n  }\n\n  find(args, me, resolver) {\n    const { baseQuery, sortQuery, skip, limit} = this.context.prepareQueries( args );\n    const authQuery = queryForRoles(\n      me,\n      {{{userRoles.readMany}}},\n      {{{docRoles.readMany}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'readMany', me)\n    );\n    const finalQuery = { ...baseQuery, ...authQuery };\n    this.context.log.debug(`\\n\\n${resolver} DB-Query:\\n\\n`, JSON.stringify(finalQuery, null, 2), '\\nsort:', sortQuery,'\\nskip:', skip, '\\nlimit:', limit, '\\n','\\n');\n    return this.collection\n      .find(finalQuery)\n      .sort(sortQuery)\n      .skip(skip)\n      .limit(limit)\n      .toArray();\n  }\n{{#each singularFields}}\n{{\u003e defaultSingularField }}\n{{/each}}\n{{#each paginatedFields}}\n{{\u003e defaultPaginatedField }}\n{{/each}}\n\n  createdBy({{typeName}}, me, resolver) {\n    return this.context.{{User}}.findOneById({{typeName}}.createdById, me, resolver);\n  }\n\n  updatedBy({{typeName}}, me, resolver) {\n    return this.context.{{User}}.findOneById({{typeName}}.updatedById, me, resolver);\n  }\n\n  async insert(doc, me, resolver) {\n    // We don't want to store passwords in plaintext\n    const { password, ...rest } = doc;\n    const hash = await bcrypt.hash(password, SALT_ROUNDS);\n    let docToInsert = Object.assign({}, rest, {\n      hash,\n      createdAt: Date.now(),\n      updatedAt: Date.now(),\n      createdById: me \u0026\u0026 me._id ? me._id : 'unknown',\n      updatedById: me \u0026\u0026 me._id ? me._id : 'unknown'\n    });\n    checkAuthDoc(\n      docToInsert,\n      me,\n      {{{userRoles.create}}},\n      {{{docRoles.create}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'create', me)\n    );\n    docToInsert = protectFields(me, [{{#if firstUserRole}}'{{firstUserRole}}'{{/if}}], [{{#if roleField}}'{{roleField}}'{{/if}}], docToInsert, {\n      {{User}}: this.context.{{User}}\n    });\n    const id = (await this.collection.insertOne(docToInsert)).insertedId;\n    if (!id) {\n      throw new Error(`insert {{typeName}} not possible.`);\n    }\n    this.context.log.debug(`inserted {{typeName}} ${id}.`);\n    const insertedDoc = this.findOneById(id, me, 'pubsub {{typeName}}Inserted');\n    this.pubsub.publish('{{typeName}}Inserted', insertedDoc);\n    return insertedDoc;\n  }\n\n  async updateById(id, doc, me, resolver) {\n    const docToUpdate = {\n      $set: Object.assign({}, doc, {\n        updatedAt: Date.now(),\n        updatedById: me \u0026\u0026 me._id ? me._id : 'unknown'\n      })\n    };\n    const baseQuery = { _id: id };\n    const authQuery = queryForRoles(\n      me,\n      {{{userRoles.update}}},\n      {{{docRoles.update}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'update', me)\n    );\n    docToUpdate.$set = protectFields(\n      me,\n      [{{#if firstUserRole}}'{{firstUserRole}}'{{/if}}],\n      [{{#if roleField}}'{{roleField}}'{{/if}}],\n      docToUpdate.$set,\n      { {{User}}: this.context.{{User}} }\n    );\n    const finalQuery = { ...baseQuery, ...authQuery };\n    const result = await this.collection.updateOne(finalQuery, docToUpdate);\n    if (result.result.ok !== 1 || result.result.n !== 1) {\n      throw new Error(`update {{typeName}} not possible for ${id}.`);\n    }\n    this.context.log.debug(`updated {{typeName}} ${id}.`);\n    this.authorizedLoader.clear(id);\n    const updatedDoc = this.findOneById(id, me, 'pubsub {{typeName}}Updated');\n    this.pubsub.publish('{{typeName}}Updated', updatedDoc);\n    return updatedDoc;\n  }\n\n  async removeById(id, me, resolver) {\n    const baseQuery = { _id: id };\n    const authQuery = queryForRoles(\n      me,\n      {{{userRoles.delete}}},\n      {{{docRoles.delete}}},\n      { {{User}}: this.context.{{User}} },\n      authlog(resolver, 'delete', me)\n    );\n    const finalQuery = { ...baseQuery, ...authQuery };\n    const result = await this.collection.remove(finalQuery);\n    if (result.result.ok !== 1 || result.result.n !== 1) {\n      throw new Error(`remove {{typeName}} not possible for ${id}.`);\n    }\n    this.context.log.debug(`removed {{typeName}} ${id}.`);\n    this.authorizedLoader.clear(id);\n    this.pubsub.publish('{{typeName}}Removed', id);\n    return result;\n  }\n}\n\n```\n\nAdd \"generate/resolvers/templates/default/authorize_default.template\":\n```javascript\n/* eslint-disable prettier */\n/* eslint comma-dangle: [2, \"only-multiline\"] */\nconst resolvers = {\n  {{TypeName}}: {\n    id({{typeName}}) {\n      return {{typeName}}._id;\n    },\n{{#each singularFields}}\n{{\u003e defaultSingularField }}\n{{/each}}\n{{#each paginatedFields}}\n{{\u003e defaultPaginatedField }}\n{{/each}}\n\n    createdBy({{typeName}}, args, { {{TypeName}}, me }) {\n      return {{TypeName}}.createdBy({{typeName}}, me, '{{typeName}} createdBy');\n    },\n\n    updatedBy({{typeName}}, args, { {{TypeName}}, me }) {\n      return {{TypeName}}.updatedBy({{typeName}}, me, '{{typeName}} updatedBy');\n    }\n  },\n  Query: {\n    {{typeName}}s(root, args, { {{TypeName}}, me }) {\n      return {{TypeName}}.find(args, me, '{{typeName}}s');\n    },\n\n    {{typeName}}(root, { id }, { {{TypeName}}, me }) {\n      return {{TypeName}}.findOneById(id, me, '{{typeName}}');\n    }\n  },\n  Mutation: {\n    async create{{TypeName}}(root, { input }, { {{TypeName}}, me }) {\n      return await {{TypeName}}.insert(input, me, 'create{{TypeName}}');\n    },\n\n    async update{{TypeName}}(root, { id, input }, { {{TypeName}}, me }) {\n      return await {{TypeName}}.updateById(id, input, me, 'update{{TypeName}}');\n    },\n\n    async remove{{TypeName}}(root, { id }, { {{TypeName}}, me }) {\n      return await {{TypeName}}.removeById(id, me, 'remove{{TypeName}}');\n    }\n  },\n  Subscription: {\n    {{typeName}}Created: {{typeName}} =\u003e {{typeName}},\n    {{typeName}}Updated: {{typeName}} =\u003e {{typeName}},\n    {{typeName}}Removed: id =\u003e id\n  }\n};\n\nexport default resolvers;\n\n```\n\n### Installation Part 6 --- For test runs\nThe \"test/output-app\" expects now also different schema files, as we added these additional query arguments. So they have to be also in the test app, otherwise our tests will fail. You don't have to do this manually. In create-graphql-server \"bin/gentest.js\" we have command line command, which is generating all the required files as test files in a temp directory, and if you are using sublime it will show them in sublime. Run it with...\n```bash\nyarn gentest              # defaults to test/input/User.graphql AND:\nyarn gentest test/input/Tweet.graphql\n```\n\nWith that you get also all schema files generated as they should look like with the new extended \"enhanceSchemaWithQueryArguments\" logic. \n\nCopy the generated *.graphql files and overwrite the files in \"test/output-app/schema/*.graphql\".\nCopy the generated *.model.js files and overwrite the files in \"test/output-app/model/*.js\"\nCopy the generated *.resolver.js files and overwrite the files in \"test/output-app/resolvers\"\n\n### Finally\nIf you have succeeded an all the following test runs are ok, you did well. Congratulations!\n```bash\nyarn end-to-end-test\nyarn output-app-generation-test\nyarn test-add-update-remove\n```\n\nIf you are having troubles somewhere, have a look into the running example at:\n[tobkle/create-graphql-server branch: Authorization+Arguments](https://github.com/tobkle/create-graphql-server/tree/Authorization+Arguments)\n\n## Documentation\n[API Documentation](https://tobkle.github.io/create-graphql-server-query-arguments/)\n\n## Tests\n```bash\nyarn test\n```\n\nOr in create-graphql-server package itself:\n```bash\nyarn end-to-end-arguments-test\n```\n\n## Contributing\nIn lieu of a formal style guide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code.\n\n# Example Queries\n\nHave a look in the test directory to see more:\n[index-test-cases](https://github.com/tobkle/create-graphql-server-query-arguments/tree/master/src/index-test-cases.js)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobkle%2Fcreate-graphql-server-query-arguments","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftobkle%2Fcreate-graphql-server-query-arguments","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftobkle%2Fcreate-graphql-server-query-arguments/lists"}