Postgres
Postgres.js - The Fastest full featured PostgreSQL client for Node.js, Deno, Bun and CloudFlare
Install / Use
/learn @porsager/PostgresREADME
- 🚀 Fastest full-featured node & deno client
- 🏷 ES6 Tagged Template Strings at the core
- 🏄♀️ Simple surface API
- 🖊️ Dynamic query support
- 💬 Chat and help on Gitter
- 🐦 Follow on Twitter
Getting started
<br> <img height="220" width="458" alt="Good UX with Postgres.js" src="https://raw.githubusercontent.com/porsager/postgres/master/demo.gif"> <br>Installation
$ npm install postgres
Usage
Create your sql database instance
// db.js
import postgres from 'postgres'
const sql = postgres({ /* options */ }) // will use psql environment variables
export default sql
Simply import for use elsewhere
// users.js
import sql from './db.js'
async function getUsersOver(age) {
const users = await sql`
select
name,
age
from users
where age > ${ age }
`
// users = Result [{ name: "Walter", age: 80 }, { name: 'Murray', age: 68 }, ...]
return users
}
async function insertUser({ name, age }) {
const users = await sql`
insert into users
(name, age)
values
(${ name }, ${ age })
returning name, age
`
// users = Result [{ name: "Murray", age: 68 }]
return users
}
ESM dynamic imports
The library can be used with ESM dynamic imports as well as shown here.
const { default: postgres } = await import('postgres')
Table of Contents
- Connection
- Queries
- Building queries
- Advanced query methods
- Transactions
- Data Transformation
- Listen & notify
- Realtime subscribe
- Numbers, bigint, numeric
- Result Array
- Connection details
- Custom Types
- Teardown / Cleanup
- Error handling
- TypeScript support
- Reserving connections
- Changelog
Connection
postgres([url], [options])
You can use either a postgres:// url connection string or the options to define your database connection properties. Options in the object will override any present in the url. Options will fall back to the same environment variables as psql.
const sql = postgres('postgres://username:password@host:port/database', {
host : '', // Postgres ip address[s] or domain name[s]
port : 5432, // Postgres server port[s]
database : '', // Name of database to connect to
username : '', // Username of database user
password : '', // Password of database user
...and more
})
More options can be found in the Connection details section.
Queries
await sql`...` -> Result[]
Postgres.js utilizes Tagged template functions to process query parameters before interpolation. Using tagged template literals benefits developers by:
- Enforcing safe query generation
- Giving the
sql``function powerful utility and query building features.
Any generic value will be serialized according to an inferred type, and replaced by a PostgreSQL protocol placeholder $1, $2, .... The parameters are then sent separately to the database which handles escaping & casting.
All queries will return a Result array, with objects mapping column names to each row.
const xs = await sql`
insert into users (
name, age
) values (
'Murray', 68
)
returning *
`
// xs = [{ user_id: 1, name: 'Murray', age: 68 }]
Please note that queries are first executed when
awaited– or instantly by using.execute().
Query parameters
Parameters are automatically extracted and handled by the database so that SQL injection isn't possible. No special handling is necessary, simply use tagged template literals as usual.
const name = 'Mur'
, age = 60
const users = await sql`
select
name,
age
from users
where
name like ${ name + '%' }
and age > ${ age }
`
// users = [{ name: 'Murray', age: 68 }]
Be careful with quotation marks here. Because Postgres infers column types, you do not need to wrap your interpolated parameters in quotes like
'${name}'. This will cause an error because the tagged template replaces${name}with$1in the query string, leaving Postgres to do the interpolation. If you wrap that in a string, Postgres will see'$1'and interpret it as a string as opposed to a parameter.
Dynamic column selection
const columns = ['name', 'age']
await sql`
select
${ sql(columns) }
from users
`
// Which results in:
select "name", "age" from users
Dynamic inserts
const user = {
name: 'Murray',
age: 68
}
await sql`
insert into users ${
sql(user, 'name', 'age')
}
`
// Which results in:
insert into users ("name", "age") values ($1, $2)
// The columns can also be given with an array
const columns = ['name', 'age']
await sql`
insert into users ${
sql(user, columns)
}
`
You can omit column names and simply execute sql(user) to get all the fields from the object as columns. Be careful not to allow users to supply columns that you do not want to be inserted.
Multiple inserts in one query
If you need to insert multiple rows at the same time it's also much faster to do it with a single insert. Simply pass an array of objects to sql().
const users = [{
name: 'Murray',
age: 68,
garbage: 'ignore'
},
{
name: 'Walter',
age: 80
}]
await sql`insert into users ${ sql(users, 'name', 'age') }`
// Is translated to:
insert into users ("name", "age") values ($1, $2), ($3, $4)
// Here you can also omit column names which will use object keys as columns
await sql`insert into users ${ sql(users) }`
// Which results in:
insert into users ("name", "age") values ($1, $2), ($3, $4)
Dynamic columns in updates
This is also useful for update queries
const user = {
id: 1,
name: 'Murray',
age: 68
}
await sql`
update users set ${
sql(user, 'name', 'age')
}
where user_id = ${ user.id }
`
// Which results in:
update users set "name" = $1, "age" = $2 where user_id = $3
// The columns can also be given with an array
const columns = ['name', 'age']
await sql`
update users set ${
sql(user, columns)
}
where user_id = ${ user.id }
`
Multiple updates in one query
To create multiple updates in a single query, it is necessary to use arrays instead of objects to ensure that the order of the items correspond with the column names.
const users = [
[1, 'John', 34],
[2, 'Jane', 27],
]
await sql`
update users set name = update_data.name, age = (update_data.age)::int
from (values ${sql(users)}) as update_data (id, name, age)
where users.id = (update_data.id)::int
returning users.id, users.name, users.age
`
Dynamic values and where in
Value lists can also be created dynamically, making where in queries simple too.
const users = await sql`
select
*
from users
where age in ${ sql([68, 75, 23]) }
`
or
const [{ a, b, c }] = await sql`
select
*
from (values ${ sql(['a', 'b', 'c']) }) as x(a, b, c)
`
Building queries
Postgres.js features a simple dynamic query builder by conditionally appending/omitting query fragments.
It works by nesting sql`` fragments within other sql`` calls or fragments. This allows you to build dynamic queries safely without risking sql injections through usual string concatenation.
Partial queries
const olderThan = x => sql`and age > ${ x }`
const filterAge = true
await sql`
select
*
from users
where name is not null ${
filterAge
? olderThan(50)
: sql``
}
`
// Which results in:
select * from users where name is not null
// Or
select * from users where name is not null and age > 50
Dynamic filters
await sql`
select
*
from users ${
id
? sql`where user_id = ${ id }`
: sql``
}
`
// Which results in:
select * from users
// Or
select * from users where user_id = $1
Dynamic ordering
const id = 1
const order = {
username: 'asc'
created_at: 'desc'
}
await sql`
select
*
from ticket
where account = ${ id }
order by ${
Object.entries(order).flatMap(([column, order], i) =>
[i ? sql`,` : sql``, sql`${ sql(column) } ${ order === 'desc' ? sql`desc` : sql`asc` }`]
)
}
`
SQL functions
Using keywords or calling functions dynamically is also possible by using sql`` fragments.
const date = null
await sql`
update users set updated_at = ${ date || sql`now()` }
`
// Which results in:
update users set updated_at = now()
Table names
Dynamic identifiers like table names and column names is also supported like so:
const table = 'users'
, column = 'id'
await sql`
select ${ sql(column) } from ${ sql(table) }
`
// Which results in:
select "id" from "users"
Quick primer on interpolation
Here's a quick oversight over all the ways to do interpolation in a query template string:
| Interpolation syntax | Usage | Example | | ------------- | ------------- | ------------- | | `${
Related Skills
notion
349.0kNotion API for creating and managing pages, databases, and blocks.
feishu-drive
349.0k|
things-mac
349.0kManage Things 3 via the `things` CLI on macOS (add/update projects+todos via URL scheme; read/search/list from the local Things database)
clawhub
349.0kUse the ClawHub CLI to search, install, update, and publish agent skills from clawhub.com
