Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

183 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Inquire

NPM Package Tests Status Coverage Status Commits License

Inquire is a lightweight TypeScript SQL builder. It helps you define schemas, build SQL queries, and execute them through a connection wrapper. It does not model records, relationships, or unit-of-work behavior for you.

What Inquire is for

Use Inquire when you want:

  • typed query results in TypeScript
  • one small API for MySQL, PostgreSQL, SQLite, and PGlite
  • schema helpers without adopting a full ORM
  • the option to mix builders and raw SQL

Use something else if you want:

  • model instances and change tracking
  • relationship loading
  • repository patterns generated by the library
  • a full migration workflow with history and orchestration

Supported databases

Inquire supports these connection packages:

  • @stackpress/inquire-mysql2
  • @stackpress/inquire-pg
  • @stackpress/inquire-pglite
  • @stackpress/inquire-sqlite3

PostgreSQL-compatible services such as CockroachDB, Neon, Supabase, and Vercel Postgres can use the PostgreSQL adapter when the underlying driver is compatible.

Requirements

  • Node.js 22 or newer
  • yarn

Install

Install the core library and one connection package.

# Core package
yarn add @stackpress/inquire

# MySQL
yarn add @stackpress/inquire-mysql2 mysql2

# PostgreSQL
yarn add @stackpress/inquire-pg pg

# SQLite
yarn add @stackpress/inquire-sqlite3 better-sqlite3

# PGlite
yarn add @stackpress/inquire-pglite @electric-sql/pglite

Quick start

This is the shortest local path with SQLite.

import sqlite from 'better-sqlite3';
import connect from '@stackpress/inquire-sqlite3';

const resource = sqlite(':memory:');
const engine = connect(resource);

await engine.create('users')
  .addField('id', { type: 'integer', autoIncrement: true })
  .addField('email', { type: 'string', length: 255, nullable: false })
  .addField('name', { type: 'string', length: 255, nullable: false })
  .addPrimaryKey('id')
  .addUniqueKey('users_email_unique', 'email');

await engine.insert('users').values({
  email: 'ada@example.com',
  name: 'Ada'
});

type UserRow = {
  id: number;
  email: string;
  name: string;
};

const users = await engine.select<UserRow>([
    'id',
    'email',
    'name'
  ])
  .from('users')
  .where('email = ?', ['ada@example.com']);

console.log(users);

Connection examples

MySQL

import mysql from 'mysql2/promise';
import connect from '@stackpress/inquire-mysql2';

const resource = await mysql.createConnection({
  host: 'localhost',
  user: 'root',
  database: 'app'
});

const engine = connect(resource);

PostgreSQL

import { Client } from 'pg';
import connect from '@stackpress/inquire-pg';

const client = new Client({
  database: 'app',
  user: 'postgres'
});

await client.connect();

const engine = connect(client);

PGlite

import { PGlite } from '@electric-sql/pglite';
import connect from '@stackpress/inquire-pglite';

const resource = new PGlite('./build/database');
const engine = connect(resource);

Core API

The Engine creates six main builders:

  • create(table)
  • alter(table)
  • select(columns?)
  • insert(table)
  • update(table)
  • delete(table)

It also exposes:

  • query(query, values?)
  • sql\...``
  • transaction(callback)
  • diff(from, to)
  • rename(from, to)
  • drop(table)
  • truncate(table, cascade?)

Raw SQL

Use query() or sql when the builder surface is not enough.

const rows = await engine.query<{ id: number; email: string }>(
  'SELECT id, email FROM users WHERE id = ?',
  [1]
);

const ids = await engine.sql<{ id: number }>`
  SELECT id
  FROM users
  WHERE email LIKE ${'%@example.com'}
`;

Transactions

Use engine.transaction() when several writes must succeed or fail together.

await engine.transaction(async (tx) => {
  await tx.query({
    query: 'INSERT INTO users (email, name) VALUES (?, ?)',
    values: ['grace@example.com', 'Grace']
  });

  await tx.query({
    query: 'INSERT INTO profiles (user_id) VALUES (?)',
    values: [1]
  });
});

The transaction callback receives the connection wrapper, not a nested Engine.

Type safety

Use TypeScript generics to type query results.

type User = {
  id: number;
  email: string;
  name: string;
};

const users = await engine.select<User>([
    'id',
    'email',
    'name'
  ])
  .from('users');

Documentation

The full docs now live under specs:

Examples

For package-level usage examples, see:

Releases

Packages

Used by

Contributors

Languages