pg-promise Documentation

repository·master·Indexed 25 days ago

https://github.com/vitaly-t/pg-promise

A high-level PostgreSQL interface for Node.js (version 12.7.0) that extends the node-postgres driver. It features automatic connection management, transaction handling, a powerful query-formatting engine with support for index variables and named parameters, and result-specific methods (none, one, many, etc.) to ensure predictable data handling.

Tokens
11.9K
Snippets
30
Records
61
Agent score
80%

What's inside pg-promise

  1. Overview of pg-promise features

    master

    pg-promise is a PostgreSQL interface for Node.js built on top of node-postgres. It provides several high-level features to simplify database interactions:

    • Automatic connections: Manages connection acquisition and release.
    • Automatic transactions: Simplifies transaction management.
    • Query-formatting engine: A powerful engine for high-performance value escaping and query generation.
    • Declarative result handling: Uses result-specific methods to handle data predictably.
    • Global events reporting: Allows for central handling of database events.
    • SQL file support: Extensive support for using external SQL files.
  2. Use Formatting Filters in Queries

    master

    Formatting filters (modifiers) allow you to change how values are formatted based on their JavaScript type. These work with both [Index Variables] (e.g., $1:filter) and [Named Parameters] (e.g., ${var:filter}).

    Note: Formatting filters are only available for normal queries. They are not available within PreparedStatement or ParameterizedQuery because those are formatted on the server side.

    // With Index Variables
    await db.any('SELECT $1:name FROM $2:name', ['price', 'products'])
    
    // With Named Parameters
    await db.any('SELECT ${column:name} FROM ${table:name}', {
        column: 'price',
        table: 'products'    
    });
  3. Access the `helpers` namespace in pg-promise

    master

    After initializing the pg-promise library with your configuration options, you can access the helpers namespace via the instance returned by the initialization function. The helpers namespace provides various utilities for SQL formatting and query construction.

    const pgp = require('pg-promise')(/*initialization options*/);
    const helpers = pgp.helpers; // `helpers` namespace
  4. Use Nested Named Parameters

    master

    Named parameters support property nesting of any depth. The resolution chain is highly flexible and supports recursion. The last name in the resolution can be:

    1. A basic JavaScript type.
    2. A function that returns a value, another function, or a Custom Type Formatting object.
    3. A Custom Type Formatting object that returns a value, another Custom Type Formatting object, or a function.

    Note: Nested parameters are not supported within the helpers namespace.

    const obj = {
        one: {
            two: {
                three: {
                    value1: 123,
                    value2: a => {
                        // a = obj.one.two.three
                        return 'hello';
                    },
                    value3: function(a) {
                        // a = this = obj.one.two.three
                        return 'world';
                    },
                    value4: {
                        toPostgres: a => {
                            // Custom Type Formatting
                            // a = obj.one.two.three.value4
                            return a.text;
                        },
                        text: 'custom'
                    }
                    
                }
            }
        }
    };
    await db.one('SELECT ${one.two.three.value1}', obj); //=> SELECT 123
    await db.one('SELECT ${one.two.three.value2}', obj); //=> SELECT 'hello'
    await db.one('SELECT ${one.two.three.value3}', obj); //=> SELECT 'world'
    await db.one('SELECT ${one.two.three.value4}', obj); //=> SELECT 'custom'
  5. Extend the pg-promise protocol with TypeScript

    master

    You can extend the pg-promise protocol (e.g., adding custom methods to the db object) by using the extend event in the initialization options. To maintain type safety, you must define an interface for your extensions and pass it as a type parameter to pgPromise.IInitOptions<IExtensions>.

    import * as pgPromise from 'pg-promise';
    
    // your protocol extensions:
    interface IExtensions {
        findUser(userId: number): Promise<any>;
    }
    
    // pg-promise initialization options:
    const options: pgPromise.IInitOptions<IExtensions> = {
        extend(obj) {
            obj.findUser = userId => {
                return obj.one('SELECT * FROM Users WHERE id = $1', [userId]);
            }
        }
    };
    
    // initializing the library:
    const pgp = pgPromise(options);
    
    // database object:
    const db = pgp('postgres://username:password@host:port/database');
    
    // protocol is extended on each level:
    const user = await db.findUser(123);
    
    // ...including inside tasks and transactions:
    await db.task(async t => {
        const user = await t.findUser(123);
        // ...etc
    });
  6. Use Index Variables for query formatting

    master

    Index variables use the $1, $2, ... syntax to inject values into a query string based on their position in an array. This is the simplest form of parameterization.

    Array-based indexing:

    await db.any('SELECT * FROM product WHERE price BETWEEN $1 AND $2', [1, 10])

    Single-value indexing: You can pass a single basic type (number, bigint, string, boolean, Date, or null) directly if the query only uses $1. However, passing values within an array is generally safer to avoid ambiguity with complex types like Array or Object.

    await db.any('SELECT * FROM users WHERE name = $1', 'John')

    WARNING: Never use ES6 template strings or manual string concatenation to generate queries. Always use the library's formatting engine to ensure proper PostgreSQL escaping.

  7. Implement Custom Type Formatting (CTF)

    master

    You can define how specific JavaScript objects are formatted for PostgreSQL using Custom Type Formatting (CTF). There are two methods:

    1. Explicit CTF

    Implement a toPostgres(self) method on your object. The method is called with the object as the this context.

    • If you want the returned value to be treated as pre-formatted (Raw Text), set rawType: true on the object.

    2. Symbolic CTF

    Use ES6 Symbols to define toPostgres and rawType. This allows you to extend types without changing their visible signature (e.g., via pgp.as.ctf).

    // Explicit CTF Example
    class STPoint {
        constructor(x, y) {
            this.x = x;
            this.y = y;
            this.rawType = true; // Result from toPostgres is injected as Raw Text
        }
        
        toPostgres(self) {
            return pgp.as.format('ST_MakePoint($1, $2)', [this.x, this.y]);
        }
    }
    
    // Symbolic CTF Example
    const {toPostgres, rawType} = pgp.as.ctf;
    const obj = {
        [toPostgres](self) {
            return 'some formatted value';
        },
        [rawType]: true
    };
  8. Use Named Parameters for query formatting

    master

    When the values argument is an object, the formatting engine uses Named Parameter syntax. You can use any of the following open-close pairs for variable names: {} , () , <> , [] , or //.

    Example usage:

    await db.none('INSERT INTO users(first_name, last_name, age) VALUES(${name.first}, $<name.last>, $/age/)', {
        name: {
            first: 'John',
            last: 'Dow'
        },
        age: 30
    });

    Key Rules:

    • Variable Names: Must follow standard JavaScript variable naming rules.
    • this keyword: The name this is reserved and refers to the formatting object itself, which is inserted as a JSON-formatted string.
    • Missing Properties: If a property does not exist in the object, an error is thrown. If a property is null or undefined, it is formatted as null in the SQL.
    • ES6 Template Strings: If you must use ES6 template strings, do not use ${}. Instead, use one of the supported pairs: $(), $<>, $[], or $//.
  9. Initialize pg-promise

    master

    To use the library, you must first initialize it. You can initialize it with an optional initOptions object or without any options.

    It is recommended to initialize the library and create your Database object in its own dedicated module.

    // With initialization options
    const initOptions = {/* initialization options */};
    const pgp = require('pg-promise')(initOptions);
    
    // Without initialization options
    const pgp = require('pg-promise')();