{"id":15024884,"url":"https://github.com/apazzolini/pgr","last_synced_at":"2025-04-12T12:52:09.201Z","repository":{"id":32414561,"uuid":"132846476","full_name":"apazzolini/pgr","owner":"apazzolini","description":"A structured and easy way to execute queries against Postgres","archived":false,"fork":false,"pushed_at":"2023-01-06T01:57:54.000Z","size":1211,"stargazers_count":6,"open_issues_count":13,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-02-04T23:06:43.905Z","etag":null,"topics":["node-postgres","postgres","postgresql"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apazzolini.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":"2018-05-10T03:59:33.000Z","updated_at":"2021-11-19T18:38:00.000Z","dependencies_parsed_at":"2023-01-14T21:08:28.976Z","dependency_job_id":null,"html_url":"https://github.com/apazzolini/pgr","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apazzolini%2Fpgr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apazzolini%2Fpgr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apazzolini%2Fpgr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apazzolini%2Fpgr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apazzolini","download_url":"https://codeload.github.com/apazzolini/pgr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239644125,"owners_count":19673579,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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"],"created_at":"2024-09-24T20:01:07.426Z","updated_at":"2025-02-21T13:32:21.024Z","avatar_url":"https://github.com/apazzolini.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pgr\n\nThis module aims to provide a structured and easy way to execute queries against a Postgres DB. It's a good fit if you want more support than using the [pg](https://github.com/brianc/node-postgres) module by itself but don't want to use an ORM. Its main features include a tagged template string based query helper and a small wrapper around pg's actual query methods.\n\n## Installation\n\n`yarn add pgr`\n\n## Basic Example Usage\n\nOnce, in your application's entry point (before you want to run a query):\n\n```js\nimport { createPool } from 'pgr'\n\ncreatePool('myPoolName', {\n    // The options here are exactly what you can provide to pg, such as\n    host: 'localhost',\n    user: 'Andre',\n    password: '',\n    database: 'mydb',\n})\n```\n\n\u003e If you only create one pool, you don't need to specify its name when running queries. For multiple pool support, check out the advanced usage section below.\n\nLater on:\n\n```js\nimport { query, sql } from 'pgr'\n\nconst value = 42\n\nconst rows = await query(sql`\n    SELECT *\n    FROM my_table\n    WHERE some_col = ${value}\n`)\n```\n\nThat's it! The `sql` tagged template string will run your statement through [pgformat](https://github.com/datalanche/node-pg-format) (always with %L) to properly escape any dangerous variables and invoke it with your previously created pool.\n\n## sql.if\n\nI find that I often want to dynamically construct my statements based on the truthiness of a given variable. This allows for compact, powerful query methods similar to what you might find in an ORM. Enter `sql.if`:\n\n### Simple mode (your test variable and arg are the same)\n\n\u003e Note: For purposes of `sql.if`, the number 0 is treated as truthy, and an empty array is treated as falsy.\n\n```js\nimport { query, sql } from 'pgr'\n\nconst findUsers = async ({ id, accountId, emails, roles }) =\u003e\n    query(sql`\n        SELECT *\n        FROM users\n        WHERE status = 'active'\n            ${sql.if('AND id = ?', id)}\n            ${sql.if('AND email = ?', email)}\n            ${sql.if('AND role IN (?)', roles)}\n    `)\n```\n\n```js\nawait findUsers({ id: 73 })\n```\n```sql\nSELECT *\nFROM users\nWHERE status = 'active'\n    AND id = '73'\n```\n\n\u003e Your variable will get subbed in for the question mark in your expression. If there is no question mark, the variable will be used to test if the expression should be added as-is.\n\n```js\nawait findUsers({ accountId: 1, roles: ['admin', 'superadmin'] })\n```\n```sql\nSELECT *\nFROM users\nWHERE status = 'active'\n    AND account_id = '1'\n    AND role IN ('admin', 'superadmin')\n```\n\n```js\nawait findUsers({ accountId: 1, roles: [] }) // An empty array is treated as falsy\n```\n```sql\nSELECT *\nFROM users\nWHERE status = 'active'\n    AND account_id = '1'\n```\n\n### Complex mode (different test and arg variables, arg is optional)\n\n```js\nimport { query, sql } from 'pgr'\n\nconst STATUSES = [1, 2, 3]\n\nconst findRelationships = async ({ id, includeOngoing }) =\u003e {\n    const checkStatus = ... // External function returning true/false\n\n    return query(sql`\n        SELECT *\n        FROM relationships\n        WHERE from_id = ${id}\n            ${sql.if({ test: includeOngoing, expr: 'AND end_date IS NULL' })}\n            ${sql.if({ test: checkStatus, expr: 'AND status IN (?)', arg: STATUSES })}\n    `)\n}\n```\n\n```js\nawait findRelationships({ id: 1, includeOngoing: true })\n```\n```sql\n(assuming checkStatus was true):\n\nSELECT *\nFROM relationships\nWHERE from_id =1\n    AND end_date IS NULL\n    AND status IN ('1','2','3')\n```\n\n## sql.raw\n\nYou may have standard query fragments that you build up and inject into many queries. You might also have situations where pgformat's substitution doesn't achieve what you need. The escape hatch that you can use **carefully** is `sql.raw`.\n\n```js\nconst currentUser = { purchasedItems: [10, 20] }\nconst fragment = sql`AND allowed_items IN (${currentUser.purchasedItems})`\n\nconst statement = sql`\n    SELECT *\n    FROM items\n    WHERE on_sale = true\n        ${sql.raw(fragment)}\n```\n```sql\nSELECT *\nFROM items\nWHERE on_sale = true\n    AND allowed_items IN ('10','20')\n```\n\nNote that fragments must themselves be run through `sql` if you need escaping. Don't be like little Bobby Tables.\n\n```js\nconst name = \"Robert'); DROP TABLE Students; --\"\n\nconst statement = sql`\n    SELECT *\n    FROM oh_no\n    WHERE name IN ('${sql.raw(fragment)}')\n```\n```sql\nSELECT *\nFROM oh_no\nWHERE name IN ('Robert'); DROP TABLE Students; --')\n```\n\n## query, query.one, query.transaction\n\nWe've seen the most simple form of query, but it can also take a second `options` argument:\n\n```js\nconst rows = await query(sql`SELECT ...`, {\n    debug: false, // Logs the statement to the console before running it\n    debugOnly: false, // Logs the statement to the console and does NOT run it\n    poolName: '', // Runs the query with a client of the specified pool name\n    rowMapper: row =\u003e {}, // A (synchronous) function to run on every row in the result\n})\n\nconst knownEmails = await query(sql`SELECT email FROM users`, {\n    rowMapper: row =\u003e row.email,\n})\n```\n\n### query.one\n\nInvoked exactly like `query`, except that instead of returning an array of rows, it will return one object. If your query results in no rows, it will return a null. If your query returns more than one row, it will throw an Error. You can also use rowMapper here.\n\n```js\nconst { email } = await query.one(sql`SELECT email FROM users WHERE id = ${currentUserId}`)\nconsole.log(email) // 'apazzolini@test.test'\n```\n\n### query.transaction\n\nYou can also run multiple queries inside of a transaction:\n\n```js\nconst result = await query.transaction(async tquery =\u003e {\n    // Inside this function, you should take care to use tquery\n    // instead of query or you may run into deadlocks.\n\n    // tquery behaves exactly like query (and also has tquery.one)\n    return 'myResult'\n})\n\nconsole.log(result) // 'myResult'\n```\n\n## Metrics\n\n`pgr` stores average execution time for your queries along with the number of times the query has happened. This is done by taking the base query (pre variable insertion) and giving it an ID based on its hash. This allows aggregating metrics even if a query is executed multiple times with different arguments.\n\n```js\nconst { metrics } = getPool('default')\nconsole.log(metrics.queries) // { [id]: { baseStatement: '...', count: 1, avgMs: 100 } }\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapazzolini%2Fpgr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapazzolini%2Fpgr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapazzolini%2Fpgr/lists"}