{"_id":"@dav3/gql-of-power","_rev":"13-6682243f76caf2ddab1fd0cc16584be4","name":"@dav3/gql-of-power","dist-tags":{"latest":"1.11.0"},"versions":{"1.0.0":{"name":"@dav3/gql-of-power","version":"1.0.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.0.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"c5f2ba5250f3b8436784903d45a0fa22e5b1edd4","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.0.0.tgz","fileCount":70,"integrity":"sha512-OQ0JqSMNAXeTBMj560+wx9kMWUh2mWOZuVsPR/CB9Pv2d9h2JRjrIsaeFAp/7paAK9D558ciwnX/n3mhRF6i7w==","signatures":[{"sig":"MEUCIQCOA1t7UBgxzp7/ujRgQssTzPVw05r8G4ZBrViy8sPiCAIgKKE5ED7F8OA3/48ZXOb4HASg19ud994R7GBCdq6QSvQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.0.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":264512},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","module":"esnext","gitHead":"dd9bef76d174ff27f7bd73f94ab047f57a4dfd7f","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","build":"tsc","watch":"tsc --watch","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"dav3","email":"npmjs@dav3.cc"},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"10.8.2","description":"> **\"One Query to Rule Them All\"** — Master your data with the power of a single GraphQL query","directories":{},"_nodeVersion":"20.19.5","dependencies":{"knex":"^3.1.0","graphql":"^16.11.0","type-graphql":"^2.0.0-rc.2","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.16.3","@types/bun":"latest","typescript":"^5.8.3","@types/node":"^22.15.17","concurrently":"^9.1.2","graphql-yoga":"^5.16.0","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.25","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.0.0_1761741245434_0.15908431269628798","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@dav3/gql-of-power","version":"1.0.1","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.0.1","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"4a982497c58fe6fd4909b86f6fb435cacd10331b","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.0.1.tgz","fileCount":70,"integrity":"sha512-zr4fZ0KRK7Ak+zaybr6mOWRuomeeosx9cHHH/zdHMTSLpU4c/BbBU2IGSNNO8LPv1P3y0ajZtWOTOgTsW7nnrw==","signatures":[{"sig":"MEUCIC8cljLHLNxB7+3Z4zuiP/VCO6WhGD8HvBlush7F1B7HAiEAi5r2s2GQEZn8iaA1Gt4eA28jWTLkJPOvOGxmwfpTfb4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.0.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":259860},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","module":"esnext","gitHead":"80903c992b52c7858db7ae0bb89d0ab6685e49fc","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","build":"tsc","watch":"tsc --watch","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"dav3","email":"npmjs@dav3.cc"},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"10.8.2","description":"> **\"One Query to Rule Them All\"** — Master your data with the power of a single GraphQL query","directories":{},"_nodeVersion":"20.19.5","dependencies":{"knex":"^3.1.0","graphql":"^16.11.0","type-graphql":"^2.0.0-rc.2","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.16.3","@types/bun":"latest","typescript":"^5.8.3","@types/node":"^22.15.17","concurrently":"^9.1.2","graphql-yoga":"^5.16.0","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.25","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.0.1_1761742497035_0.7078968339467397","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@dav3/gql-of-power","version":"1.1.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.1.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"ef13654ddd5e6932a61dbc604f345c1cda5d1461","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.1.0.tgz","fileCount":69,"integrity":"sha512-7EEnS4jE8IBZyKk87olUnut560/1qtzq80Su0+o+rgy+CE0lc3LMYrY+JHD+mrwBEXGimPjewCVik+eYZEOtyQ==","signatures":[{"sig":"MEUCIDNKibVFp/tp/RhzR4DmIj4NT0ptilD8lu7HJMEchAZAAiEA81eYJcjuqf26BBDkKfxDO6yCrBsTem+SCgoanDOcg58=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":323261},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"64864b345c09d1d28aa4449e4ef7ec6310231b58","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","build":"tsc","watch":"tsc --watch","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.11.0","description":"> **\"One Query to Rule Them All\"** — Master your data with the power of a single GraphQL query","directories":{},"_nodeVersion":"24.14.1","dependencies":{"knex":"^3.1.0","graphql":"^16.13.2","type-graphql":"^2.0.0-rc.2","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.16.3","@types/bun":"latest","typescript":"^5.8.3","@types/node":"^22.15.17","concurrently":"^9.1.2","graphql-yoga":"^5.16.0","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.25","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.1.0_1776673632120_0.09811082140032146","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@dav3/gql-of-power","version":"1.2.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.2.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"bbebeba6cb7aa9c997ddce699c07e13b3bd5d2f4","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.2.0.tgz","fileCount":69,"integrity":"sha512-s1unuZeNlZyHGq1RQLFDcKiBBNNRKGyeyaINo4fdWPTACckIlZUGhN5SI8ZIx4uIYQxAG8jwRvrjWmtSKQ3Wmg==","signatures":[{"sig":"MEQCIAKX4rJ6I5JvOT1iftZi8yeMNXty079pE0jnEkdZNTTsAiA/COqNFJ1IFxyVTCl6xPn1O6vkRGMDBnQ9mOokceXN1w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":326099},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"a81d1ddd700469afbc9164d0589c5b05b99443a5","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","build":"tsc","watch":"tsc --watch","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.11.0","description":"> **\"One Query to Rule Them All\"** — Master your data with the power of a single GraphQL query","directories":{},"_nodeVersion":"24.14.1","dependencies":{"knex":"^3.1.0","graphql":"^16.13.2","type-graphql":"^2.0.0-rc.2","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.16.3","@types/bun":"latest","typescript":"^5.8.3","@types/node":"^22.15.17","concurrently":"^9.1.2","graphql-yoga":"^5.16.0","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.25","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.2.0_1776676107906_0.8128130846502191","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@dav3/gql-of-power","version":"1.3.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.3.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"8dcd04ed29c28e9dc1c1a9066d6815b8f6df248a","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.3.0.tgz","fileCount":69,"integrity":"sha512-qzsR3SdZA+WIAEeuc1RtKsqDtlunZ02HOBnoCyYcAzCXwZK2n1zTkFrcXf78mymUJnYq2C3vV8fIJzymHCnAyQ==","signatures":[{"sig":"MEYCIQCRr09TE1PaPuqt4EO5CX/cgKZUfJlQrDwBCGyPXeeqIAIhAMhFwi0f3TySgpr3u8DYz553HcVsC5jgHYo87wtK4QAf","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":440231},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"95fdc60ba092ce269f0a70eb675860f2f297705c","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.11.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping.","directories":{},"_nodeVersion":"24.14.1","dependencies":{"knex":"^3.1.0","graphql":"^16.13.2","type-graphql":"^2.0.0-rc.2","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"pg":"^8.16.3","@types/bun":"latest","typescript":"^5.8.3","@types/node":"^22.15.17","concurrently":"^9.1.2","graphql-yoga":"^5.16.0","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.25","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.3.0_1777991118371_0.5048993759389395","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@dav3/gql-of-power","version":"1.4.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.4.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"f5c2c5eeda4745812046c567341050abb3ec3bb9","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.4.0.tgz","fileCount":78,"integrity":"sha512-8ujoLpREF/X8DFCYoKDR44hdWAst6G5u3tDZsF9rx58rxvm0BWZA8qkYtkQSBudzDh+/9nISqzPADIpgBLgYrg==","signatures":[{"sig":"MEUCIEuGgdjslMlnxctOLwZSSL9ABf6L34BT3bE9qrsBFkuvAiEAvjgT8sgmxJsA/Wkm2OyNqZS29bJIZTEkPUcN/+Dfe1Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":461834},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"23602f4720b3b3cb52e1753a5599c2a3cedad461","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.16.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","reflect-metadata":"^0.2.2","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.4.0_1784595451707_0.791456333008201","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@dav3/gql-of-power","version":"1.5.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.5.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"45d0feede3bd7679c79ff3556c189be0a7c325c5","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.5.0.tgz","fileCount":81,"integrity":"sha512-8GbpN7hI1B8R5IMTWAqXnguDW/M4v0jNdU8u/HnWyoaes0mqJ2Cp54b0U9xDrf0bxw0EukjpxAa0MBqwEkiZFQ==","signatures":[{"sig":"MEUCIQCo2trubWRwbSokyRa3eN9APQFE4ArJAokgSigp9ihLeQIgHre3ZemwrUuyH1fpDQkiDXMgfsQv6JKPa6wxRvlWfDE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":485921},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"fed30a3d81d39ee38c45eb5949d18f16233fcaa5","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.16.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","reflect-metadata":"^0.2.2","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.5.0_1786263418968_0.979820096300134","host":"s3://npm-registry-packages-npm-production"}},"1.6.0":{"name":"@dav3/gql-of-power","version":"1.6.0","keywords":[],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.6.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"63398b40c017e815de4a3f24111a6cb1354b4015","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.6.0.tgz","fileCount":81,"integrity":"sha512-KVD6BfL077utTSMTMUf+BBTdh5UyionCEaiRzUJc7Pl3yjwxETVfXLrlr1KKF/tbBjODAbm3pMmnzdW3W2QD/g==","signatures":[{"sig":"MEUCIQCIB6L7KHaEllbr7aaoP1qSHpn6RtrlShZrKTaK/EiXKgIgQNXLmWeq0FlJprL0SY3EOCfl/72JSrwDS4vo2Aavf/g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":495233},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"46fbcd50c62904af3e2e4b06e54276c7934f601b","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.16.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","reflect-metadata":"^0.2.2","@types/graphql-fields":"^1.3.9"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.6.0_1786282916020_0.08503674190410648","host":"s3://npm-registry-packages-npm-production"}},"1.7.0":{"name":"@dav3/gql-of-power","version":"1.7.0","keywords":["graphql","sql","type-graphql","n-plus-1","agent-skill","claude-code","cursor","orm"],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.7.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"6d7c7b032b955fe02e9d92ce27e80efad3eb8051","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.7.0.tgz","fileCount":81,"integrity":"sha512-CvoOp5BbNBaMUC1BMQ+ijwQrKIb+qkhd73qv3lFstAj/sTMwK2TCJa3nJ8lFb2h1l9qLHhFZN31mMUh2ESh52A==","signatures":[{"sig":"MEUCIQCKt2cQmqSZfzUfg0XtiKwU85QC7S+Zl2Ibw64lS+H9GQIgINdLF75uhoZcSI5vQaaDckUPF3oTEBRUjk/mQROXy3I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.7.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":511803},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"1e722cb215892d9dff0c601824bccc3d4efca3ba","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.16.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping. Ships with agent skill for AI coding assistants.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","@apollo/server":"^5.5.1","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.38","@types/graphql-fields":"^1.3.9","@as-integrations/aws-lambda":"^4.1.0"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.7.0_1786289025366_0.43630825650609495","host":"s3://npm-registry-packages-npm-production"}},"1.8.0":{"name":"@dav3/gql-of-power","version":"1.8.0","keywords":["graphql","sql","type-graphql","n-plus-1","agent-skill","claude-code","cursor","orm"],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.8.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"c4f6ef03618967a0441deab5393dc47581719ee2","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.8.0.tgz","fileCount":81,"integrity":"sha512-YQGfQSLO97dzgmD45u8AZwHFfPxvBH1R3mNkNzRTflyG4h7q4EVGKrF/lKPxtW9YxP/S0PjLPq0tajDBVcidmQ==","signatures":[{"sig":"MEUCICaCosk9EbUi/4vRQUqcaNBghf0KiMWWQ0rRNR1fZ/S1AiEA6eI4L7EgE444RQYSfEc6QniG8aE7nbTKh4H8ZqHvwQ4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.8.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":512177},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"9cbf5177c50982ace8585d59d28404648f6d93b7","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.16.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping. Ships with agent skill for AI coding assistants.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","@apollo/server":"^5.5.1","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.38","@types/graphql-fields":"^1.3.9","@as-integrations/aws-lambda":"^4.1.0"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.8.0_1786337534034_0.7806872959284552","host":"s3://npm-registry-packages-npm-production"}},"1.9.0":{"name":"@dav3/gql-of-power","version":"1.9.0","keywords":["graphql","sql","type-graphql","n-plus-1","agent-skill","claude-code","cursor","orm"],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.9.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"3732d50ba553b545d1290db36e84445edae0b5e4","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.9.0.tgz","fileCount":81,"integrity":"sha512-mKuEEicPbfTshCkGnqnnqIgluxCgdUyYZm3PhqWEeClyhhM8l+3kIv9HAiuTeOVLsWpyPwFEcgtXszpLGBOKiw==","signatures":[{"sig":"MEQCID1JrpG1DosmrMu7R2spKvbuBY5LNEoM3fdIZi348sIxAiB1nqkK453LT86Za2NFIeX26Cdxc6Q4+DqVW7lvM54gog==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.9.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":515040},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"7dd26f7235cd6e546d630931cccc53a372797b18","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","build:demo":"bun build examples/demo/src/main.ts --target=browser --format=iife --outfile=examples/demo/dist/main.js --define process.env.D3GOP_LOG_TYPE='\"disabled\"'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.16.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping. Ships with agent skill for AI coding assistants.","directories":{},"_nodeVersion":"24.18.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","@apollo/server":"^5.5.1","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.38","@types/graphql-fields":"^1.3.9","@as-integrations/aws-lambda":"^4.1.0"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.9.0_1786578135080_0.6791704219820218","host":"s3://npm-registry-packages-npm-production"}},"1.10.0":{"name":"@dav3/gql-of-power","version":"1.10.0","keywords":["graphql","sql","type-graphql","n-plus-1","agent-skill","claude-code","cursor","orm"],"author":"","license":"MIT NON-AI License","_id":"@dav3/gql-of-power@1.10.0","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"homepage":"https://github.com/dave-palt/gql-of-power#readme","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"dist":{"shasum":"d38d72a1c9b56a1ae2c067e2bdeec4dea1483b3d","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.10.0.tgz","fileCount":84,"integrity":"sha512-IQwmYlaNcE7GGwWzqnvE4vsoNGXbdpIuYotO8fIbHpbD2tt7GrOh2cTFXbkIdrbcW12EjkMQ688kIP6pULaGrQ==","signatures":[{"sig":"MEQCICsqzVrFUt9GgPah3ZE0INa9oNfL4i5+cr975MM0vIfRAiB+L0qC3R6IQ8qQPYl7OpMnZtWgSbdSEFxvfqocYgbjzA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.10.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":630165},"main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","gitHead":"c1cbedf1ea8ee7b8394ca999d9fc9d42bdd1a3ce","scripts":{"test":"D3GOP_LOG_TYPE=\"disabled\" bun test","audit":"fallow audit","build":"tsc","watch":"tsc --watch","format":"bunx prettier --write .","audit:fix":"fallow fix","precommit":"bun run format && bun run typecheck && bun run test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","typecheck":"tsc --noEmit","audit:full":"fallow","build:demo":"bun build examples/demo/src/main.ts --target=browser --format=iife --outfile=examples/demo/dist/main.js --define process.env.D3GOP_LOG_TYPE='\"disabled\"'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","audit:dupes":"fallow dupes","audit:health":"fallow health","format:check":"bunx prettier --check .","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","prepublishOnly":"bun run build","audit:dead-code":"fallow dead-code","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","type":"git","directory":"gql-of-power"},"workspaces":["examples/*"],"_npmVersion":"11.17.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping. Ships with agent skill for AI coding assistants.","directories":{},"_nodeVersion":"24.19.0","dependencies":{"knex":"^3.2.10","graphql":"^16.14.0","type-graphql":"^2.0.0-rc.4","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1"},"_hasShrinkwrap":false,"devDependencies":{"fallow":"^3.6.0","@types/bun":"latest","typescript":"^5.9.3","graphql-yoga":"^5.21.0","@apollo/server":"^5.5.1","class-validator":"^0.15.1","reflect-metadata":"^0.2.2","@graphql-tools/schema":"^10.0.38","@types/graphql-fields":"^1.3.9","@as-integrations/aws-lambda":"^4.1.0"},"_npmOperationalInternal":{"tmp":"tmp/gql-of-power_1.10.0_1787034790502_0.7033812912164337","host":"s3://npm-registry-packages-npm-production"}},"1.11.0":{"name":"@dav3/gql-of-power","version":"1.11.0","description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping. Ships with agent skill for AI coding assistants.","main":"dist/index.js","types":"dist/index.d.ts","module":"esnext","repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","directory":"gql-of-power","type":"git"},"scripts":{"build":"tsc","watch":"tsc --watch","prepublishOnly":"bun run build","test":"D3GOP_LOG_TYPE=\"disabled\" bun test","test:unit":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='unit'","test:integration":"D3GOP_LOG_TYPE=\"disabled\" bun test --filter='integration'","test:watch":"D3GOP_LOG_TYPE=\"disabled\" bun test --watch","test:coverage":"D3GOP_LOG_TYPE=\"disabled\" bun test --coverage","format":"bunx prettier --write .","format:check":"bunx prettier --check .","typecheck":"tsc --noEmit","precommit":"bun run format && bun run typecheck && bun run test","audit":"fallow audit","audit:full":"fallow","audit:dead-code":"fallow dead-code","audit:dupes":"fallow dupes","audit:health":"fallow health","audit:fix":"fallow fix","build:demo":"bun build examples/demo/src/main.ts --target=browser --format=iife --outfile=examples/demo/dist/main.js --define process.env.D3GOP_LOG_TYPE='\"disabled\"'"},"keywords":["graphql","sql","type-graphql","n-plus-1","agent-skill","claude-code","cursor","orm"],"author":"","license":"MIT NON-AI License","devDependencies":{"@apollo/server":"^5.5.1","@as-integrations/aws-lambda":"^4.1.0","@graphql-tools/schema":"^10.0.38","@types/bun":"latest","@types/graphql-fields":"^1.3.9","class-validator":"^0.15.1","fallow":"^3.6.0","graphql-yoga":"^5.21.0","reflect-metadata":"^0.2.2","typescript":"^5.9.3"},"dependencies":{"graphql":"^16.14.0","graphql-fields":"^2.0.3","graphql-parse-resolve-info":"^4.14.1","knex":"^3.2.10","type-graphql":"^2.0.0-rc.4"},"workspaces":["examples/*"],"gitHead":"b7c8478091a35a648df2e3f5453e566fa8a5ebc0","_id":"@dav3/gql-of-power@1.11.0","bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"homepage":"https://github.com/dave-palt/gql-of-power#readme","_nodeVersion":"24.19.0","_npmVersion":"11.17.0","dist":{"integrity":"sha512-1mw1N8xl9y9kFN3SsqQvUWNpuNdGqV6OfQHGSe+uWLRq31pjvEwhJ0cbmy6VT93iey5e+r12n2nGrRZWKj8gFQ==","shasum":"740f776cce525a4ee789dec299580f109fc6345d","tarball":"https://registry.npmjs.org/@dav3/gql-of-power/-/gql-of-power-1.11.0.tgz","fileCount":84,"unpackedSize":648125,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dav3%2fgql-of-power@1.11.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCvF7TPyjgkZ9WtY9nM/O2v3DE2LRrBzh/oD/f9pIMC4wIhALei4GsKrlMQu4veUTLwySDQ1daOBo402rBqOW/mplaV"}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:b12ce376-4c2b-4d2b-af4a-18432b2b62a7"}},"directories":{},"maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/gql-of-power_1.11.0_1787235838586_0.6986526765790806"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-29T12:34:05.352Z","modified":"2026-08-20T14:23:59.302Z","1.0.0":"2025-10-29T12:34:05.630Z","1.0.1":"2025-10-29T12:54:57.230Z","1.1.0":"2026-04-20T08:27:12.267Z","1.2.0":"2026-04-20T09:08:28.032Z","1.3.0":"2026-05-05T14:25:18.530Z","1.4.0":"2026-07-21T00:57:31.909Z","1.5.0":"2026-08-09T08:16:59.128Z","1.6.0":"2026-08-09T13:41:56.188Z","1.7.0":"2026-08-09T15:23:45.510Z","1.8.0":"2026-08-10T04:52:14.205Z","1.9.0":"2026-08-12T23:42:15.218Z","1.10.0":"2026-08-18T06:33:10.639Z","1.11.0":"2026-08-20T14:23:58.955Z"},"bugs":{"url":"https://github.com/dave-palt/gql-of-power/issues"},"license":"MIT NON-AI License","homepage":"https://github.com/dave-palt/gql-of-power#readme","keywords":["graphql","sql","type-graphql","n-plus-1","agent-skill","claude-code","cursor","orm"],"repository":{"url":"git+https://github.com/dave-palt/gql-of-power.git","directory":"gql-of-power","type":"git"},"description":"Generate a single optimized SQL query from GraphQL operations — eliminate N+1 with recursive field-to-SQL mapping. Ships with agent skill for AI coding assistants.","maintainers":[{"name":"dav3","email":"npmjs@dav3.cc"}],"readme":"# ⚔️ GQL of Power\n\n> **\"One Query to Rule Them All\"** — Master your data with the power of a single optimized SQL query\n\n---\n\n## The Ring Bearer's Tale\n\nIn the age of microservices and data loaders, a shadow falls upon performance: _the N+1 query problem_. Weary developers traverse the lands of Middleware-earth, orchestrating countless queries to fetch interconnected data.\n\nBut what if there was another way? What if, with the power of a single SQL query, you could bind all your data together?\n\n**GQL of Power** is a TypeScript library that harnesses ancient sorcery to generate perfectly optimized SQL queries from your GraphQL operations. It eliminates the need for data loaders entirely — one SQL query to fetch your complete data structure, no matter how deeply nested your relationships run.\n\nLike the One Ring wielding dominion over all other Rings, GQL of Power commands your database with singular authority.\n\n> 🎮 **[Try the Live Demo](https://dave-palt.github.io/gql-of-power/)** — Write GraphQL queries in the browser and watch the SQL generate in real time. 100% client-side, no database needed.\n\n---\n\n## Features\n\n### 🗡️ Query Unification\n\nGenerate a **single, optimized SQL query** from any GraphQL query structure — no matter how complex your relationships are.\n\n- ✨ **Eliminate Data Loaders** – Replace the tedious choreography of multiple queries with one powerful statement\n- 🏰 **Intelligent Relationship Handling** – Navigate 1:1, 1:m, m:1, and m:m relationships seamlessly\n- 🔍 **Comprehensive Filtering** – Filter at any level of your nested query tree\n- 📄 **Type-Safe Operations** – Full TypeScript support ensures your queries are error-free\n- ⚡ **Performance Optimized** – UNION ALL for OR conditions, efficient JSONB aggregation, and strategic aliasing\n\n### 🧙 Core Powers\n\n- **Recursive Query Mapping** – Transforms GraphQL field selections into SQL recursively\n- **Automatic Join Generation** – Intelligently creates JOINs based on ORM entity relationships\n- **Dynamic Filtering** – Support for field-level and class-level filter operations (`_eq`, `_in`, `_like`, `_gt`, `_and`, `_or`, etc.)\n- **Pagination & Sorting** – Native limit, offset, and order-by handling\n- **Custom Fields** – Extend entities with computed properties, DataLoaders, or automatic SQL JOINs for unmapped foreign keys\n- **Framework Agnostic** – Works with any ORM through a simple `MetadataProvider` interface\n\n---\n\n## Installation\n\n```bash\npnpm add @dav3/gql-of-power\n```\n\n---\n\n## Quick Start\n\n### 1. Define Your GQL Entities\n\nUse `defineFields` + `@GQLEntityClass` to declare GraphQL entities. `defineFields` is typed against the ORM class — invalid field names are caught at compile time.\n\n```typescript\nimport { defineFields, GQLEntityBase, GQLEntityClass } from '@dav3/gql-of-power';\nimport { Author, Book } from './orm-entities';\nimport { ID, Int } from 'type-graphql';\n\n// --- Author ---\nconst authorFields = defineFields(Author, {\n\tid: { type: () => ID, generateFilter: true },\n\tname: { type: () => String, generateFilter: true },\n});\n\n@GQLEntityClass(Author, authorFields)\nexport class AuthorGQL extends GQLEntityBase {}\n\n// --- Book ---\nconst bookFields = defineFields(Book, {\n\tid: { type: () => ID, generateFilter: true },\n\ttitle: { type: () => String, generateFilter: true },\n\tpublishedYear: { type: () => Int, generateFilter: true },\n\tauthor: { type: () => AuthorGQL, options: { nullable: true } },\n});\n\n@GQLEntityClass(Book, bookFields)\nexport class BookGQL extends GQLEntityBase {}\n```\n\nThe decorator attaches generated statics to the class:\n\n| Static                      | Purpose                                   |\n| --------------------------- | ----------------------------------------- |\n| `BookGQL.FilterInput`       | Generated filter input type               |\n| `BookGQL.PaginationInput`   | Generated pagination input type           |\n| `BookGQL.OrderBy`           | Generated order-by input type             |\n| `BookGQL.FieldsResolver`    | Auto-generated field resolver class       |\n| `BookGQL.gqlEntityName`     | GQL type name (with suffix if configured) |\n| `BookGQL.relatedEntityName` | ORM entity class name (`'Book'`)          |\n\n### 2. Write Resolvers\n\n```typescript\nimport { Resolver, Query, Arg, Info } from 'type-graphql';\nimport { GQLResolver, getAutoResolvers } from '@dav3/gql-of-power';\nimport { GraphQLResolveInfo } from 'graphql';\n\n@GQLResolver(BookGQL)\nexport class BookResolver {\n\t@Query(() => [BookGQL])\n\tasync books(\n\t\t@Arg('filter', () => BookGQL.FilterInput, { nullable: true }) filter: any,\n\t\t@Arg('pagination', () => BookGQL.PaginationInput, { nullable: true }) pagination: any,\n\t\t@Info() info: GraphQLResolveInfo\n\t) {\n\t\treturn queryManager.getQueryResultsForInfo(metadataProvider, BookGQL, info, filter, pagination);\n\t}\n}\n```\n\n### 3. Build the Schema\n\n```typescript\nimport { buildSchemaSync } from 'type-graphql';\nimport { getAutoResolvers } from '@dav3/gql-of-power';\nimport '../entities'; // trigger @GQLEntityClass decoration\n\nconst schema = buildSchemaSync({\n\tresolvers: [\n\t\tBookResolver,\n\t\t...getAutoResolvers(), // FieldsResolver for every @GQLEntityClass entity\n\t],\n});\n```\n\n---\n\n## Examples\n\nFor complete, LotR-themed walkthroughs of both mapping strategies (direct ORM relation and custom field mapping), see **[EXAMPLES.md](./EXAMPLES.md)**.\n\n---\n\n## Entity API\n\n### `defineFields<T>(OrmClass, config)`\n\nTyped wrapper that constrains config keys to `keyof T`. Identity function at runtime — it exists purely for TypeScript inference.\n\n```typescript\nconst fields = defineFields(Book, {\n\tid: { type: () => ID, generateFilter: true },\n\ttitle: { type: () => String, generateFilter: true },\n\ttypo: { type: () => String }, // TS error — 'typo' is not keyof Book ✗\n});\n```\n\n#### Field options\n\n| Option              | Type                     | Purpose                                                                               |\n| ------------------- | ------------------------ | ------------------------------------------------------------------------------------- |\n| `type`              | `() => GraphQLType`      | GraphQL return type (required)                                                        |\n| `generateFilter`    | `boolean`                | Generate filter input fields for this property                                        |\n| `options`           | `FieldOptions`           | type-graphql field options (nullable, description, etc.)                              |\n| `alias`             | `string`                 | Override the GQL field name                                                           |\n| `array`             | `true`                   | Mark as array return type                                                             |\n| `relatedEntityName` | `() => string`           | ORM entity name for array relation fields (auto-derived when using `@GQLEntityClass`) |\n| `countFieldName`    | `string`                 | Generate a count field for this relationship (see [Count Fields](#count-fields))      |\n| `aggregateFields`   | `AggregateFieldConfig[]` | Generate sum/avg/min/max aggregate fields (see [Aggregate Fields](#aggregate-fields)) |\n| `enum`              | `EnumData`               | Register an enum type                                                                 |\n\n### `@GQLEntityClass(OrmClass, fields, extra?)`\n\nClass decorator that registers the entity with type-graphql and attaches generated statics.\n\n```typescript\n@GQLEntityClass(Book, fields, {\n  customFields: { ... }, // optional — see Custom Fields\n  acl: { ... },          // optional — access control\n})\nexport class BookGQL extends GQLEntityBase {}\n```\n\n### `extends GQLEntityBase`\n\nRequired base class. Provides TypeScript visibility of the decorator-attached statics (`FilterInput`, `PaginationInput`, etc.) without `declare static` boilerplate on each entity.\n\n### `@GQLResolver(EntityClass)`\n\nMarks a class as a custom resolver for the given GQL entity. Applies `@Resolver(() => EntityClass)` and integrates with type-graphql's resolver merging (the auto `FieldsResolver` and your custom query resolver coexist seamlessly).\n\n### `getAutoResolvers()`\n\nReturns all `FieldsResolver` classes registered by `@GQLEntityClass` decorators. Pass the result into `buildSchemaSync({ resolvers: [...getAutoResolvers()] })`.\n\n---\n\n## Custom Fields\n\nCustom fields extend a GQL entity with fields that don't exist as direct ORM properties. There are two mutually exclusive strategies.\n\n### Strategy 1: `resolve` — DataLoader / computed\n\nProvide a GraphQL `@FieldResolver` function. The library fetches field(s) listed in `requires` from the main query, then your `resolve` function runs at GraphQL resolution time.\n\n```typescript\n@GQLEntityClass(Fellowship, fields, {\n\tcustomFields: {\n\t\tfirstMember: {\n\t\t\ttype: () => GraphQLJSON,\n\t\t\toptions: { nullable: true },\n\t\t\trequires: 'id', // ensure 'id' is fetched even if client didn't request it\n\t\t\tresolveDecorators: [Root(), Ctx()],\n\t\t\tresolve: (root: Fellowship, ctx: any) => {\n\t\t\t\treturn memberDataLoader.load(root.id);\n\t\t\t},\n\t\t},\n\t},\n})\nexport class FellowshipGQL extends GQLEntityBase {}\n```\n\n#### `resolve` field options\n\n| Option              | Purpose                                                                |\n| ------------------- | ---------------------------------------------------------------------- |\n| `type`              | GraphQL return type                                                    |\n| `options`           | type-graphql field options                                             |\n| `requires`          | Field name(s) to ensure are fetched from DB                            |\n| `resolve`           | The resolver function (required)                                       |\n| `resolveDecorators` | type-graphql parameter decorators in order (`[Root(), Ctx(), Info()]`) |\n\n### Strategy 2: `mapping` — automatic SQL JOIN\n\nProvide a `FieldMappingConfig`. The library generates a SQL `LEFT JOIN LATERAL` automatically and returns the related object directly from the SQL result. No resolver function needed.\n\nUse this when the foreign key exists as a plain column on the entity (not declared as an ORM relation).\n\n```typescript\nimport { Kingdom } from './orm-entities';\n\n@GQLEntityClass(Hobbit, fields, {\n\tcustomFields: {\n\t\tkingdom: {\n\t\t\ttype: () => KingdomGQL,\n\t\t\toptions: { nullable: true },\n\t\t\tmapping: {\n\t\t\t\trefEntity: Kingdom, // ORM entity class to JOIN to\n\t\t\t\trefFields: 'id', // column(s) on Kingdom — keyof Kingdom ✓\n\t\t\t\tfields: 'kingdomId', // column(s) on Hobbit — keyof Hobbit ✓\n\t\t\t},\n\t\t},\n\t},\n})\nexport class HobbitGQL extends GQLEntityBase {}\n```\n\nComposite FK — use arrays (must have the same length):\n\n```typescript\nmapping: {\n  refEntity: Weapon,\n  refFields: ['realmId', 'weaponCode'],\n  fields:    ['realmId', 'weaponExternalId'],\n}\n```\n\n#### `mapping` field options\n\n| Option              | Type                              | Purpose                                                        |\n| ------------------- | --------------------------------- | -------------------------------------------------------------- |\n| `type`              | `() => GraphQLType`               | GraphQL return type                                            |\n| `options`           | `FieldOptions`                    | type-graphql field options (nullable, etc.)                    |\n| `mapping.refEntity` | `new () => TRef`                  | ORM entity class to JOIN to (must be in the metadata provider) |\n| `mapping.refFields` | `keyof TRef \\| Array<keyof TRef>` | Column(s) on the ref entity to match against                   |\n| `mapping.fields`    | `keyof T \\| Array<keyof T>`       | Column(s) on the owner entity to match from                    |\n\n> **Note**: `resolve` and `mapping` are mutually exclusive — TypeScript enforces this via a discriminated union. `resolveDecorators` and `requires` are only valid on the `resolve` branch.\n\n#### Generated SQL\n\nFor `kingdom: { mapping: { refEntity: Kingdom, refFields: 'id', fields: 'kingdomId' } }`:\n\n```sql\nselect e_a1.id, e_a1.kingdom_id, f_j1.value as \"kingdom\"\nfrom (\n  select e_a1.id, e_a1.kingdom_id\n  from hobbit as e_a1\n  where true\n) as e_a1\nleft outer join lateral (\n  select row_to_json(f_j1)::jsonb as value\n  from (\n    select f_j1.id, f_j1.name\n    from kingdom as f_j1\n    where e_a1.kingdom_id = f_j1.id\n  ) as f_j1\n) as f_j1 on true\n```\n\nReturns `null` when the FK column is null (LEFT JOIN).\n\n---\n\n## Three Ways to Define an Entity\n\nThere are three APIs for registering a GQL entity. They differ in **when** the generated types (FilterInput, PaginationInput, FieldsResolver, etc.) are registered — that difference matters for filter-type resolution (see [Troubleshooting](#troubleshooting)).\n\n### Quick comparison\n\n| API                 | When to use                                                                                              | Calls `buildResolvers()`?                                    | FilterInput registered   |\n| ------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | ------------------------ |\n| `@GQLEntityClass`   | **Default.** No circular imports between entity files.                                                   | ✅ Automatically (at decoration time)                        | ✅ Yes                   |\n| `createGQLTypes()`  | Same as `@GQLEntityClass` but as a function call (can't decorate a class, or prefer the explicit style). | ✅ Automatically (internally)                                | ✅ Yes                   |\n| `createGQLEntity()` | **Circular imports** between entity definitions — you need to defer resolver registration.               | ❌ **Deferred** — you must call `.buildResolvers()` yourself | ❌ No, until you call it |\n\n### `@GQLEntityClass` — the default (recommended)\n\nThe decorator registers the entity **and** its FilterInput/FieldsResolver immediately at decoration time. All generated statics (`FilterInput`, `PaginationInput`, `FieldsResolver`) are available on the class.\n\n```typescript\n@GQLEntityClass(Book, bookFields)\nexport class BookGQL extends GQLEntityBase {}\n// BookGQL.FilterInput is ready. Done.\n```\n\n### `createGQLTypes()` — function-call equivalent\n\nSame behaviour as the decorator — it calls `createGQLEntity().buildResolvers()` internally (see `gql-entity.ts:1221-1222`). Use it when you can't or don't want to decorate a class.\n\n```typescript\nexport const BookGQL = createGQLTypes(Book, bookFields);\n// BookGQL.FilterInput is ready. Done.\n```\n\n### `createGQLEntity()` — for circular imports (advanced)\n\nReturns the entity definition **without** registering the FilterInput or FieldsResolver. You must call `.buildResolvers()` yourself before `buildSchema()` runs. This split exists so two entity files can reference each other's `GQLEntity` type thunks without a circular-import deadlock at module-load time.\n\n```typescript\n// book.entity.ts\nexport const BookEntity = createGQLEntity(Book, bookFields);\n//   ↑ FilterInput NOT registered yet\n\n// author.entity.ts — can import BookEntity for the thunk even if Book imports Author\nexport const AuthorEntity = createGQLEntity(Author, authorFields, {\n\tcustomFields: {/* ... uses () => BookEntity.GQLEntity ... */},\n});\n\n// schema/index.ts — YOU must call buildResolvers() on EVERY entity\nexport const BookGQL = BookEntity.buildResolvers(); // ← registers BookFilterInput\nexport const AuthorGQL = AuthorEntity.buildResolvers(); // ← registers AuthorFilterInput\n```\n\n> ⚠️ **If you forget a `.buildResolvers()` call**, any filter that references that entity (relationship fields, mapping custom-field filters, `_exists` filters) will throw at schema-build time:\n>\n> ```\n> gql-of-power: FilterInput for referenced entity \"Book\" (BookFilterInput) is not registered.\n> Make sure Book's buildResolvers() is called (or use createGQLTypes / @GQLEntityClass)\n> before building the schema.\n> ```\n>\n> The error names the missing entity so you know exactly which file to fix.\n\n---\n\n## Filtering\n\nFilter at any nesting level:\n\n```typescript\n// Simple equality\nfilter: { title: 'The Fellowship of the Ring' }\n\n// Operators\nfilter: { publishedYear: { _gte: 1950 } }\n\n// Nested relation filter\nfilter: { author: { name: { _like: '%Tolkien%' } } }\n\n// AND / OR\nfilter: {\n  _or: [\n    { title: { _like: '%Ring%' } },\n    { publishedYear: { _lt: 1960 } },\n  ],\n}\n```\n\n### Filter operations\n\n| Operation      | Meaning                                                                                        |\n| -------------- | ---------------------------------------------------------------------------------------------- |\n| `_eq`          | Equal                                                                                          |\n| `_ne`          | Not equal                                                                                      |\n| `_in`          | In array                                                                                       |\n| `_nin`         | Not in array                                                                                   |\n| `_like`        | LIKE (case-sensitive contains)                                                                 |\n| `_nlike`       | NOT LIKE                                                                                       |\n| `_ilike`       | ILIKE (case-insensitive contains)                                                              |\n| `_nilike`      | NOT ILIKE                                                                                      |\n| `_startsWith`  | LIKE prefix (case-sensitive)                                                                   |\n| `_istartsWith` | ILIKE prefix (case-insensitive)                                                                |\n| `_endsWith`    | LIKE suffix (case-sensitive)                                                                   |\n| `_iendsWith`   | ILIKE suffix (case-insensitive)                                                                |\n| `_re`          | Regex match (`~`)                                                                              |\n| `_nre`         | Regex non-match (`!~`)                                                                         |\n| `_gt` / `_gte` | Greater than / greater than or equal                                                           |\n| `_lt` / `_lte` | Less than / less than or equal                                                                 |\n| `_between`     | BETWEEN low AND high                                                                           |\n| `_nbetween`    | NOT BETWEEN low AND high                                                                       |\n| `_is_null`     | IS NULL (true) / IS NOT NULL (false)                                                           |\n| `_and`         | Logical AND                                                                                    |\n| `_or`          | Logical OR (UNION ALL by default; plain `OR` via [`orStrategy`](#or-strategy-union-all-vs-or)) |\n| `_not`         | Negates a conjunction of conditions (NOT (...) wrapper)                                        |\n| `_exists`      | Check related entities exist (AND-combined per key)                                            |\n| `_not_exists`  | Check no related entities exist (AND-combined per key)                                         |\n\n### Existence Filters (`_exists` / `_not_exists`)\n\nCheck whether related entities match a set of conditions. Each key is a relationship field name; the value is a filter applied to that related entity. Multiple keys are AND-combined.\n\n```graphql\n# Authors that have at least one book titled \"The Hobbit\"\nfilter: {\n  _exists: {\n    books: { title: \"The Hobbit\" }\n  }\n}\n\n# Authors that have a book titled \"The Hobbit\" AND no books in the \"Horror\" genre\nfilter: {\n  _and: [\n    { _exists: { books: { title: \"The Hobbit\" } } }\n    { _not_exists: { books: { genre: \"Horror\" } } }\n  ]\n}\n\n# Persons who fought in a victory battle AND wrote a book about it\nfilter: {\n  _exists: {\n    battles: { outcome: \"Victory\" }\n    books: { title: { _like: \"%War%\" } }\n  }\n}\n```\n\n`_exists` generates `EXISTS (SELECT 1 FROM ... WHERE ...)` subqueries. `_not_exists` generates `NOT EXISTS (...)`. Multiple keys within one `_exists`/`_not_exists` each produce a separate `EXISTS`/`NOT EXISTS` clause, AND-combined in the WHERE. OR across exists conditions is achieved via `_or`.\n\n### Negation Filter (`_not`)\n\nNegate a set of conditions. `_not` takes an array of filter objects, AND-combines them, and wraps the result in `NOT (...)`.\n\n```graphql\n# Persons whose name is NOT \"Sauron\" AND race is NOT \"Maiar\"\nfilter: {\n  _not: [\n    { name: \"Sauron\" }\n    { race: \"Maiar\" }\n  ]\n}\n\n# Combine _not with other filters\nfilter: {\n  age_gt: 50\n  _not: [{ race: \"Orc\" }]\n}\n```\n\nGenerates `NOT (cond1 AND cond2)` in the WHERE clause. For simple field-level negation, the negated operators (`_ne`, `_nin`) are more direct — `_not` is for negating compound expressions. Note: nesting `_or` inside `_not` is not fully negated (the UNION ALL path is not invertible); use De Morgan's law (`_and` of negated conditions) instead.\n\n---\n\n## Count Fields\n\nAdd `countFieldName` to any relationship field with `array: true` to auto-generate an Int count field. The count is computed via a correlated `COUNT(*)` subquery — no JOINs in the outer query.\n\n### Definition\n\n```typescript\nconst authorFields = defineFields(Author, {\n\tid: { type: () => ID, generateFilter: true },\n\tname: { type: () => String, generateFilter: true },\n\tbooks: {\n\t\ttype: () => BookGQL,\n\t\tarray: true,\n\t\trelatedEntityName: () => 'Book',\n\t\tcountFieldName: 'bookCount', // generates an `bookCount: Int` field\n\t},\n});\n```\n\n### Querying\n\n```graphql\nquery {\n\tauthors {\n\t\tname\n\t\tbookCount # total books\n\t\tbookCount(filter: { publishedYear: { _gt: 1950 } }) # filtered count\n\t}\n}\n```\n\n### Filtering by Count\n\nThe count field is also available as a filter key with numeric operators:\n\n```graphql\n# Authors with exactly 4 books\nfilter: { bookCount: 4 }\n\n# Authors with more than 3 books\nfilter: { bookCount_gt: 3 }\n\n# Nested object form\nfilter: { BookCount: { _gte: 2, _lte: 10 } }\n```\n\nSupported operators: `_eq`, `_ne`, `_gt`, `_gte`, `_lt`, `_lte`.\n\n### Generated SQL\n\n```sql\n-- bookCount (select)\nSELECT ...,\n  (SELECT COUNT(*) FROM \"books\" AS e_w1 WHERE e_w1.author_id = a_1.id) AS \"bookCount\"\nFROM authors AS a_1 ...\n\n-- bookCount_gt (filter)\nWHERE (SELECT COUNT(*) FROM \"books\" AS e_w1 WHERE e_w1.author_id = a_1.id) > :v_bookCount_gt__1\n```\n\nWorks for all relationship types (1:m, m:1, m:n). For m:n, the pivot table is included in the subquery.\n\n---\n\n## Aggregate Fields\n\nAdd `aggregateFields` to any relationship field to auto-generate numeric fields that return aggregated values (`sum`, `avg`, `min`, `max`) of a column on the related entities. Each aggregate is computed via a correlated subquery — no JOINs in the outer query.\n\n### Definition\n\n```typescript\nconst authorFields = defineFields(Author, {\n\tid: { type: () => ID, generateFilter: true },\n\tname: { type: () => String, generateFilter: true },\n\tbooks: {\n\t\ttype: () => BookGQL,\n\t\tarray: true,\n\t\trelatedEntityName: () => 'Book',\n\t\tcountFieldName: 'bookCount',\n\t\taggregateFields: [\n\t\t\t{ fn: 'sum', column: 'pages', fieldName: 'totalPages' }, // Float\n\t\t\t{ fn: 'avg', column: 'pages', fieldName: 'avgPages' }, // Float\n\t\t\t{ fn: 'min', column: 'publishedYear', fieldName: 'oldestBook' }, // Int\n\t\t\t{ fn: 'max', column: 'publishedYear', fieldName: 'newestBook' }, // Int\n\t\t],\n\t},\n});\n```\n\n### Field types\n\n| Function | GQL type | SQL function |\n| -------- | -------- | ------------ |\n| `sum`    | `Float`  | `SUM(col)`   |\n| `avg`    | `Float`  | `AVG(col)`   |\n| `min`    | `Float`  | `MIN(col)`   |\n| `max`    | `Float`  | `MAX(col)`   |\n\n> **Note:** The `column` is the **property name** on the related entity, not the raw SQL column name. The mapper resolves it to the correct DB column via metadata.\n\n### Querying\n\n```graphql\nquery {\n\tauthors {\n\t\tname\n\t\ttotalPages\n\t\tavgPages\n\t\toldestBook\n\t\tnewestBook\n\t}\n}\n```\n\n### Filtering by Aggregates\n\nAggregate fields support the same numeric operators as count fields:\n\n```graphql\n# Authors whose total pages exceed 500\nfilter: { totalPages_gt: 500 }\n\n# Implicit _eq\nfilter: { totalPages: 500 }\n\n# Nested object form (AND-combined)\nfilter: { TotalPages: { _gt: 200, _lte: 800 } }\n```\n\nSupported operators: `_eq`, `_ne`, `_gt`, `_gte`, `_lt`, `_lte`.\n\n### Generated SQL\n\n```sql\n-- totalPages (select)\nSELECT ...,\n  (SELECT SUM(page_count) FROM \"books\" AS e_w1 WHERE e_w1.author_id = a_1.id) AS \"totalPages\"\nFROM authors AS a_1 ...\n\n-- totalPages_gt (filter)\nWHERE (SELECT SUM(page_count) FROM \"books\" AS e_w1 WHERE e_w1.author_id = a_1.id) > :v_totalPages1_1\n```\n\nWorks for all relationship types (1:m, m:1, m:m). For m:m, the pivot table is included in the subquery.\n\n---\n\n## Pagination\n\n```typescript\npagination: {\n  limit: 20,\n  offset: 40,\n  orderBy: [{ publishedYear: 'desc' }],\n  distinct: true, // emit SELECT DISTINCT on the outermost query\n}\n```\n\n### Order By Related Columns\n\nYou can sort by columns on a related entity using **nested objects** (so\nTypeScript gives you autocomplete at every level):\n\n```typescript\npagination: {\n  orderBy: [{ author: { name: 'asc' } }], // sort Books by Author name\n}\n```\n\nThis generates a correlated subquery:\n\n```sql\nSELECT ... FROM books AS e_a1\nORDER BY (SELECT e_o.author_name FROM \"authors\" AS e_o WHERE e_a1.author_id = e_o.id) ASC\n```\n\nMultiple related and flat sort keys can be combined:\n\n```typescript\npagination: {\n  orderBy: [{ author: { name: 'asc' } }, { title: 'desc' }],\n}\n```\n\n**All cardinalities are supported in the SQL engine.** The relation's join\ndirection is resolved through the shared ownership dispatch\n(`src/queries/relation-dispatch.ts`):\n\n- **m:1** and **owning-side 1:1** (`inversedBy` set, FK on this entity): plain\n  scalar subquery — exactly one related row, no aggregation.\n- **1:m** and **inverse-side 1:1** (`mappedBy` set, FK on the related entity):\n  the many related rows are collapsed to a single sortable value via\n  aggregation — **MIN for ascending, MAX for descending** — so ordering stays\n  deterministic. Resolves the child FK through the `mappedBy` property.\n- **m:n**: same MIN/MAX aggregation, joining the related table to the pivot\n  table inside the subquery.\n\n```typescript\n// Books of each Author, oldest first (1:m, aggregated):\npagination: {\n\torderBy: [{ books: { publishedYear: 'asc' } }];\n}\n// → ORDER BY (SELECT MIN(e_o.published_year) FROM \"books\" e_o WHERE e_a1.id = e_o.author_id) ASC\n```\n\nAggregated sorts (1:m / m:n) require a **single-column** related field —\nmulti-column is ambiguous under aggregation. An orderBy key that resolves to\nneither a relation nor a scalar field throws a named error instead of silently\nproducing broken SQL.\n\n> **GraphQL schema note:** the auto-generated `<Entity>OrderBy` input type\n> currently exposes **flat `Sort` fields only**. Nested related-column orderBy\n> works through the **programmatic pagination API** — pass `pagination` to\n> `getQueryResultsForInfo` / `getQueryResultsForFields` (or your resolver's\n> pagination arg typed as `any`) — the SQL engine handles the nested objects.\n> Exposing nested orderBy in the generated input types is a planned enhancement.\n\n### Distinct\n\nWhen `pagination.distinct` is `true`, the outermost SELECT is emitted as `SELECT DISTINCT`,\ndeduplicating the final user-facing rows. This is useful when relationship JOINs could\nmultiply parent rows and you only want unique parents back.\n\n```sql\nSELECT DISTINCT e_a1.id, e_a1.book_title AS \"title\" FROM ( ... ) AS e_a1\n```\n\nWorks alongside `limit`, `offset`, `orderBy`, and `_or`/`_and` filters (the UNION ALL\npath also gets the outer `DISTINCT` — the inner structural `select distinct *` is\npreserved as well).\n\n#### Nested distinct\n\nThe `distinct` flag also works on reference-list fields (1:m and m:m relations).\nPass it via the field's `pagination` argument:\n\n```graphql\nquery {\n\tauthors {\n\t\tid\n\t\tname\n\t\tbooks(distinct: true) {\n\t\t\tid\n\t\t\ttitle\n\t\t}\n\t}\n}\n```\n\nThis emits `SELECT DISTINCT` inside the correlated subquery for `books`:\n\n```sql\nSELECT ... COALESCE((\n  SELECT json_agg(row_to_json(e_a2)) FROM (\n    SELECT DISTINCT e_a2.id, e_a2.title\n    FROM \"books\" AS e_a2 WHERE e_a2.author_id = e_a1.id\n  ) AS e_a2\n), '[]') AS \"books\"\nFROM authors AS e_a1\n```\n\nUseful when a m:m pivot or a 1:m join fans out duplicate children. Both root and\nnested `distinct` can be used simultaneously.\n\n### OR Strategy (`union-all` vs `or`)\n\nBy default, `_or` (and `_and`-combination) filters are compiled into separate\nSELECTs combined with `UNION ALL` — each branch keeps its own INNER JOINs\nisolated. Some workloads prefer a single index-friendly scan with a plain `OR`\nin the WHERE clause instead. Set `orStrategy` to switch:\n\n```typescript\n// Per query (via pagination):\nconst rings = await queryManager.getQueryResultsForFields(provider, Ring, fields, filter, {\n\torStrategy: 'or',\n});\n\n// Or globally (also readable from env GQL_OF_POWER_OR_STRATEGY):\nsetGlobalConfig({ orStrategy: 'or' });\n```\n\n**Exposing it to clients.** `orStrategy` is a native field on the generated\n`PaginationInput` (registered via `ensureOrStrategyRegistered()`), so clients\ncan pick the strategy per query — and **per sub-branch** — through the\npagination argument. A relation field's own pagination selects the strategy\nfor that branch only (nearest-wins inheritance; siblings are isolated):\n\n```graphql\nquery {\n\tauthors {\n\t\tid\n\t\tbooks(\n\t\t\tpagination: { orStrategy: OR }\n\t\t\tfilter: { characters: { _or: [{ name_eq: \"Frodo\" }, { name_eq: \"Gandalf\" }] } }\n\t\t) { id title }\n\t\tgenres { id name } # sibling: unaffected, keeps the inherited/default strategy\n\t}\n}\n```\n\nPrecedence, highest first:\n\n1. **Explicit query-building argument** — `buildQueryAndBindingsFor({ orStrategy })`\n   or the trailing `orStrategy` param on `getQueryResultsForFields` /\n   `getQueryResultsForInfo`: a query-wide hard override that **ignores every\n   pagination-carried value (root and child)** and logs a warning per\n   overridden value (`D3GOP_LOG_TYPE=orStrategy` filters them) — for backend\n   code that must force a strategy regardless of client input.\n2. **Branch pagination** — the field's own `pagination.orStrategy`.\n3. **Root pagination** — the query-level `pagination.orStrategy`.\n4. **Global** — `setGlobalConfig({ orStrategy })` / `GQL_OF_POWER_OR_STRATEGY`.\n5. Default `'union-all'`.\n\nFor finer resolver-level control you can still add a dedicated arg using the\nexported `GQLOrStrategy` enum (value names are GraphQL-safe; the values carry\nthe raw `'union-all' | 'or'` strings):\n\n```typescript\nimport { GQLOrStrategy, ensureOrStrategyRegistered } from '@dav3/gql-of-power';\n\nensureOrStrategyRegistered(); // idempotent — registers the enum with type-graphql\n\n@Query(() => [RingGQL])\nasync rings(\n\t@Arg('filter', () => RingGQL.FilterInput, { nullable: true }) filter?: any,\n\t@Arg('orStrategy', () => GQLOrStrategy, { nullable: true }) orStrategy?: GQLOrStrategy,\n\t@Arg('pagination', () => RingGQL.PaginationInput, { nullable: true }) pagination?: any,\n) {\n\treturn queryManager.getQueryResultsForInfo(provider, Ring, info, filter, {\n\t\t...pagination,\n\t\torStrategy, // resolved value drops straight in\n\t}, orStrategy); // explicit hard override — beats every pagination value above\n}\n```\n\n```graphql\nquery {\n\trings(\n\t\torStrategy: OR\n\t\tfilter: { _or: [{ power_like: \"%corruption%\" }, { forgedBy_eq: \"Sauron\" }] }\n\t) {\n\t\tid\n\t}\n}\n```\n\nGenerated SQL for `filter: { _or: [{ name_eq: 'Frodo' }, { race_eq: 'Elf' }] }`:\n\n```sql\n-- orStrategy: 'or' (default 'union-all' emits one SELECT per branch instead)\nSELECT ... FROM persons AS e_a1\nWHERE ((e_a1.person_name = :v_name_eq1_1) OR (e_a1.race = :v_race_eq1_1))\n```\n\nThe strategy applies everywhere `_or` branches are compiled: the root query,\nrelationship `EXISTS` subqueries (m:1 / 1:m / m:m / mapped custom-field), and\ncount/aggregate correlated subqueries.\n\n**Note on relationship-based `_or` branches.** Relationship filter branches\ncompile to self-contained correlated `EXISTS` subqueries (not parent-level\nINNER JOINs), so `'or'` mode is equivalent to UNION ALL for them too —\nverified by PG integration tests covering mixed relationship+scalar branches\nand dual-relationship branches on different tables. Counts and aggregates over\n`_or`-filtered children dedupe on the child's primary keys, so a child\nmatching multiple branches is counted/summed exactly once in both modes.\n\n---\n\n## Relationship Handling\n\n| Relationship           | SQL Strategy                                      |\n| ---------------------- | ------------------------------------------------- |\n| **m:1** (many-to-one)  | `LEFT JOIN LATERAL` + `row_to_json`               |\n| **1:1** (one-to-one)   | `LEFT JOIN LATERAL` + `row_to_json`               |\n| **1:m** (one-to-many)  | `LEFT JOIN LATERAL` + `json_agg`                  |\n| **m:m** (many-to-many) | Pivot table subquery + `json_agg`                 |\n| **custom `mapping`**   | `LEFT JOIN LATERAL` + `row_to_json` (same as m:1) |\n\n---\n\n## Configuration\n\n### Environment Variables\n\n| Variable                       | Purpose                                                                                                           |\n| ------------------------------ | ----------------------------------------------------------------------------------------------------------------- |\n| `D3GOP_TYPES_SUFFIX`           | Suffix appended to all generated GQL entity type names (e.g. `'V2'` → `BookV2`, `AuthorV2`)                       |\n| `D3GOP_SORT_SUFFIX`            | Suffix appended to sort/pagination types only (e.g. `'V2'` → `SortV2`, `BookV2OrderBy`)                           |\n| `D3GOP_LOG_TYPE`               | Logging level: `debug` or `disabled`                                                                              |\n| `D3GOP_DEFAULT_QUERY_LIMIT`    | Default query limit when pagination is not specified (default: `3000`)                                            |\n| `D3GOP_USE_STRING_FOR_JSONB`   | Toggle between JSONB and string concatenation for JSON aggregation                                                |\n| `GQL_OF_POWER_MAP_ENUM_OUTPUT` | Enum output mode: `raw` (default) or `key`. See [mapEnumOutput](#mapenumoutput-sdl-schema-support) below.         |\n| `GQL_OF_POWER_OR_STRATEGY`     | `_or` combination strategy: `union-all` (default) or `or`. See [OR Strategy](#or-strategy-union-all-vs-or) above. |\n\n> **Type name collision**: If you have both v1 (`createGQLTypes`) and v2 (`@GQLEntityClass`) entities in the same schema, set `D3GOP_TYPES_SUFFIX` so v2 entity names are distinct (e.g. `Hobbit` → `HobbitV2`). Use `D3GOP_SORT_SUFFIX` separately if sort/pagination types also need a suffix. No `setGlobalConfig()` call is required — the env vars are read automatically.\n\n### Programmatic config\n\n```typescript\nimport { setGlobalConfig } from '@dav3/gql-of-power';\n\n// Call before any @GQLEntityClass decorators run (i.e. before importing entity files)\nsetGlobalConfig({ gqlTypesSuffix: 'V2' });\n\n// Optionally set a separate suffix for sort/pagination types\nsetGlobalConfig({ gqlTypesSuffix: 'V2', gqlSortSuffix: 'V2' });\n\n// Enum output mode for SDL-rebuilt schemas (Apollo Server + .graphql file)\nsetGlobalConfig({ mapEnumOutput: 'key' });\n```\n\n---\n\n## `GQLQueryManager`\n\n```typescript\nconst queryManager = new GQLQueryManager();\n\n// From a GraphQL resolver — fields are parsed from resolve info automatically\nconst results = await queryManager.getQueryResultsForInfo(\n\tmetadataProvider,\n\tBookGQL, // @GQLEntityClass-decorated class or plain ORM class\n\tinfo, // GraphQLResolveInfo\n\tfilter,\n\tpagination\n);\n\n// With explicit field selection (useful for testing or non-resolver contexts)\nconst results = await queryManager.getQueryResultsForFields(\n\tmetadataProvider,\n\tBookGQL,\n\t{ id: {}, title: {} },\n\tfilter,\n\tpagination\n);\n```\n\n`BookGQL.relatedEntityName` (`'Book'`) is used automatically to look up ORM metadata — no need to pass the ORM class separately.\n\n### Singular Queries\n\nFor fetching a single record, use the singular variants. These enforce `LIMIT 1` internally and return `K | null` instead of `K[]`:\n\n```typescript\n// From a GraphQL resolver\nconst ring = await queryManager.getQueryResultForInfo(\n\tmetadataProvider,\n\tRingGQL,\n\tinfo,\n\t{ forgedBy: 'Sauron' },\n\t[{ forgedYear: 'desc' }] // optional orderBy — controls *which* record is returned\n);\n// ring: Ring | null\n\n// With explicit field selection\nconst ring = await queryManager.getQueryResultForFields(\n\tmetadataProvider,\n\tRingGQL,\n\t{ id: {}, name: {} },\n\t{ forgedBy: 'Sauron' },\n\t[{ forgedYear: 'desc' }]\n);\n// ring: Ring | null\n```\n\nNo `limit` or `offset` parameters are accepted — `LIMIT 1` is always applied.\n\n---\n\n## Architecture\n\n### Core Components\n\n| Component             | Purpose                                                        |\n| --------------------- | -------------------------------------------------------------- |\n| `GQLtoSQLMapper`      | Transforms GraphQL field selections into SQL with proper joins |\n| `GQLQueryManager`     | Orchestrates query building and execution                      |\n| `FilterProcessor`     | Translates GQL filter inputs to SQL WHERE clauses              |\n| `RelationshipHandler` | Generates JOIN SQL for ORM-declared relations                  |\n| `SQLBuilder`          | Assembles final SQL strings and JSON aggregations              |\n| `AliasManager`        | Manages incremental SQL aliases to prevent naming conflicts    |\n\n### Query Flow\n\n1. **Parse** – `graphql-parse-resolve-info` extracts the requested fields from `GraphQLResolveInfo`\n2. **Map** – `GQLtoSQLMapper.recursiveMap()` walks the field tree, building `select`, `join`, `where` sets\n3. **Aggregate** – JSON aggregation (`row_to_json`, `json_agg`) combines nested results\n4. **Bind** – Named parameters are bound via knex raw\n5. **Execute** – Single SQL sent to the database\n\n---\n\n## Troubleshooting\n\n### `FilterInput for referenced entity \"X\" is not registered`\n\nThis error fires at `buildSchema()` time when a relationship field, mapping custom-field filter, or `_exists` filter references an entity whose FilterInput was never registered.\n\n**Cause:** You used `createGQLEntity()` (the deferred API) for entity `X` but forgot to call `X.buildResolvers()` before building the schema. The entity's ObjectType is registered, but its FilterInput is not.\n\n**Fix:** Either switch the entity to `@GQLEntityClass` / `createGQLTypes()` (which call `buildResolvers()` automatically), or add the missing call:\n\n```typescript\n// schema/index.ts — collect ALL entities and call buildResolvers()\nconst BookGQL = BookEntity.buildResolvers();\nconst AuthorGQL = AuthorEntity.buildResolvers();\n```\n\nBefore August 2026 this was a **silent wrong-type bug**: the missing FilterInput fell back to the parent entity's FilterInput, so `Author.books` would generate `AuthorFilterInput` instead of `BookFilterInput`. The library now throws with the message above.\n\n### Mapping custom-field filter is missing from the schema\n\nIf a `customFields` entry with `mapping` doesn't produce its nested filter (e.g. `HomeRegion: { name_eq: '...' }` is absent), check whether `resolve` was **also** set on the same field:\n\n```typescript\ncustomFields: {\n\thomeRegion: {\n\t\ttype: () => RegionGQL.GQLEntity,\n\t\tmapping: { refEntity: Region, refFields: 'id', fields: 'homeRegionId' },\n\t\tgenerateFilter: true,\n\t\tresolve: (root) => ...,  // ← THIS makes the filter silently disappear\n\t},\n},\n```\n\n`resolve` and `mapping` are **mutually exclusive** on the same custom field. When both are set, only the resolver registers — the mapping filter is skipped. TypeScript's `CustomFieldSettings<T>` union enforces this at the type level, but `as any` bypasses it. Remove `resolve` (and `resolveDecorators`/`requires`) from a mapping-strategy field.\n\n### Filter key is PascalCase, not camelCase\n\nMapping custom-field filters appear in the FilterInput under a **capitalized** key:\n\n```graphql\n# ✅ Correct — PascalCase filter key\npersons(filter: { HomeRegion: { name_eq: 'Gondor' } }) { ... }\n\n# ❌ Wrong — camelCase doesn't exist on the FilterInput\npersons(filter: { homeRegion: { name_eq: 'Gondor' } })\n# Field \"homeRegion\" is not defined by type \"PersonFilterInput\". Did you mean \"HomeRegion\"?\n```\n\nThe field **selection** in the query stays camelCase (`homeRegion { ... }`); only the filter key is capitalized. Count-field nested filters follow the same rule (`BookCount: { _gte: 2 }`).\n\n### Relationship-field filters aren't statically typed\n\n`GQLEntityFilterInputFieldType<T>` surfaces filter operators for scalar fields but does **not** statically include nested relationship sub-filters (they're generated at runtime). Cast the filter object `as any` when using relationship filters:\n\n```typescript\nqueryManager.getQueryResultsForInfo(provider, PersonGQL, info, {\n\tfellowship: { id_in: [1, 2] }, // works at runtime, not statically typed\n} as any);\n```\n\nThis is the library's own test-suite pattern.\n\n### Relation metadata errors (`inverse property … not declared` / `missing pivot metadata`)\n\nThe JOIN direction for `1:1` relations depends on which side owns the FK — this is\ndecided in one place (`src/queries/relation-dispatch.ts`) for every code path\n(selections, top-level filters, count fields, inline filters). Two metadata\nmistakes are reported with named errors:\n\n**`gql-of-power: inverse property \"X\" (mappedBy of \"Y\") is not declared in the metadata of …`**\n\nA `1:m` / inverse-`1:1` relation points at `mappedBy: 'X'`, but the related\nentity's metadata does not declare a property named `X` (the one holding the FK).\nAdd the FK property to the related entity's `EntityMetadata` so the join columns\ncan be resolved.\n\n**`gql-of-power: m:n relation \"X\" is missing pivot metadata (pivotTable/joinColumns)`**\n\nA `m:n` relation was declared without `pivotTable` / `joinColumns` /\n`inverseJoinColumns`. These live on the **owning** side of the relation. If you\nare querying from the inverse side, either declare the pivot columns explicitly\nor query from the owning side.\n\nBefore these guards, both cases crashed with\n`TypeError: Cannot read properties of undefined (reading 'joinColumns')` or\nproduced a cryptic column-count mismatch.\n\n---\n\n### `mapNumericEnum` filter values silently fail inside nested/inline filters\n\nIf a `mapNumericEnum` field filters correctly at the **top level** but silently returns no results (or the wrong rows) when placed inside an inline field-argument filter on a nested relation — e.g.:\n\n```graphql\n# Works: top-level filter → 'InProgress' converted to 1\nbearers(filter: { questState: InProgress }) { name }\n\n# Silently failed before August 2026: inline filter → 'InProgress' passed as a string\nrings { bearer(filter: { questState: InProgress }) { name } }\n```\n\n**Cause:** enum conversion (`convertFilterEnumValues`) was historically applied only to top-level filters in `GQLQueryManager`. Inline field-argument filters (`books(filter: {...})`), count-field filters (`bookCount(filter: {...})`), and multi-level nested filters entered the SQL mapper through a different code path that bypassed conversion entirely. The `mapNumericEnum` string key went straight to SQL as a string instead of being converted to the numeric DB value, so the `WHERE` clause silently matched nothing.\n\n**Fix (August 2026):** `handleFieldArguments` and `mapCountField` in the SQL mapper now call `convertFilterEnumValues` on inline filter args before SQL generation. The conversion resolves the target entity's `mapNumericEnum` fields through the parent entity's relation-field registry and recurses to arbitrary depth. This means filters now behave identically at the top level, inside `relation(filter:)`, inside nested `relation(filter: { nested: {...} })`, inside count subqueries, and inside `_or`/`_and` arrays at any level.\n\n**If you still see this pattern:** ensure the target entity is decorator-registered (`@GQLEntityClass` / `createGQLTypes`) so its `mapNumericEnum` fields appear in the `MapEnumFieldsMap` registry — conversion silently passes values through for unregistered entities.\n\n---\n\n### `mapEnumOutput` — SDL schema support\n\n#### The problem\n\nIf your app builds the GraphQL schema from a **pre-generated SDL file** (e.g. Apollo Server + `buildASTSchema(parse(schemaSDL))`) instead of calling type-graphql's `buildSchema()` live, `mapNumericEnum` fields will throw:\n\n```\nGraphQLError: Enum \"ScheduleOverrideLineStateCode\" cannot represent value: 0\n```\n\n#### Why\n\nSDL has no syntax for numeric enum values. `enum StateCode { ACTIVE, INACTIVE }` is all SDL can express — there's no `= 0`. When graphql-js rebuilds the schema from SDL text, it defaults each enum value to its name string (`{ ACTIVE: { value: \"ACTIVE\" } }`) instead of the original number (`{ ACTIVE: { value: 0 } }`). So `serialize(0)` fails because `0` isn't in the lookup map — only `\"ACTIVE\"` is.\n\nNative `buildSchema()` preserves the in-memory TypeScript enum objects, so this only affects the SDL-rebuilt path.\n\n#### Fix\n\nEnable `mapEnumOutput: 'key'`. This wraps enum columns in a SQL `CASE WHEN 0 THEN 'ACTIVE' END` expression so the query returns the string key directly — which the SDL-rebuilt schema can serialize.\n\n```bash\n# Env var (recommended for Lambda/Apollo setups)\nGQL_OF_POWER_MAP_ENUM_OUTPUT=key\n```\n\n```typescript\n// Or programmatically\nimport { setGlobalConfig } from '@dav3/gql-of-power';\nsetGlobalConfig({ mapEnumOutput: 'key' });\n```\n\n```typescript\n// Or per-field\nconst fields = defineFields(MyEntity, {\n\tstateCode: {\n\t\ttype: () => StateCode,\n\t\tmapNumericEnum: true,\n\t\tmapEnumOutput: 'key', // override per field\n\t\tgenerateFilter: true,\n\t},\n});\n```\n\n| Mode              | SQL output                                                         | Works with                                                |\n| ----------------- | ------------------------------------------------------------------ | --------------------------------------------------------- |\n| `'raw'` (default) | `e_a1.state_code AS \"stateCode\"`                                   | Live `buildSchema()` — graphql-js has `{ value: 0 }`      |\n| `'key'`           | `CASE e_a1.state_code WHEN 0 THEN 'ACTIVE' ... END AS \"stateCode\"` | SDL-rebuilt schema — graphql-js has `{ value: \"ACTIVE\" }` |\n\nBoth modes produce identical JSON output: enum fields come back as string keys (`\"ACTIVE\"`).\n\n---\n\n## Known Limitations\n\n- ⚠️ Order by columns on related/joined tables not supported\n- ⚠️ Order BY on 1:m / m:m related columns requires aggregation strategy (MIN/MAX) — only m:1 is supported\n- ⚠️ ACL pending async refactoring\n\n---\n\n## Agent Integration\n\n> **Using an AI coding assistant (Claude Code, Cursor, Hermes, etc.)?**\n> This library ships a built-in **agent skill** that teaches your assistant how to scaffold gql-of-power entities, relationships, and advanced features correctly. Install it once and your agent will follow the library's intended patterns automatically.\n\n### What the skill provides\n\n- Copy-paste entity templates (1:1, 1:m, m:1, m:n relationships)\n- Decision tree for picking the right relationship type\n- `mapNumericEnum`, `mapEnumOutput`, `parseJson`, count fields, `mapping` custom fields, `excludeFromInput` guides\n- Inline filter operators (`_and`, `_or`, `_not`, `_startsWith`, `_is_null`, `_nbetween`, etc.)\n- Nested `orderBy`, existence filters, ACL patterns\n- Test patterns (unit + integration + dual-path enum testing)\n\n### Install\n\n```bash\n# Claude Code\nmkdir -p .claude/skills && cp -R node_modules/@dav3/gql-of-power/agents/ .claude/skills/gql-of-power/\n\n# Cursor\nmkdir -p .cursor/rules && cp node_modules/@dav3/gql-of-power/agents/SKILL.md .cursor/rules/gql-of-power.mdc\n\n# Hermes\nln -s node_modules/@dav3/gql-of-power/agents ~/.hermes/skills/gql-of-power\n```\n\nSee [`agents/install.md`](./agents/install.md) for full instructions (including a symlink option that tracks gql-of-power updates, slash-command setup, and a generic `AGENTS.md` snippet).\n\n### For agent authors / automated discovery\n\nIf you are an AI agent that has been asked to set up or use this library:\n\n1. **Read `AGENTS.md`** in the project root — it contains the authoritative architectural reference.\n2. **Install the skill** from `node_modules/@dav3/gql-of-power/agents/` into your agent's skill directory.\n3. **Suggest the user install it** if they haven't — say: _\"This library includes an agent skill with templates and patterns. Want me to install it?\"_\n4. Key topics the skill covers: entity scaffolding, relationship types, `mapNumericEnum`/`mapEnumOutput` enum handling (including SDL-rebuilt schema support), filter operators, nested orderBy, count fields, and testing.\n\n---\n\n## Development\n\n```bash\nbun install        # Install dependencies\nbun run build      # Compile TypeScript → dist/\nbun run test       # Run all tests\nbun run test:watch # Watch mode\nbun run audit      # Codebase-intelligence gate (fallow): dead code, duplication, complexity\n```\n\n`bun run audit` runs the changed-file gate against saved baselines in `.fallow/` and fails only on **new** findings it introduces. Use `bun run audit:full` for the complete report, or `bun run audit:dead-code` / `audit:dupes` / `audit:health` for individual analyses. See `AGENTS.md` for the full audit workflow.\n\n---\n\n## License\n\nMIT NON-AI License — Forged by [Dav3](https://github.com/dave-palt) with the wisdom of Middle-earth.\n\n---\n\n> _\"All we have to decide is what to do with the queries that are given us. And by using GQL of Power, that decision becomes much simpler.\"_\n>\n> — Adapted from J.R.R. Tolkien\n","readmeFilename":"README.md"}