Skip to content

Commit 90febc6

Browse files
author
Toni Sharpe
committed
PR Comments
Resolves fastify#75
1 parent 3de300e commit 90febc6

File tree

5 files changed

+87
-169
lines changed

5 files changed

+87
-169
lines changed

add-handler.js

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module.exports = (existingHandler, newHandler) => {
2+
if (Array.isArray(existingHandler)) {
3+
return [
4+
...existingHandler,
5+
newHandler
6+
]
7+
} else if (typeof existingHandler === 'function') {
8+
return [existingHandler, newHandler]
9+
} else {
10+
return [newHandler]
11+
}
12+
}

index.js

+27-49
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
const defaultPg = require('pg')
44
const fp = require('fastify-plugin')
55

6+
const addHandler = require('./add-handler.js')
7+
8+
const transactionFailedSymbol = Symbol('transactionFailed')
9+
610
function transactionUtil (pool, fn, cb) {
711
pool.connect((err, client, done) => {
812
if (err) return cb(err)
@@ -52,19 +56,6 @@ function transact (fn, cb) {
5256
})
5357
}
5458

55-
// Re-usable code adds the handlers nicely
56-
const addHandler = (existingHandler, newHandler) => {
57-
if (Array.isArray(existingHandler)) {
58-
existingHandler.push(newHandler)
59-
} else if (typeof existingHandler === 'function') {
60-
existingHandler = [existingHandler, newHandler]
61-
} else {
62-
existingHandler = [newHandler]
63-
}
64-
65-
return existingHandler
66-
}
67-
6859
function fastifyPostgres (fastify, options, next) {
6960
let pg = defaultPg
7061

@@ -115,52 +106,39 @@ function fastifyPostgres (fastify, options, next) {
115106
}
116107
}
117108

109+
if (!fastify.hasRequestDecorator('pg')) {
110+
fastify.decorateRequest('pg', null)
111+
}
112+
118113
fastify.addHook('onRoute', routeOptions => {
119-
const useTransaction = routeOptions.useTransaction || (routeOptions.options && routeOptions.options.useTransaction)
114+
const useTransaction = routeOptions.pg && routeOptions.pg.transact
120115

121116
if (useTransaction) {
122-
// This will rollback the transaction if the handler fails at some point
123-
const onError = async (req, reply, error) => {
124-
req.transactionFailed = true
125-
126-
try {
127-
await req.pg.query('ROLLBACK')
128-
} catch (err) {
129-
await req.pg.query('ROLLBACK')
130-
}
117+
const preHandler = async (req, reply) => {
118+
const client = await pool.connect()
119+
req.pg = client
120+
req.pg.query('BEGIN')
131121
}
132122

133-
routeOptions.onError = addHandler(routeOptions.onError, onError)
134-
}
135-
136-
const preHandler = async (req, reply) => {
137-
const client = await pool.connect()
138-
req.pg = client
139-
140-
if (useTransaction) {
141-
await req.pg.query('BEGIN')
123+
const onError = (req, reply, error, done) => {
124+
req[transactionFailedSymbol] = true
125+
req.pg.query('ROLLBACK', done)
142126
}
143-
}
144127

145-
// This will commit the transaction (or rollback if that fails) and also always
146-
// release the client, regardless of error state or useTransaction value
147-
const onSend = async (req, reply, payload) => {
148-
try {
149-
if (!req.transactionFailed && useTransaction) {
150-
await req.pg.query('COMMIT')
151-
}
152-
} catch (err) {
153-
if (useTransaction) {
154-
await req.pg.query('ROLLBACK')
128+
const onSend = async (req) => {
129+
try {
130+
if (!req[transactionFailedSymbol]) {
131+
await req.pg.query('COMMIT')
132+
}
133+
} finally {
134+
req.pg.release()
155135
}
156-
} finally {
157-
req.pg.release()
158136
}
159-
}
160137

161-
// Add these handlers
162-
routeOptions.preHandler = addHandler(routeOptions.preHandler, preHandler)
163-
routeOptions.onSend = addHandler(routeOptions.onSend, onSend)
138+
routeOptions.preHandler = addHandler(routeOptions.preHandler, preHandler)
139+
routeOptions.onError = addHandler(routeOptions.onError, onError)
140+
routeOptions.onSend = addHandler(routeOptions.onSend, onSend)
141+
}
164142
})
165143

166144
next()

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"types": "index.d.ts",
77
"scripts": {
88
"testonly": "tap -J test/*.test.js && npm run test:typescript",
9-
"test": "standard --fix && tap -J test/*.test.js && npm run test:typescript",
9+
"test": "standard && tap -J test/*.test.js && npm run test:typescript",
1010
"test:typescript": "tsd",
1111
"test:report": "standard && tap -J --coverage-report=html test/*.test.js",
1212
"test:verbose": "standard && tap -J test/*.test.js -Rspec",

test/add-handler.test.js

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
'use strict'
2+
3+
const t = require('tap')
4+
const test = t.test
5+
const addHandler = require('../add-handler')
6+
7+
test('addHandler - ', t => {
8+
test('when existing handler is not defined', t => {
9+
t.plan(1)
10+
11+
const handlers = addHandler(
12+
undefined,
13+
'test'
14+
)
15+
16+
t.same(handlers, ['test'])
17+
})
18+
test('when existing handler is a array', t => {
19+
t.plan(1)
20+
21+
const handlers = addHandler(
22+
['test'],
23+
'again'
24+
)
25+
26+
t.same(handlers, ['test', 'again'])
27+
})
28+
test('when existing handler is a function', t => {
29+
t.plan(2)
30+
31+
const stub = () => 'test'
32+
33+
const handlers = addHandler(
34+
stub,
35+
'again'
36+
)
37+
38+
t.same(handlers[0](), 'test')
39+
t.same(handlers[1], 'again')
40+
})
41+
42+
t.end()
43+
})

test/req-initialization.test.js

+4-119
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,6 @@ const Fastify = require('fastify')
66
const fastifyPostgres = require('../index')
77
const { connectionString } = require('./helpers')
88

9-
// // A failed set of queries with transactions on, on test, NONE of these entries should be visible in the DB
10-
// fastify.get('/fail', { useTransaction: true }, async (req, reply) => {
11-
// console.log('in fail registration')
12-
13-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-in-q1'])
14-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-in-q2'])
15-
// await req.pg.query('INSERT INTO nope(username) VALUES($1) RETURNING id', ['fail-opt-in-q3'])
16-
17-
// reply.send('Fail example')
18-
// })
19-
20-
// // A passing set of queries with transactions on, on test, ALL of these entries should be visible in the DB
21-
// fastify.get('/pass', { useTransaction: true }, async (req, reply) => {
22-
// console.log('in pass registration')
23-
24-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in-q1'])
25-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in-q2'])
26-
27-
// reply.send('Pass example')
28-
// })
29-
30-
// // A failed set of queries with transactions off, on test, THE FIRST TWO of these entries should be visible in the DB
31-
// fastify.get('/fail-opt-out', { useTransaction: false }, async (req, reply) => {
32-
// console.log('in fail registration')
33-
34-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-out-q1'])
35-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-out-q2'])
36-
// await req.pg.query('INSERT INTO nope(username) VALUES($1) RETURNING id', ['fail-opt-out-q3'])
37-
38-
// reply.send('Fail example')
39-
// })
40-
41-
// // A passing set of queries with transactions off, on test, ALL of these entries should be visible in the DB
42-
// fastify.get('/pass-opt-out', { useTransaction: false }, async (req, reply) => {
43-
// console.log('in pass registration')
44-
45-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-out-q1'])
46-
// await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-out-q2'])
47-
48-
// reply.send('Pass example')
49-
// })
50-
519
const extractUserCount = response => parseInt(JSON.parse(response.payload).rows[0].userCount)
5210

5311
test('fastify postgress useTransaction route option - ', t => {
@@ -63,12 +21,12 @@ test('fastify postgress useTransaction route option - ', t => {
6321
await fastify.pg.query('TRUNCATE users')
6422

6523
await fastify.get('/count-users', async (req, reply) => {
66-
const result = await req.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'pass-opt-in\'')
24+
const result = await fastify.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'pass-opt-in\'')
6725

6826
reply.send(result)
6927
})
7028

71-
await fastify.get('/pass', { useTransaction: true }, async (req, reply) => {
29+
await fastify.get('/pass', { pg: { transact: true } }, async (req, reply) => {
7230
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in'])
7331
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-in'])
7432
reply.send('complete')
@@ -97,12 +55,12 @@ test('fastify postgress useTransaction route option - ', t => {
9755
await fastify.pg.query('TRUNCATE users')
9856

9957
await fastify.get('/count-users', async (req, reply) => {
100-
const result = await req.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'fail-opt-in\'')
58+
const result = await fastify.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'fail-opt-in\'')
10159

10260
reply.send(result)
10361
})
10462

105-
await fastify.get('/fail', { useTransaction: true }, async (req, reply) => {
63+
await fastify.get('/fail', { pg: { transact: true } }, async (req, reply) => {
10664
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-in'])
10765
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-in'])
10866
await req.pg.query('INSERT INTO nope(username) VALUES($1) RETURNING id', ['fail-opt-in'])
@@ -124,79 +82,6 @@ test('fastify postgress useTransaction route option - ', t => {
12482

12583
t.end()
12684
})
127-
test('set to false - ', t => {
128-
test('passing queries provided', async t => {
129-
const fastify = Fastify()
130-
t.teardown(() => fastify.close())
131-
132-
await fastify.register(fastifyPostgres, {
133-
connectionString
134-
})
135-
136-
await fastify.pg.query('TRUNCATE users')
137-
138-
await fastify.get('/count-users', async (req, reply) => {
139-
const result = await req.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'pass-opt-out\'')
140-
141-
reply.send(result)
142-
})
143-
144-
await fastify.get('/pass-opt-out', { useTransaction: false }, async (req, reply) => {
145-
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-out'])
146-
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['pass-opt-out'])
147-
reply.send('complete')
148-
})
149-
150-
await fastify.inject({
151-
method: 'GET',
152-
url: '/pass-opt-out'
153-
})
154-
155-
const response = await fastify.inject({
156-
method: 'GET',
157-
url: '/count-users'
158-
})
159-
160-
t.is(extractUserCount(response), 2)
161-
})
162-
test('failing queries provided', async t => {
163-
const fastify = Fastify()
164-
t.teardown(() => fastify.close())
165-
166-
await fastify.register(fastifyPostgres, {
167-
connectionString
168-
})
169-
170-
await fastify.pg.query('TRUNCATE users')
171-
172-
await fastify.get('/count-users', async (req, reply) => {
173-
const result = await req.pg.query('SELECT COUNT(*) AS "userCount" FROM users WHERE username=\'fail-opt-out\'')
174-
175-
reply.send(result)
176-
})
177-
178-
await fastify.get('/fail-opt-out', { useTransaction: false }, async (req, reply) => {
179-
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-out'])
180-
await req.pg.query('INSERT INTO users(username) VALUES($1) RETURNING id', ['fail-opt-out'])
181-
await req.pg.query('INSERT INTO nope(username) VALUES($1) RETURNING id', ['fail-opt-out'])
182-
reply.send('complete')
183-
})
184-
185-
await fastify.inject({
186-
method: 'GET',
187-
url: '/fail-opt-out'
188-
})
189-
190-
const response = await fastify.inject({
191-
method: 'GET',
192-
url: '/count-users'
193-
})
194-
195-
t.is(extractUserCount(response), 2)
196-
})
197-
198-
t.end()
199-
})
20085

20186
t.end()
20287
})

0 commit comments

Comments
 (0)