{"id":40841741,"url":"https://github.com/inad9300/pgeon","last_synced_at":"2026-01-21T23:05:52.946Z","repository":{"id":47791695,"uuid":"202780740","full_name":"inad9300/pgeon","owner":"inad9300","description":"🐦 A Postgres client for Node.js which type-checks your SQL queries at compile time!","archived":false,"fork":false,"pushed_at":"2021-10-18T20:18:24.000Z","size":540,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-16T07:21:04.450Z","etag":null,"topics":["node-postgres","postgres","postgresql","sql","static-analysis","type-safety","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/inad9300.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-16T18:36:10.000Z","updated_at":"2024-05-17T22:35:29.000Z","dependencies_parsed_at":"2022-09-05T04:02:06.806Z","dependency_job_id":null,"html_url":"https://github.com/inad9300/pgeon","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/inad9300/pgeon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inad9300%2Fpgeon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inad9300%2Fpgeon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inad9300%2Fpgeon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inad9300%2Fpgeon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/inad9300","download_url":"https://codeload.github.com/inad9300/pgeon/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/inad9300%2Fpgeon/sbom","scorecard":{"id":486748,"data":{"date":"2025-08-11","repo":{"name":"github.com/inad9300/pgeon","commit":"01b033c22302736fe430e9252b8b7fcec6f2bd88"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"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":"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":"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":"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":"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":"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":"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":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU Affero General Public License v3.0: 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":"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":"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":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: containerImage not pinned by hash: Dockerfile.node:1: pin your Docker image by updating node:16.10.0-alpine to node:16.10.0-alpine@sha256:3da1c08529fef7007d57d2133a0feb0fa8c60fdd4ad6691978f9dfcb0365b430","Warn: containerImage not pinned by hash: Dockerfile.postgres:1: pin your Docker image by updating postgres:14.0-alpine to postgres:14.0-alpine@sha256:1cf551de75fd602ebc94ccda93305a4e411f941bf9465f59d850bdcfd474ca52","Info:   0 out of   2 containerImage dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"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":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"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-19T18:00:22.650Z","repository_id":47791695,"created_at":"2025-08-19T18:00:22.650Z","updated_at":"2025-08-19T18:00:22.650Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28646684,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-21T21:29:11.980Z","status":"ssl_error","status_checked_at":"2026-01-21T21:24:31.872Z","response_time":86,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: 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":["node-postgres","postgres","postgresql","sql","static-analysis","type-safety","typescript"],"created_at":"2026-01-21T23:05:52.260Z","updated_at":"2026-01-21T23:05:52.929Z","avatar_url":"https://github.com/inad9300.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"_Work in progress..._\n\n# pgeon\n\nThis library is:\n1. A zero-dependencies, decently fast Postgres client.\n2. A webpack loader that type-checks your SQL queries at compile time (seriously).\n\n\n## Installation\n\n```sh\nnpm install --save pgeon\n```\n\n\n## Example\n\nFor a first look, check out the small [example application](./example.ts) and its corresponding [webpack configuration](./example.webpack.config.ts). Provided Docker is running, you can try starting it with the command below. Notice that there is a type error which is caught _at compile time!_\n\n```sh\n./docker-npm run example\n```\n\n\n## Postgres client\n\nA from-scratch implementation of the Postgres protocol covering most common use cases. Its features include:\n- Connection pooling\n- Secure database connections\n- Support for most common data types (with more in the horizon)\n- Well-defined mapping between Postgres and JavaScript types\n- Query cancellation\n- Basic transaction management\n- Usage of Postgres' binary data format\n- Query preparation for SQL injection prevention\n\n### Connection pool\n\nThe first step towards executing useful queries is starting a connection pool.\n\n```ts\nimport { newPool } from 'pgeon/postgres-client'\n\nexport const db = newPool()\n```\n\nIf no options are provided, [standard Postgres environmental variables](https://postgresql.org/docs/current/libpq-envars.html) will be read and default values used. Explicit parameters can be provided to configure the database connection and pool limits.\n\n```ts\nimport { newPool } from 'pgeon/postgres-client'\n\nexport const db = newPool({\n   host: 'https://example.org',\n   port: 41100,\n   username: 'john_doe',\n   password: 'aV27FGH!!bVxpQyyBukKyQ5\u0026#TzX^)mg5%JzDuZKuA*xi(uh5s)%zZ!2CCY\u0026(@5T',\n   minConnections: 1,\n   maxConnections: 16\n})\n```\n\n### Query execution\n\nThrough a connection pool, queries can be `run()`. Queries with no dynamic parts on them (save their parameters) should be defined using the `sql` template literal tag. This allows for static type checking later on, such that the types of the columns returned by the query are taken into account at compile time, just like for any regular TypeScript function. For this reason, it is important that `sql` is not aliased, and that no other template literal tag named the same exists elsewhere in the codebase.\n\nTo prevent SQL injection, template literal placeholders are replaced with Postgres query placeholders, and the query is prepared and executed in separate steps.\n\n```ts\nimport { sql } from 'pgeon/postgres-client'\nimport { db } from './db'\n\nconst name = 'john'\n\ndb\n   .run(sql`select * from people where name = ${name}`)\n   .then(queryResult =\u003e console.debug(queryResult))\n```\n\nThe same method accepts dynamic queries too. Parameter SQL injection is prevented in the same way as for static queries.\n\n```ts\nimport { db } from './db'\n\nconst dynamicCriteria = true ? 'name = $1' : 'nickname = $1'\n\nconst name = 'john'\n\ndb\n   .run({\n      sql: `select * from people where ${dynamicCriteria}`,\n      params: [name]\n   })\n   .then(queryResult =\u003e console.debug(queryResult))\n```\n\n\n## webpack loader\n\nIn order to enable compile-time checks of static SQL queries, the [webpack loader](./webpack-loader.ts) must be run _before_ your TypeScript loader of choice. In webpack, this means placing it _after_ said TypeScript loader in the webpack configuration.\n\nNote that in order to write the webpack configuration in TypeScript, as well as to be able to reference loaders written in TypeScript directly, [ts-node](https://github.com/TypeStrong/ts-node) is needed as a dependency.\n\n```ts\nimport { Configuration } from 'webpack'\n\nconst webpackConfig: Configuration = {\n   entry: './main.ts',\n   target: 'node',\n   module: {\n      rules: [{\n         test: /\\.ts$/,\n         use: ['ts-loader', 'pgeon/webpack-loader.ts']\n      }]\n   },\n   resolve: {\n      extensions: ['.ts']\n   }\n}\n\nexport default webpackConfig\n```\n\nAs an example, the following code fails at compile time due to the type mismatch it introduces.\n\n```ts\nimport { newPool, sql } from 'pgeon/postgres-client'\n\nconst db = newPool()\n\ndb\n   .run(sql`select 1 as number`)\n   .then(queryResult =\u003e {\n      const one: string = queryResult.rows[0].number\n      console.debug(one)\n   })\n```\n\nTypeScript will emit a regular error, as illustrated below. Notice that all returned values are assumed to be nullable, unless they are known to refer to a non-nullable database column, as Postgres does not offer better information in this regard.\n\n```\nERROR in /example.ts(8,11)\n  TS2322: Type 'number | null' is not assignable to type 'string'.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finad9300%2Fpgeon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Finad9300%2Fpgeon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Finad9300%2Fpgeon/lists"}