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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@iarna/pg

v1.1.2

Published

A wrapper around `pg` providing convenience methods, an appropriate SQL template string function, easy access to cursor based streaming results (thanks to `pg-query-stream`) and a reasonable, retrying, transaction interface.

Downloads

15

Readme

@iarna/pg

A wrapper around pg providing convenience methods, an appropriate SQL template string function, easy access to cursor based streaming results (thanks to pg-query-stream) and a reasonable, retrying, transaction interface.

CONSTRUCTION

Databases always use instances of Pool.

const { PG, sql } = require('@iarna/pg')

const pg = new PG({connectionString: 'postgresql://...'})
const row = pg.get(sql`SELECT * FROM example WHERE id=${23}`)

pg.end()

Closes all connections and disables the pool. Further queries will be an error.

QUERY METHODS

All query methods either take a query produced by the sql template string function, or an SQL string, followed by an array of values to use as values for bound parameters. That is to say the all accept the following function signatures: ([SQL, BoundParams]) or (SQL, BoundParams).

If any of the queries encounter an error, the resulting error object will have the SQL and bound parameters in the sql and binds properties respectively.

sql`SQL QUERY HERE` -> [SQL, BoundParams]

The SQL template strings replace values as follows:

  • Nulls and undefined values are replaced with NULL
    sql`${null}` -> [NULL, []]
    sql`${undefined}` -> [NULL, []]
  • Plain values are replaced with a placeholder, eg $1 and bound, eg
    sql`${23}` -> ['$1', [23]]
    sql`${'abc'}` -> ['$1', ['abc']]
  • You can explicitly cast a value by passing in an object with a key of ::type or $$type. eg
    sql`${{'::int': 23}}` -> ['$1::int', [23]]
    sql`${{$$int: 23}} -> ['$1::int', [23]]
  • Arrays are replaced with a parenthisized list with placeholders for each value, eg
    sql`${[1,2,3]}` -> ['($1, $2, $3)', [1, 2, 3]]
    Individual values of the arrays may be cast, eg:
    sql`${[1,2,{$$int: 3}]}` -> ['($1, $2, $3::int)', [1, 2, 3]]
  • If you want a postgres array type, you can get them by explicitly casting, either to a concrete type, or to array where it will be guessed from your data.
    sql`${{$$array:[1,2,3]}}` -> ['$1::numeric[]', [[1,2,3]]]
    sql`${{$$text:[1,2,3]}}` -> ['$1::text[]', [[1,2,3]]]
  • Ordinary objects become comma separated key-value pairs, appropriate for UPDATE. Nulls and plain values are the same as with direct values. Undefined values are ignored. eg
    sql`${{abc: 1, def: 2, ghi: null}}` -> ['abc=$1, def=$2, ghi=NULL', [1, 2]]
    Array values of objects are always cast to postgres array types, with a best guess as to type, eg
    sql`${{abc: [1, 2, 3]}}` -> ['abc=$1::numeric[]', [[1, 2, 3]]]
    Or you can explicitly cast the array, and you should if your array might be empty:
    sql`${{abc: {$$int: [1, 2, 3]}}}` -> ['abc=$1::int[]', [[1, 2, 3]]]
  • And finally, if you want to construct portions of WHERE clauses, an object with only a key of _ and a value of the object to become the where clause. The output is parenthesised and the fields are separated with AND instead of , . Specific value types differ in:
    • Null values are emitted as field IS NULL instead of field=NULL
    • Undefined values are ignored instead of being emitted as field=NULL.
    • Arrays are emitted as field IN ($1, $2, $2)
    • Cast arrays are emitted with a contains-within query, eg field @> $1::type[]

pg.run(query) -> Promise(rowCount)

Execute a query for which you don't need any results.

pg.value(query) -> Promise(value)

Execute a query and return the value of the first column of the first row. As a rule, your query should only have one column and row.

pg.get(query) -> Promise(row)

Execute a query and return the first row. As a rule, your query should only return one row.

pg.all(query) -> Promise(Array(row))

Execute a query and return an array of all of the matching rows.

pg.iterate(query) -> FunStream

Execute a query and return a stream of rows. As a funstream, it is an ordinary Node stream, but it also has Array-type functions like .map, .filter, etc. .all will always be faster, unless you're running out of memory.

TRANSACTION METHODS

pg.serial(todo[, commit, rollback]) -> Promise(todoResult)

pg.committed(todo[, commit, rollback]) -> Promise(todoResult)

pg.repeatable(todo[, commit, rollback]) -> Promise(todoResult)

pg.readonly(todo[, commit, rollback]) -> Promise(todoResult)

Creates a dedicated connection for the transaction and passes that to the todo function.

todo, commit and rollback are all functions that may return promises or act synchronously. commit and rollback are there to take actions in Node.js needed to make either commit or rollback the actions taken in the transaction. They are NOT for doing database things in. Most of the time you don't need them. You only need them if you want to mutate Node.js data structures in your transaction.

Based on which transaction method you used, it selects an isolation level as follows:

  • serial - SERIALIZABLE
  • committed - READ COMMITTED
  • repeatable - REPEATABLE READ
  • readonly - REPEATABLE READ READ ONLY

All actions within the transaction must be on the provided client, not the object that you created the transaction on.

If todo succeeds, then the transaction is committed and commit() is run before finally returning the value that todo returned.

If todo fails, then the transaction is rolled back and rollback() is run.

If the transaction fails due to an error that may be retriable (eg, a deadlock) then it will be retried up to 10 times. The system will sleep a random amount of time between 1ms and 1000ms between each attempt.

If the transaction fails for any other reason, then the error propagated.

Please note that due to retries, your todo and rollback methods may be called several times as retries happen.

WHY THIS?

Everyone seems to need to write one of these, myself included.