npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

pg-lit

v0.3.0

Published

A tagged template literal interface for `node-postgres`.

Downloads

1

Readme

pg-lit

A tagged template literal interface for node-postgres.

Build Status Coverage Status

Also available: Syntax Highlighting in VS Code

Contents

Installation

npm i pg pg-lit
# for TypeScript
npm i -D @types/pg

Getting Started

pg-lit takes any configuration that you'd normally pass to a pg.Pool constructor and returns a template tag for querying the pool.

import { pgLit } from 'pg-lit'
// or
const { pgLit } = require('pg-lit')

const sql = pgLit({ ...PoolConfig })

Features

The pg library is solid, but I found it somewhat unergonomic for a few common tasks. pg-lit is a small wrapper that makes these tasks simpler while remaining "SQL-first".

Robust alternatives to pg-lit include porsager/postgres and adelsz/pgtyped.

Parameterized Queries

pg-lit uses the parameterized queries mechanism provided by node-postgres. Queries created by pg-lit are formatted as "config" objects that are passed to the node-postgres driver.

sql`select ${7} as "seven"`

{
  text: 'select $1 as "seven"',
  values: [7]
}

Async/Thenable

A query can be executed by await or .then() but it is lazily computed, so it will not perform any I/O until your code does one of these.

try {
  const [gotEm] = await sql`select ${7} as "seven"`
  // { seven: 7 }
} catch (err) {
  // deal with it
}

sql`select ${7} as "seven"`
  .then(([gotEm]) => {
    // { seven: 7 }
  })
  .catch(err => {
    // deal with it
  })

Fragments and Helpers

A few helpers are included that can be used for some common tasks that were less nice with the pg driver directly. Identifiers are escaped using the pg library. There are helpers for inserting and updating, and any of these can be embedded in larger queries.

const patch = { isCompleted: true }

await sql`
  update "todos"
  ${sql.set(patch, 'isCompleted')}
   where "todoId" = ${7}
`

{
  text: 'update "todos" set ("isCompleted") = row($1) where "todoId" = $2',
  values: [true, 7]
}

await sql.insertInto('users', [
  { username: 'bebop' },
  { username: 'rocksteady' }
])

{
  text: 'insert into "users" ("username") values ($1), ($2)',
  values: ['bebop', 'rocksteady']
}

Transactions

Transactions can be used with either automatic or manual commit and rollback. "Nested" transactions are implemented using savepoints.

// automatic
try {
  const [inserted] = sql.begin(async sql => {
    return sql`
      insert into "users"
      ${sql.insert({ username: 'krang' })}
      returning *
    `
  })
} catch (err) {
  // transaction rolled back
  // deal with it
}

// manual
const trx = await sql.begin()

try {
  await trx.insertInto('users', [
    { username: 'bebop' },
    { username: 'rocksteady' }
  ])
  await trx.commit()
} catch (err) {
  await trx.rollback()
}

Driver Access

You can still get at the pg.Pool instance once pgLit is instantiated.

const sql = pgLit({ /* PoolConfig */ })

await sql.pool.end() // shut it down

API

pgLit(poolConfig) -> PgLit

Instantiates a pg.Pool and wraps it in a template tag interface.

import { pgLit } from 'pg-lit'
const sql = pgLit({ ...PoolConfig })

PgLit`` -> SqlQuery

Calling the sql tag with a template literal produces a query that can be either executed on its own, or embedded within another SqlQuery. Values passed into the template string are not concatenated into the query text (because security), but instead gathered to be sent as query parameters with pg.

const simple = sql`select 1 as "one"`

const embedded = sql`
  with "selected" as (
    ${sql`select 1 as "one"`}
  )
  select "one"
    from "selected"
`

SqlQuery.then() -> Promise<SqlResult> OR await SqlQuery -> SqlResult

A SqlQuery is a thenable object, so you can either call .then() on it, to instantiate a Promise for your result or await the result. A safe, parameterized query is sent through pg to the database.

sql`select 1 as "one"`
  .then(result => {
    // got 'em
  })
  .catch(err => {
    // deal with it
  })

try {
  const result = await sql`select 1 as "one"`
  // got 'em
} catch (err) {
  // deal with it
}

SqlResult

The SqlResult is actually an Array of rows returned by your query.

const result = await sql`
  select *
    from "todos"
`

result.forEach(todo => {
  console.log(typeof todo) // 'object'
})

Usually the rows are what you're after, so for convenience that's what is returned, but properties of pg's Result are added directly to the array of rows in case you need them.

  • SqlResult.oid
  • SqlResult.fields
  • SqlResult.command
  • SqlResult.rowCount

SqlQuery.exec({ name, rowMode }) -> Promise<SqlResult>

Build and send the query to the database, optionally specifying a prepared statement name and a rowMode. These are options supported directly by pg.

PgLit.insertInto(table, rows, ...columns) -> SqlQuery

Create a query that takes care of the annoying parts of constructing a basic insert statement. Like any SqlQuery, it can be embedded into the template of another SqlQuery.

  • table the string name of the table to insert into.
  • rows a single object or array of objects.
  • columns are optional and by default will be inferred from the keys of first row being inserted.
const users = [
  { username: 'bebop' },
  { username: 'rocksteady' }
]

await sql.insertInto('users', users, 'username')

{
  text: 'insert into "users" ("username") values ($1), ($2)',
  values: ['bebop', 'rocksteady']
}

const [bebop] = await sql`
  with "inserted" as (
    ${sql.insertInto('users', users)}
    returning *
  )
  select *
    from "inserted"
   where "username" = 'bebop'
`

{
  text: `
    with "inserted" as (
      insert into "users" ("username")
      values ($1), $(2)
      returning *
    )
    select *
      from "inserted"
     where "username" = 'bebop'
  `,
  values: ['bebop', 'rocksteady']
}

PgLit.set(updates, ...columns) -> SetClause

Create a query fragment that takes care of the annoying parts of constructing the set clause of an update statement. Note: this is not an executable SqlQuery.

  • updates is an object.
  • columns are optional and by default will be inferred from the keys of the updates object.
const updates = {
  isCompleted: false
  task: 'do it again'
}

await sql`
  update "todos"
  ${sql.set(updates, 'task', 'isCompleted')}
   where "todoId" = 1
`

{
  text: `
    update "todos"
       set ("task", "isCompleted") = row($1, $2)
     where "todoId" = 1
  `,
  values: ['do it again', false]
}

PgLit.insert(rows, ...columns) -> ColumnsAndValues

Create a query fragment that takes care of the annoying parts of inserting records into a table while allowing an alias for the target table. Note: this is not an executable SqlQuery.

  • rows can be an object or an array.
  • columns are optional and by default will be inferred from the keys of the first row being inserted.
const rows = [
  { username: 'bebop' },
  { username: 'rocksteady' }
]

const result = await sql`
  insert into "users"
  ${sql.insert(rows, 'username')}
  returning *
`

{
  text: 'insert into "users" ("username") values ($1), ($2)',
  values: ['bebop', 'rocksteady']
}

PgLit.begin(Trx -> any) -> Promise<any>

A convenience method for executing a database transaction.

In this callback form, the transaction is managed for you by default. The return value of the callback is awaited and if this Promise is fulfilled, the transaction is committed. Otherwise, if this Promise is rejected, the transactions is rolled back.

The return value of the callback is also the Promise value returned by .begin() in this form.

try {
  const [inserted] = sql.begin(async sql => {
    // in here, sql is scoped to a specific client connection
    // to be used for the lifetime of the transaction
    return sql`
      insert into "users"
      ${sql.insert({ username: 'krang' })}
      returning *
    `
  })
} catch (err) {
  // transaction rolled back
  // deal with it
}

PgLit.begin() -> Promise<Trx>

In this form, you must manage the transaction yourself and ensure that either commit or rollback is called.

const trx = await sql.begin()

try {
  await trx.insertInto('users', [
    { username: 'bebop' },
    { username: 'rocksteady' }
  ])
  await trx.commit()
} catch (err) {
  await trx.rollback()
}

Trx.commit() -> Promise<void>

commit the transaction.

Trx.rollback() -> Promise<void>

rollback the transaction.

Trx.savepoint() -> Promise<void>

Create a uniquely identified savepoint for the transaction.

Trx.revert() -> Promise<void>

rollback to the last savepoint of the transaction.

Trx.begin(Trx -> any) -> Promise<any> OR Trx.begin()

Begin a "nested" transaction simulated with savepoint that is automatically saved again once the Promise is fulfilled or rolled back if the Promise is rejected. Note: on rejection, the entire transaction is rolled back to its start, not just to the last savepoint.

Trx`` -> Promise<SqlResult>

Trx.insertInto(table, rows, ...columns)

Trx.set(table, rows, ...columns)

Trx.insert(rows, ...columns)

The same methods available on a normal PgLit instance.