{"id":20348489,"url":"https://github.com/onebeyond/handy-postgres","last_synced_at":"2025-04-12T01:14:53.244Z","repository":{"id":38426216,"uuid":"194239572","full_name":"onebeyond/handy-postgres","owner":"onebeyond","description":"A handy, safe API to deal with common PG operations","archived":false,"fork":false,"pushed_at":"2023-07-19T10:45:11.000Z","size":740,"stargazers_count":6,"open_issues_count":23,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-12T01:14:47.261Z","etag":null,"topics":["hacktoberfest"],"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/onebeyond.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-28T08:44:24.000Z","updated_at":"2023-01-10T11:23:23.000Z","dependencies_parsed_at":"2024-11-15T01:01:43.975Z","dependency_job_id":null,"html_url":"https://github.com/onebeyond/handy-postgres","commit_stats":null,"previous_names":["guidesmiths/handy-postgres"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onebeyond%2Fhandy-postgres","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onebeyond%2Fhandy-postgres/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onebeyond%2Fhandy-postgres/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/onebeyond%2Fhandy-postgres/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/onebeyond","download_url":"https://codeload.github.com/onebeyond/handy-postgres/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248501861,"owners_count":21114684,"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":["hacktoberfest"],"created_at":"2024-11-14T22:20:42.575Z","updated_at":"2025-04-12T01:14:53.225Z","avatar_url":"https://github.com/onebeyond.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Maintainability](https://api.codeclimate.com/v1/badges/80036456f9bda3ae0316/maintainability)](https://codeclimate.com/github/onebeyond/handy-postgres/maintainability)\n[![Test Coverage](https://api.codeclimate.com/v1/badges/80036456f9bda3ae0316/test_coverage)](https://codeclimate.com/github/onebeyond/handy-postgres/test_coverage)\n\n# handy-postgres\n\nA handy API for Postgres which uses promises and [this super library](https://github.com/brianc/node-postgres), which also uses pool handling.\n\n## Configuration\n\n```js\n\"pg\": {\n  \"user\": \"postgres\",\n  \"database\": \"postgres\",\n  \"password\": \"password\",\n  \"host\": \"localhost\",\n  \"port\": 5432,\n  \"max\": 10, // Maximum number of connections in the pool\n  \"sql\": \"myfolder/sql\", // optional location for sql files\n  \"idleTimeoutMillis\": 30000,\n}\n```\n\n### Multiple Connections\n\nYou can specify a different config path by passing it in when instantiating the component:\n\n```js\nHandyPg({ configPath: 'mykey' });\n```\n\nYou can find configuration examples [here](https://github.com/guidesmiths/handy-postgres/blob/master/test/e2e/config.test.js)\n\n### Loading SQL Files\n\nBy specifying the location for sql files, it will automatically read and cache all of the sql in the folder for use in your model, reducing boilerplate.\n\nFile:\n\n```sh\n/src/model/sql/test.sql\n```\n\nHow to use these shorthand functions is explained below.\n\n## The API\n\nAfter creating a Handy PG component, the following methods will be available:\n\n| Property  | Description | Promise result |\n| ------------- | ------------- | ----------- |\n| withTransaction | Begin a new named transaction `pg.withTransaction(next)` | `(connection) =\u003e {}` |\n| withConnection | Claims a connection from the pool `pg.withConnection(next)` |\n| query | Execute an unformatted query using shorthands `SELECT $1::INT AS number` defaulting to a raw query if it cannot find one | `(result) =\u003e {}` |\n| streamQuery | Same as `query`, but returns a stream ('data', 'error', 'end'). Multiple queries not possible (throws error). | `(stream) =\u003e {}` |\n| formattedQuery | Execute a formatted query using shorthands `SELECT %L::INT AS %I` | `(result) =\u003e {}` |\n| formattedStreamQuery | Same as formattedQuery but returns a stream ('data', 'error', 'end'). Multiple queries not possible (throws error). | `(stream) =\u003e {}` |\n| insert | Insert data `(table, data, options)` (object `options` is optional. It accepts the boolean property `returning` to retrieve inserted data) | `() =\u003e {}` |\n| update | Update data `(table, update, where, options)` (objects `where` and `options` are optional. `where` accepts where conditions, `options` is analogous to `insert` usage)| `() =\u003e {}` |\n| schema | Sets a schema and returns the query operations to use with that schema `(schema)`| `({ query, formattedQuery, insert, update }) =\u003e {}` |\n| explain | Execute an explain plan for an unformatted query |\n| formattedExplain | Execute an explain plan for a formatted query |\n| copyFrom | Copy table contents from read stream |\n| copyTo | Copy table contents to write stream |\n\nYou can find some examples for query, formattedQuery, insert and update [here](https://github.com/guidesmiths/handy-postgres/blob/master/test/e2e/query.test.js)\n\n## Transactions\n\nTransactions are made easier via a helper `withTransaction` block.  This helper takes a function that receives a 'transaction' object, returning a promise chain where all your operations will be placed. The 'transaction' object gives you the same 'query' helpers as explained above, reusing a single connection for all operations within the tx. The usual rollback, commit and begin operations are also exposed but they are abstracted away by the 'withTransaction' helper.\n\n\n```js\npg.withTransaction((tx) =\u003e\n  Promise.all([\n    tx.schema('myschema').insert('films', myFilm1),\n    tx.schema('myschema').insert('films', myFilm2),\n  ])\n)\n.catch((err) =\u003e {\n  // Error occurred (but it still rolled back and closed connection)\n})\n```\n\nYou can find some transactions examples [here](https://github.com/guidesmiths/handy-postgres/blob/master/test/e2e/tx.test.js)\n\n### Isolation Levels\n\nSometimes you will need to use a different transaction isolation level than the default one. You can [read more about this here](https://www.postgresql.org/docs/9.1/static/transaction-iso.html).\n\nhandy-postgres lets you specify your own in config:\n\n```\n{\n  withSql: {\n    ...\n    isolationLevel: 'REPEATABLE READ',\n    ...\n  }\n}\n```\nAlso, you could override this configuration on specific transactions by passing the isolation level as second argument whenever you use the `withTransaction` operation:\n\n```js\npg.withTransaction((tx) =\u003e\n  Promise.all([\n    tx.schema('myschema').insert('films', myFilm1),\n    tx.schema('myschema').insert('films', myFilm2),\n  ]), 'SERIALIZABLE' // I want this transaction in particular to use the SERIALIZABLE isolation level\n)\n.catch((err) =\u003e {\n  // Error occurred (but it still rolled back and closed connection)\n})\n```\n## Migrations\n\nHandy postgres uses [marv](https://github.com/guidesmiths/marv) to offer migration support. To use it, you need to specify marv options in migrations field. It will use handy-postgres configuration as connection options for marv.\n\n```js\n\"pg\": {\n  // ...\n  \"migrations\": [{ \"directory\": \"src/migrations\", \"namespace\": \"test\", \"filter\": \"\\\\.sql$\" }],\n}\n```\n\nYou can also specify a different migration user, e.g.\n\n```js\n\"pg\": {\n  \"migrationsUser\": \"marv\",\n  \"migrationsPassword\": \"secret\",\n  \"migrations\": [{ \"directory\": \"src/migrations\", \"namespace\": \"test\", \"filter\": \"\\\\.sql$\" }],\n\n```\n\n## Streams\nIf you would like to query a very large data set, you may have to use a stream, here's how:\n\n```js\nPromise.resolve()\n  .then(() =\u003e pg.streamQuery('SELECT loads FROM data'))\n  .then((stream) =\u003e {\n     return new Promise((resolve, reject) =\u003e {\n       stream.on('data', (data) =\u003e {\n         // do something with data...\n       });\n       stream.on('error', reject);\n       stream.on('end', () =\u003e resolve({ result: /*...*/ }));\n    });\n  })\n```\nAlso check out [promisepipe](https://www.npmjs.com/package/promisepipe) and [promise-streams](https://www.npmjs.com/package/promise-streams)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonebeyond%2Fhandy-postgres","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fonebeyond%2Fhandy-postgres","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fonebeyond%2Fhandy-postgres/lists"}