From 9c201ea08ca405f8c1cfad19330d1bb6a1f84e46 Mon Sep 17 00:00:00 2001 From: Andy Edwards Date: Thu, 16 May 2024 14:59:14 -0500 Subject: [PATCH] feat: initial code commit --- .gitignore | 2 + README.md | 23 +++- package.json | 31 ++++- pnpm-lock.yaml | 322 ++++++++++++++++++++++++++++++++++++++++--- src/index.ts | 25 ++++ test/index.test.ts | 134 ++++++++++++++++++ toolchain.config.cjs | 4 +- 7 files changed, 510 insertions(+), 31 deletions(-) create mode 100644 src/index.ts create mode 100644 test/index.test.ts diff --git a/.gitignore b/.gitignore index e451df9..0a5db37 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ .nyc_output node_modules /coverage +/.pgpass +/.get-pg-configrc.json \ No newline at end of file diff --git a/README.md b/README.md index cb6be89..cce48c2 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,22 @@ -# @jcoreio/get-pg-options +# @jcoreio/get-pg-config -convenience wrapper for pg-connection-string/pgpass +apply default postgres connection config from dotfiles and .pgpass -[![CircleCI](https://circleci.com/gh/jcoreio/get-pg-options.svg?style=svg)](https://circleci.com/gh/jcoreio/get-pg-options) -[![Coverage Status](https://codecov.io/gh/jcoreio/get-pg-options/branch/master/graph/badge.svg)](https://codecov.io/gh/jcoreio/get-pg-options) +[![CircleCI](https://circleci.com/gh/jcoreio/get-pg-config.svg?style=svg)](https://circleci.com/gh/jcoreio/get-pg-config) +[![Coverage Status](https://codecov.io/gh/jcoreio/get-pg-config/branch/master/graph/badge.svg)](https://codecov.io/gh/jcoreio/get-pg-config) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) -[![npm version](https://badge.fury.io/js/%40jcoreio%2Fget-pg-options.svg)](https://badge.fury.io/js/%40jcoreio%2Fget-pg-options) +[![npm version](https://badge.fury.io/js/%40jcoreio%2Fget-pg-config.svg)](https://badge.fury.io/js/%40jcoreio%2Fget-pg-config) + +This solves two minor problems with `pg`'s default connection parameters: + +- it doesn't read `~/.pgpass`/`PGPASSFILE` +- `user` defaults to the OS user. In our work we always use Docker and the `postgres` user, + so we can configure that as the default with the following in `package.json` or `.get-pg-configrc` etc: + ```json + "get-pg-config": { + "defaults": { + "user": "postgres" + } + } + ``` diff --git a/package.json b/package.json index f7ba961..6ed497e 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,13 @@ { - "name": "@jcoreio/get-pg-options", - "description": "convenience wrapper for pg-connection-string/pgpass", + "name": "@jcoreio/get-pg-config", + "description": "apply default postgres connection config from dotfiles and .pgpass", "repository": { "type": "git", - "url": "https://github.com/jcoreio/get-pg-options.git" + "url": "https://github.com/jcoreio/get-pg-config.git" }, - "homepage": "https://github.com/jcoreio/get-pg-options", + "homepage": "https://github.com/jcoreio/get-pg-config", "bugs": { - "url": "https://github.com/jcoreio/get-pg-options/issues" + "url": "https://github.com/jcoreio/get-pg-config/issues" }, "author": "Andy Edwards", "license": "MIT", @@ -26,11 +26,18 @@ "@jcoreio/toolchain-mocha": "^4.5.5", "@jcoreio/toolchain-semantic-release": "^4.5.5", "@jcoreio/toolchain-typescript": "^4.5.5", + "@types/chai": "^4.0.0", + "@types/chai-subset": "^1.3.5", + "@types/mocha": "^10.0.6", + "@types/pg": "^8.11.6", "@typescript-eslint/eslint-plugin": "^7.6.0", "@typescript-eslint/parser": "^7.6.0", + "chai": "^4.0.0", + "chai-subset": "^1.6.0", "eslint": "^8.56.0", "eslint-plugin-no-only-tests": "^3.1.0", "mocha": "^10.2.0", + "pg": "^8.11.5", "typescript": "^5.1.0" }, "version": "0.0.0-development", @@ -41,11 +48,23 @@ "test": "toolchain test", "prepublishOnly": "echo This package is meant to be published by semantic-release from the dist build directory. && exit 1" }, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./dist/package.json", + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + } + }, "engines": { "node": ">=16" }, "packageManager": "pnpm@8.11.0", "dependencies": { - "@babel/runtime": "^7.18.6" + "@babel/runtime": "^7.18.6", + "cosmiconfig": "^9.0.0", + "pg": "^8.11.5", + "pgpass": "^1.0.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66b5328..64a4afc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ dependencies: '@babel/runtime': specifier: ^7.18.6 version: 7.24.5 + cosmiconfig: + specifier: ^9.0.0 + version: 9.0.0(typescript@5.4.5) + pg: + specifier: ^8.11.5 + version: 8.11.5 + pgpass: + specifier: ^1.0.5 + version: 1.0.5 devDependencies: '@jcoreio/eslint-plugin-implicit-dependencies': @@ -31,12 +40,30 @@ devDependencies: '@jcoreio/toolchain-typescript': specifier: ^4.5.5 version: 4.5.5(eslint@8.57.0)(typescript@5.4.5) + '@types/chai': + specifier: ^4.0.0 + version: 4.3.16 + '@types/chai-subset': + specifier: ^1.3.5 + version: 1.3.5 + '@types/mocha': + specifier: ^10.0.6 + version: 10.0.6 + '@types/pg': + specifier: ^8.11.6 + version: 8.11.6 '@typescript-eslint/eslint-plugin': specifier: ^7.6.0 version: 7.9.0(@typescript-eslint/parser@7.9.0)(eslint@8.57.0)(typescript@5.4.5) '@typescript-eslint/parser': specifier: ^7.6.0 version: 7.9.0(eslint@8.57.0)(typescript@5.4.5) + chai: + specifier: ^4.0.0 + version: 4.4.1 + chai-subset: + specifier: ^1.6.0 + version: 1.6.0 eslint: specifier: ^8.56.0 version: 8.57.0 @@ -63,6 +90,7 @@ packages: /@babel/cli@7.24.5(@babel/core@7.24.5): resolution: {integrity: sha512-2qg1mYtJRsOOWF6IUwLP5jI42P8Cc0hQ5TmnjLrik/4DKouO8dFJN80HEz81VmVeUs97yuuf3vQ/9j7Elrcjlg==} engines: {node: '>=6.9.0'} + hasBin: true peerDependencies: '@babel/core': ^7.0.0-0 dependencies: @@ -85,7 +113,6 @@ packages: dependencies: '@babel/highlight': 7.24.5 picocolors: 1.0.1 - dev: true /@babel/compat-data@7.24.4: resolution: {integrity: sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==} @@ -322,7 +349,6 @@ packages: /@babel/helper-validator-identifier@7.24.5: resolution: {integrity: sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} @@ -357,7 +383,6 @@ packages: chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.1 - dev: true /@babel/parser@7.24.5: resolution: {integrity: sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==} @@ -1597,6 +1622,34 @@ packages: fastq: 1.17.1 dev: true + /@types/chai-subset@1.3.5: + resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==} + dependencies: + '@types/chai': 4.3.16 + dev: true + + /@types/chai@4.3.16: + resolution: {integrity: sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==} + dev: true + + /@types/mocha@10.0.6: + resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} + dev: true + + /@types/node@20.12.12: + resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/pg@8.11.6: + resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==} + dependencies: + '@types/node': 20.12.12 + pg-protocol: 1.6.1 + pg-types: 4.0.2 + dev: true + /@types/validate-npm-package-name@4.0.2: resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} dev: true @@ -1788,7 +1841,6 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -1829,13 +1881,16 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true /array-union@2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true + /assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /babel-parse-wild-code@2.1.5: resolution: {integrity: sha512-PxrFABFZZRi8X4BfMsptUOMGwMcSyQVn0D4kR2/uhUSi0fP1s9vkt39axHjwZlCEJS9tbwAdEYLCd+R3syKRrw==} dependencies: @@ -1967,7 +2022,6 @@ packages: /callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true /camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} @@ -1983,6 +2037,24 @@ packages: resolution: {integrity: sha512-p407+D1tIkDvsEAPS22lJxLQQaG8OTBEqo0KhzfABGk0TU4juBNDSfH0hyAp/HRyx+M8L17z/ltyhxh27FTfQg==} dev: true + /chai-subset@1.6.0: + resolution: {integrity: sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug==} + engines: {node: '>=4'} + dev: true + + /chai@4.4.1: + resolution: {integrity: sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.3 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + /chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -1990,7 +2062,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -2005,6 +2076,12 @@ packages: engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} dev: true + /check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + dependencies: + get-func-name: 2.0.2 + dev: true + /chokidar@3.5.3: resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} @@ -2086,7 +2163,6 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: true /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -2097,7 +2173,6 @@ packages: /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -2139,6 +2214,22 @@ packages: browserslist: 4.23.0 dev: true + /cosmiconfig@9.0.0(typescript@5.4.5): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + typescript: 5.4.5 + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2175,6 +2266,13 @@ packages: resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==} dev: true + /deep-eql@4.1.3: + resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==} + engines: {node: '>=6'} + dependencies: + type-detect: 4.0.8 + dev: true + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -2222,6 +2320,17 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: false + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + /es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} dev: true @@ -2234,7 +2343,6 @@ packages: /escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: true /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} @@ -2243,6 +2351,7 @@ packages: /eslint-config-prettier@8.10.0(eslint@8.57.0): resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} + hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: @@ -2566,6 +2675,10 @@ packages: engines: {node: '>=18'} dev: true + /get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + dev: true + /get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -2652,7 +2765,6 @@ packages: /has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -2704,7 +2816,6 @@ packages: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -2727,6 +2838,10 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -2915,7 +3030,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} @@ -2930,7 +3044,6 @@ packages: hasBin: true dependencies: argparse: 2.0.1 - dev: true /jsesc@0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} @@ -2945,6 +3058,10 @@ packages: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} dev: true + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: false + /json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} dev: true @@ -2995,6 +3112,10 @@ packages: engines: {node: '>=14'} dev: true + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + dev: false + /lint-staged@15.2.2: resolution: {integrity: sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==} engines: {node: '>=18.12.0'} @@ -3078,6 +3199,12 @@ packages: wrap-ansi: 9.0.0 dev: true + /loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + dependencies: + get-func-name: 2.0.2 + dev: true + /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -3257,6 +3384,10 @@ packages: - supports-color dev: true + /obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + dev: true + /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -3360,7 +3491,16 @@ packages: engines: {node: '>=6'} dependencies: callsites: 3.1.0 - dev: true + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.24.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: false /path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} @@ -3396,9 +3536,90 @@ packages: engines: {node: '>=8'} dev: true + /pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + + /pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + requiresBuild: true + dev: false + optional: true + + /pg-connection-string@2.6.4: + resolution: {integrity: sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==} + dev: false + + /pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + /pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + dev: true + + /pg-pool@3.6.2(pg@8.11.5): + resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} + peerDependencies: + pg: '>=8.0' + dependencies: + pg: 8.11.5 + dev: false + + /pg-protocol@1.6.1: + resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + + /pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + dev: false + + /pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + dev: true + + /pg@8.11.5: + resolution: {integrity: sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + dependencies: + pg-connection-string: 2.6.4 + pg-pool: 3.6.2(pg@8.11.5) + pg-protocol: 1.6.1 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + dev: false + + /pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + dependencies: + split2: 4.2.0 + dev: false + /picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -3441,6 +3662,54 @@ packages: find-up: 3.0.0 dev: true + /postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + dev: false + + /postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + dev: true + + /postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + dev: false + + /postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + dependencies: + obuf: 1.1.2 + dev: true + + /postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + dev: false + + /postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + dev: true + + /postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + dependencies: + xtend: 4.0.2 + dev: false + + /postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + dev: true + + /postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + dev: true + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3551,7 +3820,6 @@ packages: /resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - dev: true /resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} @@ -3704,6 +3972,11 @@ packages: which: 2.0.2 dev: true + /split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + dev: false + /sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -3770,7 +4043,6 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -3836,6 +4108,11 @@ packages: prelude-ls: 1.2.1 dev: true + /type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + dev: true + /type-fest@0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -3856,6 +4133,9 @@ packages: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} hasBin: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} dev: true /unicode-canonical-property-names-ecmascript@2.0.0: @@ -3888,6 +4168,7 @@ packages: /update-browserslist-db@1.0.16(browserslist@4.23.0): resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: @@ -3972,6 +4253,11 @@ packages: typedarray-to-buffer: 3.1.5 dev: true + /xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + dev: false + /y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} dev: true diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..f587cdc --- /dev/null +++ b/src/index.ts @@ -0,0 +1,25 @@ +import { cosmiconfig } from 'cosmiconfig' +import { type ClientConfig } from 'pg' +import ConnectionParameters from 'pg/lib/connection-parameters' +// @ts-expect-error not typed +import pgpass from 'pgpass' + +export async function getPgConfig(given?: ClientConfig): Promise { + const defaults = + (await cosmiconfig('get-pg-config').search())?.config?.defaults || {} + const base = { ...given } + if (defaults) { + for (const key in defaults) { + if (defaults[key] != null && (base as any)[key] == null) { + ;(base as any)[key] = defaults[key] + } + } + } + const defaulted = new ConnectionParameters(base) + if (base.user) defaulted.user = base.user + const result = { ...defaulted, password: defaulted.password } + if (!result.password) { + result.password = await new Promise((resolve) => pgpass(result, resolve)) + } + return result +} diff --git a/test/index.test.ts b/test/index.test.ts new file mode 100644 index 0000000..0bf6bd3 --- /dev/null +++ b/test/index.test.ts @@ -0,0 +1,134 @@ +import { describe, it } from 'mocha' +import chai, { expect } from 'chai' +import chaiSubset from 'chai-subset' +import fs from 'fs/promises' +import path from 'path' +chai.use(chaiSubset) +import { getPgConfig } from '../src' + +const configFile = path.resolve(__dirname, '..', '.get-pg-configrc.json') +const pgpassfile = path.resolve(__dirname, '..', '.pgpass') + +describe(`getPgConfig`, function () { + beforeEach(async function () { + await fs.unlink(configFile).catch(() => {}) + await fs.unlink(pgpassfile).catch(() => {}) + }) + after(async function () { + await fs.unlink(configFile).catch(() => {}) + await fs.unlink(pgpassfile).catch(() => {}) + }) + it(`with separate fields`, async function () { + const fields = { + host: 'foo', + port: 5431, + user: 'us', + password: 'passss', + database: 'dbbb', + } + expect(await getPgConfig(fields)).to.containSubset(fields) + }) + it(`with connectionString`, async function () { + expect( + await getPgConfig({ + connectionString: 'postgres://user:pass@localhost:5431/db', + }) + ).to.containSubset({ + host: 'localhost', + port: 5431, + user: 'user', + password: 'pass', + database: 'db', + }) + }) + describe(`with env vars`, function () { + let envBefore = { ...process.env } + beforeEach(() => (envBefore = { ...process.env })) + afterEach(() => (process.env = envBefore)) + it(`works`, async function () { + process.env.PGHOST = 'hozt' + process.env.PGUSER = 'uzer' + process.env.PGPORT = '5438' + process.env.PGPASSWORD = 'pazzword' + process.env.PGDATABASE = 'dbz' + expect(await getPgConfig()).to.containSubset({ + host: 'hozt', + port: 5438, + user: 'uzer', + password: 'pazzword', + database: 'dbz', + }) + expect(await getPgConfig({ user: 'USER' })).to.containSubset({ + host: 'hozt', + port: 5438, + user: 'USER', + password: 'pazzword', + database: 'dbz', + }) + }) + it(`custom PGPASSFILE works`, async function () { + await fs.writeFile( + pgpassfile, + `localhost:*:*:postgres:pgpassword +localhost:*:*:foo:foopassword +remote:*:*:foo:remotepass + +`, + { encoding: 'utf8', mode: 0o600 } + ) + process.env.PGPASSFILE = pgpassfile + expect(await getPgConfig({ user: 'postgres' })).to.containSubset({ + host: 'localhost', + port: 5432, + user: 'postgres', + password: 'pgpassword', + database: 'postgres', + }) + expect(await getPgConfig({ user: 'foo' })).to.containSubset({ + host: 'localhost', + port: 5432, + user: 'foo', + password: 'foopassword', + database: 'foo', + }) + expect( + await getPgConfig({ host: 'remote', user: 'foo' }) + ).to.containSubset({ + host: 'remote', + port: 5432, + user: 'foo', + password: 'remotepass', + database: 'foo', + }) + }) + }) + it(`config works`, async function () { + await fs.writeFile( + configFile, + JSON.stringify({ + defaults: { + user: 'postgres', + }, + }), + { encoding: 'utf8', mode: 0o600 } + ) + expect(await getPgConfig()).to.containSubset({ + host: 'localhost', + port: 5432, + user: 'postgres', + database: 'postgres', + }) + expect(await getPgConfig({ database: 'foo' })).to.containSubset({ + host: 'localhost', + port: 5432, + user: 'postgres', + database: 'foo', + }) + expect(await getPgConfig({ user: 'foo' })).to.containSubset({ + host: 'localhost', + port: 5432, + user: 'foo', + database: 'foo', + }) + }) +}) diff --git a/toolchain.config.cjs b/toolchain.config.cjs index b01d6a4..5af1b04 100644 --- a/toolchain.config.cjs +++ b/toolchain.config.cjs @@ -1,8 +1,8 @@ /* eslint-env node, es2018 */ module.exports = { cjsBabelEnv: { forceAllTransforms: true }, - esmBabelEnv: { targets: { node: 16 } }, - // outputEsm: false, // disables ESM output (default: true) + // esmBabelEnv: { targets: { node: 16 } }, + outputEsm: false, // disables ESM output (default: true) // esWrapper: true, // outputs ES module wrappers for CJS modules (default: false) // scripts: { // pretest: 'docker compose up -d',