pg-lazy
v3.0.2
Published
Helpers for node-postgres for Lazy devs
Maintainers
Readme
pg-Lazy
Simple functional helpers for node-postgres.
Requires Node >= ^10.0.0 and node-postgres ^8.0.0
Breaking Changes from v2.x.x to v3.x.x
PoolandClientare no longer an instance ofpg._Poolandpg._Clientrespectively.isConnectedis renamed withcanConnect- Now user proper ES6 class extends.
Breaking Changes from v1.x.x to v2.x.x
- Due to new es6 codes, this module now requires Node v8.1.4 and above.
- This module no longer mutates pg.Pool and pg.Client, it instead
extendsthem and store them aspg._Poolandpg._Client - It no longer automatically initialize the
Poolunless a third Object argument is passed{singleton:true} pg-Lazynow returns a default Object{ pg, Pool, Client, sql, _raw }in whichPoolis an instance ofpg._Pooland Client is an instance ofpg._Client. To get the originalpg.Poolandpg.Clientinstances, you can usepgto access them.- If
{singleton:true}is passed as a third argument, it then addspoolfrom the returned Object. Thispoolis an already-initializedpg._Pool - Read more changes here ChangeLog
Installation
npm install pg-lazy pg --save or yarn add pg-lazy pg
Usage
Manual Pool initialization:
const pgLazy = require('pg-lazy');
// create your configuration
const connectionString = 'postgres://localhost:5432/pg_test';
// pool instance is no longer initiated, you must initialize it using pg.Pool.
const { Pool, sql, _raw, pg } = pgLazy(require('pg'), { connectionString });
const pool = new Pool()
async function getUser(name,id){
// regular query
return pool.query(sql`SELECT * FROM TABLE WHERE name = ${name}`);
// many for more than 1 result
return pool.many(sql`SELECT * FROM TABLE WHERE id > ${id}`);
// one for single result
return pool.one(sql`SELECT * FROM TABLE WHERE id = ${id}`);
// none for no result
return pool.many(sql`SELECT * FROM TABLE WHERE id < 0`);
}
async function(){
const username = await getUser('john',5)
}Automatic Pool initialization:
const pgLazy = require('pg-lazy');
// create your configuration
const connectionString = 'postgres://localhost:5432/pg_test';
// pool instance is automatically initialized when passing {singleton:true}
const { pool, sql, _raw, pg } = pgLazy(require('pg'), { connectionString }, {singleton:true});
async function getUser(name,id){
// regular query
return pool.query(sql`SELECT * FROM TABLE WHERE name = ${name}`);
// many for more than 1 result
return pool.many(sql`SELECT * FROM TABLE WHERE id > ${id}`);
// one for single result
return pool.one(sql`SELECT * FROM TABLE WHERE id = ${id}`);
// none for no result
return pool.many(sql`SELECT * FROM TABLE WHERE id < 0`);
}
async function(){
const username = await getUser('john',5)
}Helpers
pg.Pool with prototype methods
query,many,one,none,withTransaction,canConnect.pg.Client with prototype methods
query,many,one,none,canConnect.Extends both with
.prepared(name).{query,many,one}()All methods returns a Promise
Automatically defaults to Environment variables for DB config, that means you can also set your DB config via
process.envConfigures the client parser to parse postgres ints and numerics into javascript numbers (else
SELECT 1::int8would return a string "1").Accepts String, Objects and connectionString for configuration,
Exposes
sqland_rawtemplate literal helpers for writing queries.const uname = 'nisha42' const key = 'uname' const direction = 'desc' await pool.one(sql` SELECT * FROM users WHERE lower(uname) = lower(${uname}) `.append(_raw`ORDER BY ${key} ${direction}`))All query methods fail if the query you pass in is not built with the
sqlor_rawtag. This avoids the issue of accidentally introducing sql injection with template literals. If you want normal template literal behavior (dumb interpolation), you must tag it with_raw.
Example
const pgLazy = require('pg-lazy');
const url = 'postgres://user:pass@localhost:5432/my-db'
const { pool, sql, _raw, pg } = pgLazy(require('pg'), { connectionString:url },{ singleton:true });
exports.findUserByUname = async function (uname) {
return pool.one(sql`
SELECT *
FROM users
WHERE lower(uname) = lower(${uname})
`)
}
exports.listUsersInCities = async function (cities, direction = 'DESC') {
return pool.many(sql`
SELECT *
FROM users
WHERE city = ANY (${cities})
`.append(_raw`ORDER BY uname ${direction}`))
}
exports.transferBalance = async function (from, to, amount) {
return pool.withTransaction(async (client) => {
await client.query(sql`
UPDATE accounts SET amount = amount - ${amount} WHERE id = ${from}
`)
await client.query(sql`
UPDATE accounts SET amount = amount + ${amount} WHERE id = ${to}
`)
})
}Check more examples on the Test folder
Query template tags
pg-extra forces you to tag template strings with sql or _raw.
You usually use sql.
sql is a simple helper that translates this:
sql`
SELECT *
FROM users
WHERE lower(uname) = lower(${'nisha42'})
AND faveFood = ANY (${['kibble', 'tuna']})
`into the sql bindings object that node-postgres expects:
{
text: `
SELECT *
FROM users
WHERE lower(uname) = lower($1)
AND faveFood = ANY ($2)
`,
values: ['nisha42', ['kibble', 'tuna']]
}_raw is how you opt-in to regular string interpolation, made ugly
so that it stands out.
Use .append() to chain on to the query. The argument to .append()
must also be tagged with sql or _raw.
sql`${'foo'} ${'bar'}`.append(_raw`${'baz'}`) // '$1 $2 baz'
_raw`${'foo'} ${'bar'}`.append(sql`${'baz'}`) // 'foo bar $1'Test
Setup local postgres database with seeded rows that the tests expect:
- psql -c 'create user lazy_test_user with password '"'lazy_test_pw'"';' -U postgres
- psql -c 'create database lazy_test owner lazy_test_user;' -U postgres
- psql -d lazy_test -c 'create table bars (n int not null);' -U lazy_test_user
- psql -d lazy_test -c 'insert into bars (n) values (1), (2), (3);' -U lazy_test_user
Then run the tests:
`yarn test` or `npm test`Changelog
Shouts
- Heavily inspired by pg-extra.
