SQL Select TS Query Builder
sql-select-ts is a modern, database-agnostic SELECT query builder for JavaScript and TypeScript, currently stable at version 2.0.18. It distinguishes itself through its composable API and strong static type checking, making it an excellent choice for projects prioritizing type safety and maintainable SQL generation. The package exhibits a frequent release cadence, with numerous minor updates and bug fixes being published regularly, indicating active development and responsiveness to community feedback. Its core value proposition lies in enabling developers to construct complex SELECT queries programmatically without sacrificing type safety or database portability, moving beyond raw string concatenation or less type-safe alternatives. It focuses specifically on SELECT statements, offering a streamlined API for this common database operation, and is suitable for both Node.js and browser environments.
Common errors
-
TS2339: Property 'nonExistentColumn' does not exist on type 'Table<User>'
cause Attempting to reference a column name that is not defined in the TypeScript interface associated with the table.fixEnsure the column name exactly matches a property in the interface provided to `table<T>`, or add the missing property to the interface. -
SyntaxError: require is not defined in ES module scope
cause Attempting to use CommonJS `require()` syntax to import modules from `sql-select-ts` in an ES Module environment (or when Node.js is configured for ESM).fixUse ES Module `import` syntax: `import { select, column } from 'sql-select-ts';` -
TypeError: select is not a function
cause Incorrectly attempting a default import of `select` or a CommonJS `require` of a named export.fixEnsure `select` is imported as a named export: `import { select } from 'sql-select-ts';` (not `import select from 'sql-select-ts'`).
Warnings
- gotcha Using the `raw()` function directly allows for arbitrary SQL injection if user-supplied input is not properly sanitized, bypassing the type safety and protective mechanisms of the query builder.
- gotcha While `sql-select-ts` is database-agnostic, it generates standard SQL. Specific database dialects (e.g., PostgreSQL, MySQL, SQL Server) may have unique functions or syntax not directly supported by the builder's fluent API. These will require the use of `raw()` expressions.
- gotcha When using `.as()` for column aliases, especially in conjunction with `raw()` expressions, the inferred TypeScript type of the resulting query's output may become less specific or require explicit type assertions downstream.
Install
-
npm install sql-select-ts -
yarn add sql-select-ts -
pnpm add sql-select-ts
Imports
- select
import select from 'sql-select-ts'
import { select } from 'sql-select-ts' - column
const column = require('sql-select-ts').columnimport { column } from 'sql-select-ts' - table
import { table } from 'sql-select-ts' - raw
import { raw } from 'sql-select-ts'
Quickstart
import { select, column, table, raw } from 'sql-select-ts';
interface User {
id: number;
name: string;
email: string;
createdAt: Date;
}
interface Post {
id: number;
userId: number;
title: string;
}
const users = table<User>('users');
const posts = table<Post>('posts');
// Build a complex SELECT query with joins, conditions, grouping, and ordering
const query = select(
column(users.id),
column(users.name).as('userName'),
column(users.email),
raw('COUNT(posts.id)').as('postCount')
)
.from(users)
.leftJoin(posts)
.on(column(users.id).eq(column(posts.userId)))
.where(column(users.createdAt).gt(raw("NOW() - INTERVAL '1 year'")))
.groupBy(column(users.id), column(users.name), column(users.email))
.orderBy(column(users.name).asc())
.limit(10)
.offset(0);
const queryString = query.toSQL();
console.log(queryString);
/*
Expected output:
SELECT users.id, users.name AS userName, users.email, COUNT(posts.id) AS postCount
FROM users
LEFT JOIN posts ON users.id = posts.userId
WHERE users.createdAt > NOW() - INTERVAL '1 year'
GROUP BY users.id, users.name, users.email
ORDER BY users.name ASC
LIMIT 10 OFFSET 0
*/