diff --git a/README.md b/README.md index d95d644..6122698 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,33 @@ 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`. +You can't use both named and an unnamed postgres conenction at once. + +```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).* @@ -211,10 +238,24 @@ 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 +### Docker approach + First, start postgres with: ``` @@ -234,6 +275,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/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/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..a7d6546 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,16 +97,37 @@ 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) => { t.ok(err) - t.is(err.message, 'fastify-postgres has already been registered') + t.is((err || {}).message, 'fastify-postgres has already been registered') + }) +}) + +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') }) }) @@ -118,17 +140,17 @@ 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 }) 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`) }) }) @@ -139,7 +161,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 +181,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' })