A tiny wrapper around pg that makes PostgreSQL a lot of fun to use. Written in TypeScript.

Overview

Coverage Status npm

A tiny wrapper around pg that makes PostgreSQL a lot of fun to use. Written in TypeScript.

import Pg from '@mojojs/pg';

// Use standard PostgreSQL connection URIs
const pg = new Pg('postgres://user:password@localhost:5432/database');

// Single query with safe placeholder
const results = await pg.query`SELECT ${'One'} AS one`;
for (const row of results) {
  console.log(row.one);
}

// Multiple queries on the same connection
const db = await pg.db();
const results = await db.query`SELECT 2`;
const results = await db.query`SELECT 3`;
await db.release();

Tagged template literals are used everywhere to protect from SQL injection attacks and to make syntax highlighting easy.

TypeScript

TypeScript is fully supported, just pass along a type with your query. This works for all query methods.

interface User {
  id: number;
  name: string;
}

const results = await pg.query<User>`SELECT * FROM users`;
for (const {id, name} of results) {
  console.log(`${id}: ${name}`);
}

SQL building

For easier SQL query building with partials, there are also pg.sql and db.sql tagged template literals. They can be used recursively to build complex queries securely.

// Build safe SQL query with placeholder and partial SQL query
const role = 'admin';
const partialQuery = pg.sql`AND role = ${role}`;
const name = 'root';
const results = await pg.query`SELECT * FROM users WHERE name = ${name} ${partialQuery}`;

But if you need a little more control over the generated SQL query, you can of course also bypass safety features with the tagged template literals pg.sqlUnsafe and db.sqlUnsafe. But make sure to use methods like pg.escapeLiteral() to escape unsafe values yourself.

const role = 'role = ' + pg.escapeLiteral('power user');
const partialQuery = pg.sqlUnsafe`AND ${role}`;
const name = 'root';
const results = await pg.query`SELECT * FROM users WHERE name = ${name} ${partialQuery}`;

And if you want to do complex things like reusing the same placeholder in multiple places, there is also pg.rawQuery() and db.rawQuery() available.

const results = await pg.rawQuery('SELECT * FROM users WHERE name = $1 AND login = $1', 'Sara');

Transactions

It's best to use try/finally blocks whenever you dequeue a connection with pg.db(), to ensure efficient resource management.

try {
  const db = await pg.db();
  const tx = await db.begin();

  try {
    for (const user of ['Daniel', 'Isabell']) {
      await db.query`INSERT INTO users (name) VALUES (${user})`;
    }
    await tx.commit();

  } finally {
    await tx.rollback();
  }
} finally {
  await db.release();
}

The tx.rollback() call does nothing if tx.commit() has been called first.

Migrations

To manage your database schema, there is also a minimal SQL based migration system built-in. A migration file is just a collection of sql blocks, with one or more statements, separated by comments of the form -- VERSION UP/DOWN.

-- 1 up
CREATE TABLE messages (message TEXT);
INSERT INTO messages VALUES ('I ♥ Mojolicious!');
-- 1 down
DROP TABLE messages;
 
-- 2 up (...you can comment freely here...)
CREATE TABLE stuff (whatever INT);
-- 2 down
DROP TABLE stuff;

The idea is to let you migrate from any version, to any version, up and down. Migrations are very safe, because they are performed in transactions and only one can be performed at a time. If a single statement fails, the whole migration will fail and get rolled back. Every set of migrations has a name, which is stored together with the currently active version in an automatically created table named mojo_migrations.

import Path from '@mojojs/path';

// Load migrations from "migrations/myapp.sql" and migrate to the latest version
await pg.migrations.fromFile(Path.currentFile().sibling('migrations', 'myapp.sql'), {name: 'myapp'});
await pg.migrations.migrate();

// Use migrations to drop and recreate the schema
await pg.migrations.migrate(0);
await pg.migrations.migrate();

// Load migrations from a string
pg.migrations.fromString('-- 1 up\n...', {name: 'my_other_app'});

// Load migrations from a directory
await pg.migrations.fromDirecory(Path.currentFile().sibling('migrations'), {name: 'yet_another_app'});

To store your individual migration steps in separate SQL files you can use a directory structure like this. These files do not require special comments, because the version and migration direction are contained in the file names.

`--migrations
   |-- 1
   |   |-- up.sql
   |   `-- down.sql
   |-- 2
   |   `-- up.sql
   |-- 4
   |   |-- up.sql
   |   `-- down.sql
   `-- 5
       |-- up.sql
       `-- down.sql

Migrations are also compatible with Mojo::Pg, if you want to mix Perl and JavaScript code.

Notifications

You can use events as well as async iterators for notifications.

// Send notifications
const db = await pg.db();
await db.notify('foo', 'just a message');

// Use an iterator to wait for incoming notifications
await db.listen('foo');
for await (const message of db) {
  console.log(`${message.channel}: ${message.payload}`);
  break;
}
await db.unlisten('foo');

// Use event to handle incoming notifications
await db.listen('bar');
db.on('notification', (message) => {
  console.log(`${message.channel}: ${message.payload}`);
});
await db.unlisten('bar');

Introspection

You can set the MOJO_PG_DEBUG environment variable to get all SQL queries printed to STDERR.

$ MOJO_CLIENT_DEBUG=1 node myapp.js
-- Query
INSERT INTO users (name) VALUES ($1)

Examples

This distribution also contains a great example you can use for inspiration. The well-structured blog application will show you how to apply the MVC design pattern in practice.

Future

This package is designed to be compatible with the explicit resource management proposal and will support it as soon as the using keyword is available in Node.js.

// Multiple queries on the same connection (with automatic resource management)
using await const db = await pg.db();
const results = await db.query`SELECT 2`;
const results = await db.query`SELECT 3`;

Editor Support

Installation

All you need is Node.js 16.0.0 (or newer).

$ npm install @mojojs/pg
You might also like...

A PostgreSQL client with strict types, detailed logging and assertions.

A PostgreSQL client with strict types, detailed logging and assertions.

Slonik A battle-tested PostgreSQL client with strict types, detailed logging and assertions. (The above GIF shows Slonik producing query logs. Slonik

Jan 3, 2023

PostgreSQL interface for Node.js

pg-promise PostgreSQL interface for Node.js About Support & Sponsorship Documentation Contributing Usage Methods Query Formatting Index Variables Name

Jan 6, 2023

NodeJS PostgreSQL database performance insights. Locks, index usage, buffer cache hit ratios, vacuum stats and more.

Node Postgres Extras NodeJS port of Heroku PG Extras with several additions and improvements. The goal of this project is to provide powerful insights

Nov 14, 2022

A simple url shorter API built with nodejs running on Kubernetes in Google Cloud, using PostgreSQL for storage and cloud sql proxy.

Simple URL Shorter - Google Cloud - Kubernetes A simple url shorter API built with nodejs running on Kubernetes in Google Cloud, using PostgreSQL for

Nov 25, 2021

Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

Dec 30, 2022

A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud.

Dittorm A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud. Installatio

Dec 25, 2022

A Node.js library for retrieving data from a PostgreSQL database with an interesting query language included.

RefQL A Node.js library for retrieving data from a PostgreSQL database with an interesting query language included. Introduction RefQL is about retrie

Nov 2, 2022

Lovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.

Lovefield Lovefield is a relational database written in pure JavaScript. It provides SQL-like syntax and works cross-browser (currently supporting Chr

Jan 3, 2023

ConnectNOW - Live web application that allows you to connect with people around the world!

connectNOW Live web application that allows you to connect with people around the world! You can share images, quotes, and anything on your mind! It a

Jan 3, 2022
Comments
  • Port to MySQL?

    Port to MySQL?

    Hello!

    I just discovered the excellent Mojo.js yesterday and am super excited because I remember Mojo from back in my Perl days.

    I'd like to use Mojo.js but I want to use MySQL also. The pg.js project looks clean and I'm considering porting it over in order to support MySQL in a Mojo.js environment.

    Has this been done already? I don't want to duplicate someone else's work, but as a way to improve my TypeScript skills and extend an awesome framework I'd be happy to spend a little time on the port.

    Thoughts?

    opened by jdrago999 2
Owner
Mojolicious
Web development tools you can rely on
Mojolicious
Ultimate Script to complete PostgreSQL-to-PostgreSQL Migration right after AWS DMS task done

Ultimate Script to complete PostgreSQL-to-PostgreSQL Migration right after AWS DMS task done

방신우 22 Dec 23, 2022
ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.

TypeORM is an ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used

null 30.1k Jan 3, 2023
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite databases.

TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite datab

MikroORM 5.4k Dec 31, 2022
Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server & SQLite

Prisma Quickstart • Website • Docs • Examples • Blog • Slack • Twitter • Prisma 1 What is Prisma? Prisma is a next-generation ORM that consists of the

Prisma 28k Jan 2, 2023
just a graphql example created by typescript + fastify + mikro-orm(postgresql) + mercurius(graphql adaptor) + type-graphql

fastify-mikro-orm-mercurius-graphql-example A MikroORM boilerplate for GraphQL made with Fastify, Mercurius, Typescript using TypeGraphQL ?? Packages

Vigen 10 Aug 28, 2022
Validate and auto-generate TypeScript types from raw SQL queries in PostgreSQL.

SafeQL Write SQL Queries With Confidence • Get started Install I would first recommend follow the instructions in the documentation. npm install --sav

null 747 Dec 28, 2022
Illustration of issues around use of top-level await in Vite apps

vite-top-level-await-repro Illustration of issues around use of top-level await in Vite apps: https://github.com/vitejs/vite/issues/5013 Top-level awa

Rich Harris 6 Apr 25, 2022
Execute one command (or mount one Node.js middleware) and get an instant high-performance GraphQL API for your PostgreSQL database!

PostGraphile Instant lightning-fast GraphQL API backed primarily by your PostgreSQL database. Highly customisable and extensible thanks to incredibly

Graphile 11.7k Jan 4, 2023
PostgreSQL client for node.js.

node-postgres Non-blocking PostgreSQL client for Node.js. Pure JavaScript and optional native libpq bindings. Monorepo This repo is a monorepo which c

Brian C 10.9k Jan 9, 2023
A simple Node.js ORM for PostgreSQL, MySQL and SQLite3 built on top of Knex.js

bookshelf.js Bookshelf is a JavaScript ORM for Node.js, built on the Knex SQL query builder. It features both Promise-based and traditional callback i

Bookshelf.js 6.3k Jan 2, 2023