diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9fc1fa2..d7038c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,10 +14,9 @@ jobs: strategy: matrix: node-version: - - 10 - - 12 - 14 - 16 + - 18 services: postgres: image: postgres:11-alpine diff --git a/README.md b/README.md index 8b10602..39ed5cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# fastify-postgres +# @fastify/postgres ![CI](https://github.com/fastify/fastify-postgres/workflows/CI/badge.svg) -[![NPM version](https://img.shields.io/npm/v/fastify-postgres.svg?style=flat)](https://www.npmjs.com/package/fastify-postgres) +[![NPM version](https://img.shields.io/npm/v/@fastify/postgres.svg?style=flat)](https://www.npmjs.com/package/@fastify/postgres) [![Known Vulnerabilities](https://snyk.io/test/github/fastify/fastify-postgres/badge.svg)](https://snyk.io/test/github/fastify/fastify-postgres) [![Coverage Status](https://coveralls.io/repos/github/fastify/fastify-postgres/badge.svg?branch=master)](https://coveralls.io/github/fastify/fastify-postgres?branch=master) [![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://standardjs.com/) @@ -11,7 +11,7 @@ Under the hood [node-postgres](https://github.com/brianc/node-postgres) is used, ## Install ``` -npm i pg fastify-postgres --save +npm i pg @fastify/postgres --save ``` ## Usage Add it to your project with `register` and you are done! @@ -28,7 +28,7 @@ Example: ```js const fastify = require('fastify')() -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres' }) @@ -58,17 +58,22 @@ Async await is supported as well! ```js const fastify = require('fastify')() -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres' }) fastify.get('/user/:id', async (req, reply) => { const client = await fastify.pg.connect() - const { rows } = await client.query( - 'SELECT id, username, hash, salt FROM users WHERE id=$1', [req.params.id], - ) - client.release() - return rows + try { + const { rows } = await client.query( + 'SELECT id, username, hash, salt FROM users WHERE id=$1', [req.params.id], + ) + // Note: avoid doing expensive computation here, this will block releasing the client + return rows + } finally { + // Release the client immediately after query resolves, or upon error + client.release() + } }) fastify.listen(3000, err => { @@ -80,7 +85,7 @@ Use of `pg.query` ```js const fastify = require('fastify')() -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres' }) @@ -103,7 +108,7 @@ Use of `pg.transact` ```js const fastify = require('fastify')() -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres' }) @@ -156,7 +161,7 @@ You can use both unnamed and named postgres connections at once. There can be on ```js const fastify = require('fastify')() -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres', name: 'foo' }) @@ -184,7 +189,7 @@ Note: trying to use native options without successfully installation of `pg-nati ```js const fastify = require('fastify')() -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres', native: true }) @@ -212,7 +217,7 @@ const fastify = require('fastify')() const pg = require("pg"); require("pg-range").install(pg) -fastify.register(require('fastify-postgres'), { +fastify.register(require('@fastify/postgres'), { connectionString: 'postgres://postgres@localhost/postgres', pg: pg }) @@ -233,7 +238,7 @@ fastify.listen(3000, err => { ``` ### Transact route option -It is possible to automatically wrap a route handler in a transaction by using the `transact` option when registering a route with Fastify. Note that the option must be scoped within a `pg` options object to take effect. +It is possible to automatically wrap a route handler in a transaction by using the `transact` option when registering a route with Fastify. Note that the option must be scoped within a `pg` options object to take effect. `query` commands can then be accessed at `request.pg` or `request.pg[name]` and `transact` can be set for either the root pg client with value `true` or for a pg client at a particular namespace with value `name`. Note that the namespace needs to be set when registering the plugin in order to be available on the request object. diff --git a/index.js b/index.js index d5cab2b..638a20a 100644 --- a/index.js +++ b/index.js @@ -90,7 +90,7 @@ function fastifyPostgres (fastify, options, next) { const pool = new pg.Pool(options) const db = { connect: pool.connect.bind(pool), - pool: pool, + pool, Client: pg.Client, query: pool.query.bind(pool), transact: transact.bind(pool) @@ -189,6 +189,6 @@ function fastifyPostgres (fastify, options, next) { } module.exports = fp(fastifyPostgres, { - fastify: '>=1.1.0', - name: 'fastify-postgres' + fastify: '4.x', + name: '@fastify/postgres' }) diff --git a/package.json b/package.json index 58d2760..6ee88f7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fastify/postgres", - "version": "4.0.0", + "version": "5.0.0", "description": "Fastify PostgreSQL connection plugin", "main": "index.js", "types": "index.d.ts", @@ -39,7 +39,7 @@ "devDependencies": { "@tsconfig/node10": "^1.0.8", "@types/pg": "^8.6.1", - "fastify": "^3.21.5", + "fastify": "^4.0.0-rc.2", "pg": "^8.7.1", "pg-native": "^3.0.0", "standard": "^17.0.0", diff --git a/test/req-initialization.test.js b/test/req-initialization.test.js index 08a2203..5bf23e2 100644 --- a/test/req-initialization.test.js +++ b/test/req-initialization.test.js @@ -21,13 +21,13 @@ test('When we use the fastify-postgres transaction route option', t => { fastify.get('/count-users', async (req, reply) => { const result = await fastify.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'pass-opt-in\'') - reply.send(result) + return result }) fastify.get('/pass', { pg: { transact: true } }, async (req, reply) => { await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in']) await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in']) - reply.send('complete') + return 'complete' }) await fastify.inject({ url: '/pass' }) @@ -54,14 +54,14 @@ test('When we use the fastify-postgres transaction route option', t => { fastify.get('/count-users', async (req, reply) => { const result = await fastify.pg.test.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'pass-opt-in\'') - reply.send(result) + return result }) fastify.get('/pass', { pg: { transact: 'test' } }, async (req, reply) => { await req.pg.test.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in']) await req.pg.test.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in']) - reply.send('complete') + return 'complete' }) await fastify.inject({ url: '/pass' }) @@ -155,12 +155,11 @@ test('Should not add hooks with combinations of registration `options.name` and fastify.register(fastifyPostgres, { connectionString + }).after(() => { + fastify.get('/', (req, reply) => { + t.equal(req.pg, null) + }) }) - - fastify.get('/', (req, reply) => { - t.equal(req.pg, null) - }) - fastify.inject({ url: '/' }) }) @@ -173,10 +172,10 @@ test('Should not add hooks with combinations of registration `options.name` and fastify.register(fastifyPostgres, { connectionString, name: 'test' - }) - - fastify.get('/', (req, reply) => { - t.equal(req.pg, null) + }).after(() => { + fastify.get('/', (req, reply) => { + t.equal(req.pg, null) + }) }) fastify.inject({ url: '/' }) @@ -191,10 +190,10 @@ test('Should not add hooks with combinations of registration `options.name` and fastify.register(fastifyPostgres, { connectionString, name: 'test' - }) - - fastify.get('/', { pg: { transact: true } }, (req, reply) => { - t.equal(req.pg, null) + }).after(() => { + fastify.get('/', { pg: { transact: true } }, (req, reply) => { + t.equal(req.pg, null) + }) }) fastify.inject({ url: '/' }) @@ -208,10 +207,10 @@ test('Should not add hooks with combinations of registration `options.name` and fastify.register(fastifyPostgres, { connectionString - }) - - fastify.get('/', { pg: { transact: 'test' } }, (req, reply) => { - t.equal(req.pg, null) + }).after(() => { + fastify.get('/', { pg: { transact: 'test' } }, (req, reply) => { + t.equal(req.pg, null) + }) }) fastify.inject({ url: '/' }) @@ -226,10 +225,10 @@ test('Should not add hooks with combinations of registration `options.name` and fastify.register(fastifyPostgres, { connectionString, name: 'test' - }) - - fastify.get('/', { pg: { transact: 'different' } }, (req, reply) => { - t.equal(req.pg, null) + }).after(() => { + fastify.get('/', { pg: { transact: 'different' } }, (req, reply) => { + t.equal(req.pg, null) + }) }) fastify.inject({ url: '/' }) @@ -239,40 +238,34 @@ test('Should not add hooks with combinations of registration `options.name` and }) test('Should throw errors with incorrect combinations of registration `options.name` and route options `pg.transact`', t => { - t.test('Should throw an error when `name` is set as reserved keyword', t => { - t.plan(2) - + t.test('Should throw an error when `name` is set as reserved keyword', async t => { const fastify = Fastify() t.teardown(() => fastify.close()) const name = 'user' - fastify.register(fastifyPostgres, { + await fastify.register(fastifyPostgres, { connectionString, name }) fastify.get('/', { pg: { transact: name } }, (req, reply) => {}) - fastify.inject({ url: '/' }, (err, response) => { - t.error(err) - t.same(response.json(), { - statusCode: 500, - error: 'Internal Server Error', - message: `request client '${name}' does not exist` - }) + const response = await fastify.inject({ url: '/' }) + t.same(response.json(), { + statusCode: 500, + error: 'Internal Server Error', + message: `request client '${name}' does not exist` }) }) - t.test('Should throw an error when pg client has already been registered with the same name', t => { - t.plan(2) - + t.test('Should throw an error when pg client has already been registered with the same name', async t => { const fastify = Fastify() t.teardown(() => fastify.close()) const name = 'test' - fastify.register(fastifyPostgres, { + await fastify.register(fastifyPostgres, { connectionString, name }) @@ -281,23 +274,19 @@ test('Should throw errors with incorrect combinations of registration `options.n }) fastify.get('/', { pg: { transact: name } }, (req, reply) => {}) - fastify.inject({ url: '/' }, (err, response) => { - t.error(err) - t.same(response.json(), { - statusCode: 500, - error: 'Internal Server Error', - message: `request client '${name}' has already been registered` - }) + const response = await fastify.inject({ url: '/' }) + t.same(response.json(), { + statusCode: 500, + error: 'Internal Server Error', + message: `request client '${name}' has already been registered` }) }) - t.test('Should throw an error when pg client has already been registered', t => { - t.plan(2) - + t.test('Should throw an error when pg client has already been registered', async t => { const fastify = Fastify() t.teardown(() => fastify.close()) - fastify.register(fastifyPostgres, { + await fastify.register(fastifyPostgres, { connectionString }) fastify.addHook('onRequest', async (req, reply) => { @@ -305,13 +294,11 @@ test('Should throw errors with incorrect combinations of registration `options.n }) fastify.get('/', { pg: { transact: true } }, (req, reply) => {}) - fastify.inject({ url: '/' }, (err, response) => { - t.error(err) - t.same(response.json(), { - statusCode: 500, - error: 'Internal Server Error', - message: 'request client has already been registered' - }) + const response = await fastify.inject({ url: '/' }) + t.same(response.json(), { + statusCode: 500, + error: 'Internal Server Error', + message: 'request client has already been registered' }) }) diff --git a/test/transaction.test.js b/test/transaction.test.js index f9a013b..3f9d4cb 100644 --- a/test/transaction.test.js +++ b/test/transaction.test.js @@ -418,49 +418,6 @@ test('When fastify.pg.test namespace is used:', (t) => { }) }) - t.test('Should be able to use transact util with a commit callback', (t) => { - t.plan(4) - - const fastify = Fastify() - t.teardown(() => fastify.close()) - - fastify.register(fastifyPostgres, { - connectionString, - name: 'test' - }) - - fastify.ready((err) => { - t.error(err) - - fastify.pg.test.transact( - (client, commit) => { - client.query( - 'INSERT INTO users(username) VALUES($1) RETURNING id', - ['namespace-commit-callback'], - (err, id) => { - commit(err, id) - } - ) - }, - function (err, result) { - t.error(err) - t.equal(result.rows.length, 1) - - const userId = result.rows[0].id - - fastify.pg.test - .query('SELECT * FROM users WHERE id = $1', [userId]) - .then((result) => { - t.equal(result.rows[0].username, 'namespace-commit-callback') - }) - .catch((err) => { - t.fail(err) - }) - } - ) - }) - }) - t.test('Should trigger a rollback when something goes wrong (with callback)', (t) => { t.plan(9)