From ca2e25e18226550740137352ec8d2f4da5758f50 Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 9 Nov 2020 16:58:36 +0100 Subject: [PATCH 1/6] Types: Add "pg" property to FastifyInstance As recommended in the guide for creating TypeScript compatible Fastify plugins, properties that the Fastify instances are decorated with should also in the types get added to those instances: https://www.fastify.io/docs/latest/TypeScript/#creating-a-typescript-fastify-plugin This change follows up on #63 by adding that. --- index.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/index.d.ts b/index.d.ts index 174af26..eba0aad 100644 --- a/index.d.ts +++ b/index.d.ts @@ -37,5 +37,11 @@ type PostgresPluginOptions = { declare const fastifyPostgres: FastifyPluginCallback; +declare module 'fastify' { + interface FastifyInstance { + pg: PostgresDb + } +} + export { fastifyPostgres, PostgresDb, PostgresPluginOptions }; export default fastifyPostgres; From 9333cb0e807be33693fdcb62afb64e2b5ee1ce9b Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 9 Nov 2020 17:52:52 +0100 Subject: [PATCH 2/6] Document "name" option --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/README.md b/README.md index d95d644..d23027b 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,32 @@ fastify.listen(3000, err => { As you can see there is no need to close the client, since is done internally. Promises and async await are supported as well. +### Name option +If you need to have multiple databases set up, then you can name each one of them by passing `name: 'foo'`. It will then be accessible as `fastify.pg.foo` instead of `fastify.pg` + +```js +const fastify = require('fastify')() + +fastify.register(require('fastify-postgres'), { + connectionString: 'postgres://postgres@localhost/postgres', + name: 'foo' +}) + +fastify.get('/user/:id', (req, reply) => { + fastify.pg.foo.query( + 'SELECT id, username, hash, salt FROM users WHERE id=$1', [req.params.id], + function onResult (err, result) { + reply.send(err || result) + } + ) +}) + +fastify.listen(3000, err => { + if (err) throw err + console.log(`server listening on ${fastify.server.address().port}`) +}) +``` + ### Native option If you want to gain the maximum performances you can install [pg-native](https://github.com/brianc/node-pg-native), and pass `native: true` to the plugin options. *Note: it requires PostgreSQL client libraries & tools installed, see [instructions](https://github.com/brianc/node-pg-native#install).* From 22568980d6b664d8aef670bb5c8d814993be33c6 Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 9 Nov 2020 18:41:46 +0100 Subject: [PATCH 3/6] Enable use of non-docker postgres db in tests --- README.md | 17 ++++++++++++++++- test/helpers.js | 11 +++++++++++ test/initialization.test.js | 23 ++++++++++++----------- test/query.test.js | 37 ++++++++++++++++++------------------- test/transaction.test.js | 31 +++++++++++++++++-------------- 5 files changed, 74 insertions(+), 45 deletions(-) create mode 100644 test/helpers.js diff --git a/README.md b/README.md index d23027b..fe3315e 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,8 @@ fastify.listen(3000, err => { As you can see there is no need to close the client, since is done internally. Promises and async await are supported as well. ### Name option -If you need to have multiple databases set up, then you can name each one of them by passing `name: 'foo'`. It will then be accessible as `fastify.pg.foo` instead of `fastify.pg` +If you need to have multiple databases set up, then you can name each one of them by passing `name: 'foo'`. It will then be accessible as `fastify.pg.foo` instead of `fastify.pg`. +You can't use both named and an unnamed postgres conenction at once. ```js const fastify = require('fastify')() @@ -241,6 +242,8 @@ You can find examples in the [examples/typescript](./examples/typescript) direct ## Development and Testing +### Docker approach + First, start postgres with: ``` @@ -260,6 +263,18 @@ CREATE TABLE $ npm test ``` +### Custom Postgres approach + +1. Set up a database of your choice oin a postgres server of your choice +2. Create the required table using + ```sql + CREATE TABLE users(id serial PRIMARY KEY, username VARCHAR (50) NOT NULL); + ``` +3. Specify a connection string to it in a `DATABASE_TEST_URL` environment variable when you run the tests + ```bash + DATABASE_TEST_URL="postgres://username:password@localhost/something_thats_a_test_database" npm test + ``` + ## Acknowledgements This project is kindly sponsored by: diff --git a/test/helpers.js b/test/helpers.js new file mode 100644 index 0000000..c068533 --- /dev/null +++ b/test/helpers.js @@ -0,0 +1,11 @@ +'use strict' + +const BAD_DB_NAME = 'db_that_does_not_exist' +const connectionString = process.env.DATABASE_TEST_URL || 'postgres://postgres:postgres@localhost/postgres' +const connectionStringBadDbName = connectionString.replace(/\/[^/]+$/, '/' + BAD_DB_NAME) + +module.exports = Object.freeze({ + BAD_DB_NAME, + connectionString, + connectionStringBadDbName +}) diff --git a/test/initialization.test.js b/test/initialization.test.js index 083ed9d..7558d03 100644 --- a/test/initialization.test.js +++ b/test/initialization.test.js @@ -4,6 +4,7 @@ const t = require('tap') const test = t.test const Fastify = require('fastify') const fastifyPostgres = require('../index') +const { connectionString } = require('./helpers') test('Should be able to use native module', (t) => { t.plan(2) @@ -12,7 +13,7 @@ test('Should be able to use native module', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, native: true }) @@ -38,7 +39,7 @@ test('Should be able to use an alternative pg module', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, pg: altPg }) @@ -64,7 +65,7 @@ test('Should not throw if registered within different scopes (with and without n fastify.register(function scopeOne (instance, opts, next) { instance.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) next() @@ -72,12 +73,12 @@ test('Should not throw if registered within different scopes (with and without n fastify.register(function scopeTwo (instance, opts, next) { instance.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'one' }) instance.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'two' }) @@ -96,11 +97,11 @@ test('Should throw when trying to register multiple instances without giving a n t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) fastify.ready((err) => { @@ -118,11 +119,11 @@ test('Should throw when trying to register duplicate connection names', (t) => { fastify .register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name }) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name }) @@ -139,7 +140,7 @@ test('fastify.pg namespace should exist', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) fastify.ready((err) => { @@ -159,7 +160,7 @@ test('fastify.pg.test namespace should exist', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) diff --git a/test/query.test.js b/test/query.test.js index 2209cdb..46c5046 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4,6 +4,11 @@ const t = require('tap') const test = t.test const Fastify = require('fastify') const fastifyPostgres = require('../index') +const { + BAD_DB_NAME, + connectionString, + connectionStringBadDbName +} = require('./helpers') test('When fastify.pg root namespace is used:', (t) => { t.test('Should be able to connect and perform a query with a callback', (t) => { @@ -13,7 +18,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) fastify.ready((err) => { @@ -40,7 +45,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) fastify.ready((err) => { @@ -60,7 +65,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString }) fastify.ready((err) => { @@ -85,10 +90,8 @@ test('When fastify.pg root namespace is used:', (t) => { const fastify = Fastify() t.teardown(() => fastify.close()) - const DB_NAME = 'database_that_do_not_exist' - fastify.register(fastifyPostgres, { - connectionString: `postgres://postgres:postgres@localhost/${DB_NAME}` + connectionString: connectionStringBadDbName }) fastify.ready((err) => { @@ -97,7 +100,7 @@ test('When fastify.pg root namespace is used:', (t) => { fastify.pg.query('SELECT NOW()', (err, result) => { t.is(result, undefined) t.ok(err) - t.is(err.message, `database "${DB_NAME}" does not exist`) + t.is(err.message, `database "${BAD_DB_NAME}" does not exist`) }) }) } @@ -109,10 +112,8 @@ test('When fastify.pg root namespace is used:', (t) => { const fastify = Fastify() t.teardown(() => fastify.close()) - const DB_NAME = 'database_that_do_not_exist' - fastify.register(fastifyPostgres, { - connectionString: `postgres://postgres:postgres@localhost/${DB_NAME}` + connectionString: connectionStringBadDbName }) fastify.ready((err) => { @@ -125,7 +126,7 @@ test('When fastify.pg root namespace is used:', (t) => { }) .catch((err) => { t.ok(err) - t.is(err.message, `database "${DB_NAME}" does not exist`) + t.is(err.message, `database "${BAD_DB_NAME}" does not exist`) }) }) }) @@ -141,7 +142,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -167,7 +168,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -187,7 +188,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -212,7 +213,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test', native: true }) @@ -237,10 +238,8 @@ test('When fastify.pg.test namespace is used:', (t) => { const fastify = Fastify() t.teardown(() => fastify.close()) - const DB_NAME = 'database_that_do_not_exist' - fastify.register(fastifyPostgres, { - connectionString: `postgres://postgres:postgres@localhost/${DB_NAME}`, + connectionString: connectionStringBadDbName, name: 'test' }) @@ -254,7 +253,7 @@ test('When fastify.pg.test namespace is used:', (t) => { }) .catch((err) => { t.ok(err) - t.is(err.message, `database "${DB_NAME}" does not exist`) + t.is(err.message, `database "${BAD_DB_NAME}" does not exist`) }) }) }) diff --git a/test/transaction.test.js b/test/transaction.test.js index b136074..3fdcf9e 100644 --- a/test/transaction.test.js +++ b/test/transaction.test.js @@ -4,6 +4,11 @@ const t = require('tap') const test = t.test const Fastify = require('fastify') const fastifyPostgres = require('../index') +const { + BAD_DB_NAME, + connectionString, + connectionStringBadDbName +} = require('./helpers') test('When fastify.pg root namespace is used:', (t) => { t.test('Should be able to use transact util with a callback', (t) => { @@ -13,7 +18,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString: process.env.DATABASE_TEST_URL || 'postgres://postgres:postgres@localhost/postgres' }) fastify.ready((err) => { @@ -50,7 +55,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString: process.env.DATABASE_TEST_URL || 'postgres://postgres:postgres@localhost/postgres' }) fastify.ready((err) => { @@ -87,7 +92,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString: process.env.DATABASE_TEST_URL || 'postgres://postgres:postgres@localhost/postgres' }) fastify.ready((err) => { @@ -128,7 +133,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString: process.env.DATABASE_TEST_URL || 'postgres://postgres:postgres@localhost/postgres' }) fastify.ready((err) => { @@ -182,7 +187,7 @@ test('When fastify.pg root namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres' + connectionString: process.env.DATABASE_TEST_URL || 'postgres://postgres:postgres@localhost/postgres' }) fastify.ready((err) => { @@ -231,10 +236,9 @@ test('When fastify.pg root namespace is used:', (t) => { t.plan(3) const fastify = Fastify() - const BAD_DB_NAME = 'db_that_does_not_exist' fastify.register(fastifyPostgres, { - connectionString: `postgres://postgres:postgres@localhost/${BAD_DB_NAME}` + connectionString: connectionStringBadDbName }) fastify.ready((err) => { @@ -259,7 +263,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -297,7 +301,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -337,7 +341,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -380,7 +384,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -435,7 +439,7 @@ test('When fastify.pg.test namespace is used:', (t) => { t.teardown(() => fastify.close()) fastify.register(fastifyPostgres, { - connectionString: 'postgres://postgres:postgres@localhost/postgres', + connectionString, name: 'test' }) @@ -485,10 +489,9 @@ test('When fastify.pg.test namespace is used:', (t) => { t.plan(3) const fastify = Fastify() - const BAD_DB_NAME = 'db_that_does_not_exist' fastify.register(fastifyPostgres, { - connectionString: `postgres://postgres:postgres@localhost/${BAD_DB_NAME}`, + connectionString: connectionStringBadDbName, name: 'test' }) From 73b05fd26b00cd6d2219f65adecef96854efed2e Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 9 Nov 2020 18:42:35 +0100 Subject: [PATCH 4/6] Fix tests when no error is thrown --- test/initialization.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/initialization.test.js b/test/initialization.test.js index 7558d03..f75e504 100644 --- a/test/initialization.test.js +++ b/test/initialization.test.js @@ -106,7 +106,7 @@ test('Should throw when trying to register multiple instances without giving a n fastify.ready((err) => { t.ok(err) - t.is(err.message, 'fastify-postgres has already been registered') + t.is((err || {}).message, 'fastify-postgres has already been registered') }) }) @@ -129,7 +129,7 @@ test('Should throw when trying to register duplicate connection names', (t) => { fastify.ready((err) => { t.ok(err) - t.is(err.message, `fastify-postgres '${name}' instance name has already been registered`) + t.is((err || {}).message, `fastify-postgres '${name}' instance name has already been registered`) }) }) From 3c3235c865eda2598e2987f1b7f81a2e98788b7b Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 9 Nov 2020 18:43:10 +0100 Subject: [PATCH 5/6] Throw if named and unnamed are combined --- index.js | 6 +++--- test/initialization.test.js | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index a6dda6e..731b444 100644 --- a/index.js +++ b/index.js @@ -85,9 +85,9 @@ function fastifyPostgres (fastify, options, next) { if (name) { if (!fastify.pg) { fastify.decorate('pg', {}) - } - - if (fastify.pg[name]) { + } else if (fastify.pg.pool instanceof pg.Pool) { + return next(new Error('fastify-postgres already has an unnamed instance registered')) + } else if (fastify.pg[name]) { return next(new Error(`fastify-postgres '${name}' instance name has already been registered`)) } diff --git a/test/initialization.test.js b/test/initialization.test.js index f75e504..a7d6546 100644 --- a/test/initialization.test.js +++ b/test/initialization.test.js @@ -110,6 +110,27 @@ test('Should throw when trying to register multiple instances without giving a n }) }) +test('Should throw when trying to register a named instance after an unnamed', (t) => { + t.plan(2) + + const fastify = Fastify() + t.teardown(() => fastify.close()) + + fastify.register(fastifyPostgres, { + connectionString + }) + + fastify.register(fastifyPostgres, { + connectionString, + name: 'two' + }) + + fastify.ready((err) => { + t.ok(err) + t.is((err || {}).message, 'fastify-postgres already has an unnamed instance registered') + }) +}) + test('Should throw when trying to register duplicate connection names', (t) => { t.plan(2) From 7d40153567c9a4997521aa0275faec293be67b0a Mon Sep 17 00:00:00 2001 From: Pelle Wessman Date: Mon, 9 Nov 2020 18:46:15 +0100 Subject: [PATCH 6/6] Clarify that intention is to manually add type --- README.md | 14 +++++++++++++- index.d.ts | 6 ------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fe3315e..6122698 100644 --- a/README.md +++ b/README.md @@ -238,7 +238,19 @@ Install the compiler and typings for pg module: npm install --save-dev typescript @types/pg ``` -You can find examples in the [examples/typescript](./examples/typescript) directory. +Add the `pg` property to `FastifyInstance`. Like this if you use an unnamed instance: + +```typescript +import type { PostgresDb } from 'fastify-postgres'; + +declare module 'fastify' { + export interface FastifyInstance { + pg: PostgresDb; + } +} +``` + +More examples in the [examples/typescript](./examples/typescript) directory. ## Development and Testing diff --git a/index.d.ts b/index.d.ts index eba0aad..174af26 100644 --- a/index.d.ts +++ b/index.d.ts @@ -37,11 +37,5 @@ type PostgresPluginOptions = { declare const fastifyPostgres: FastifyPluginCallback; -declare module 'fastify' { - interface FastifyInstance { - pg: PostgresDb - } -} - export { fastifyPostgres, PostgresDb, PostgresPluginOptions }; export default fastifyPostgres;