TypeScript + SQLite
Generate synchronous TypeScript code for SQLite databases using the better-sqlite3 driver.
Overview
Section titled “Overview”| Property | Value |
|---|---|
| Generator | typescript/sqlite (or typescript/sqlite/better-sqlite3) |
| Runtime | Node.js |
| API Style | Synchronous |
| Driver | better-sqlite3 |
When to Use
Section titled “When to Use”Choose typescript/sqlite when:
- Building Node.js applications with SQLite
- Need synchronous API for simpler code flow
- Want maximum performance for single-connection scenarios
Installation
Section titled “Installation”pnpm add -D @sqg/sqg # pnpmnpm install -D @sqg/sqg # npmyarn add -D @sqg/sqg # yarn
# Install runtime dependenciespnpm add better-sqlite3pnpm add -D @types/better-sqlite3Example Configuration
Section titled “Example Configuration”version: 1name: my-app
sql: - files: - queries.sql gen: - generator: typescript/sqlite output: ./src/generated/Quick Start
Section titled “Quick Start”-
Initialize a project
Terminal window sqg init --generator typescript/sqlite -
Write your SQL
-- MIGRATE 1CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT NOT NULL,email TEXT UNIQUE,created_at TEXT DEFAULT CURRENT_TIMESTAMP);-- QUERY all_usersSELECT * FROM users ORDER BY created_at DESC;-- QUERY get_user :one@set id = 1SELECT * FROM users WHERE id = ${id};-- QUERY find_users_by_name@set name = 'John'SELECT * FROM users WHERE name LIKE '%' || ${name} || '%';-- EXEC create_user@set name = 'John Doe'INSERT INTO users (name, email) VALUES (${name}, ${email});-- EXEC update_user@set id = 1@set name = 'Jane Doe'UPDATE users SET name = ${name} WHERE id = ${id};-- EXEC delete_user@set id = 1DELETE FROM users WHERE id = ${id}; -
Generate code
Terminal window sqg sqg.yaml -
Use the generated code
import Database from 'better-sqlite3';import { MyApp } from './generated/my-app';// Create database connectionconst db = new Database('app.db');// Run migrationsfor (const migration of MyApp.getMigrations()) {db.exec(migration);}// Create query instanceconst queries = new MyApp(db);// Insert data// Query dataconst users = queries.allUsers();console.log(users);// [{ id: 1, name: 'Alice', email: '[email protected]', created_at: '...' }, ...]const user = queries.getUser(1);console.log(user?.name); // 'Alice'// Update dataqueries.updateUser(1, 'Alice Smith');// Delete dataqueries.deleteUser(2);
Generated Code Structure
Section titled “Generated Code Structure”The generator creates a single TypeScript file with:
- Type definitions for each query result
- A class with methods for each query/exec
- Static
getMigrations()method returning migration SQL strings
// ...
allUsers(): { id: number; name: string; email: string | null; created_at: string | null; }[] { const stmt = this.prepare< [], { id: number; name: string; email: string | null; created_at: string | null; } >("all_users", "SELECT * FROM users ORDER BY created_at DESC;"); return stmt.all(); }
// ...Transactions
Section titled “Transactions”Use better-sqlite3’s built-in transaction support:
const transfer = db.transaction((fromId: number, toId: number, amount: number) => { queries.debit(fromId, amount); queries.credit(toId, amount);});
// Runs atomicallytransfer(1, 2, 100);Connection Management
Section titled “Connection Management”better-sqlite3 connections are synchronous and don’t require pooling:
// Simple single connectionconst db = new Database('app.db');const queries = new MyApp(db);
// WAL mode for better concurrencydb.pragma('journal_mode = WAL');
// Close when donedb.close();Type Mapping
Section titled “Type Mapping”| SQLite Type | TypeScript Type |
|---|---|
INTEGER | number |
REAL | number |
TEXT | string |
BLOB | Buffer |
NULL | null |
Nullable columns use union types: string | null
Best Practices
Section titled “Best Practices”- Use WAL mode for better concurrent read performance
- Run migrations on startup before creating the query instance
- Use transactions for multiple related writes
- Close the database when your application shuts down