Config
Fixtures for configuration knobs that shape what sqlfu generate emits: sync,
importExtension, tsconfig-driven .ts-import detection, nested query directories, and the
runtime query catalog that drives the form UI.
No default config block on this page — every test here exercises a different
sqlfu.config.ts, so each one spells its config out in full.
sync: true emits SyncClient wrappers without async/await
Section titled “sync: true emits SyncClient wrappers without async/await”input
create table posts (id integer primary key, slug text not null, title text);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql', generate: {sync: true},};select id, slug, title from posts;select id, slug, title from posts where slug = :slug limit 1;insert into posts (slug, title) values (:slug, :title);output
import type {SyncClient} from 'sqlfu';
const sql = `select id, slug, title from posts;`;const query = { sql, args: [], name: "listPosts" };
export const listPosts = Object.assign( function listPosts(client: SyncClient): listPosts.Result[] { return client.all<listPosts.Result>(query); }, { sql, query },);
export namespace listPosts { export type Result = { id: number; slug: string; title?: string; };}import type {SyncClient} from 'sqlfu';
const sql = `select id, slug, title from posts where slug = ? limit 1;`;const query = (params: findPost.Params) => ({ sql, args: [params.slug], name: "findPost" });
export const findPost = Object.assign( function findPost(client: SyncClient, params: findPost.Params): findPost.Result | null { const rows = client.all<findPost.Result>(query(params)); return rows.length > 0 ? rows[0] : null; }, { sql, query },);
export namespace findPost { export type Params = { slug: string; }; export type Result = { id: number; slug: string; title?: string; };}import type {SyncClient} from 'sqlfu';
const sql = `insert into posts (slug, title) values (?, ?);`;const query = (params: insertPost.Params) => ({ sql, args: [params.slug, params.title], name: "insertPost" });
export const insertPost = Object.assign( function insertPost(client: SyncClient, params: insertPost.Params) { return client.run(query(params)); }, { sql, query },);
export namespace insertPost { export type Params = { slug: string; title: string | null; };}importExtension: ‘.ts’ emits .ts-suffixed barrel imports
Section titled “importExtension: ‘.ts’ emits .ts-suffixed barrel imports”input
create table posts (id integer primary key, slug text not null);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql', generate: {importExtension: '.ts'},};select id, slug from posts;output
export * from "./tables.ts";export * from "./list-posts.sql.ts";import type {Client} from 'sqlfu';
const sql = `select id, slug from posts;`;const query = { sql, args: [], name: "listPosts" };
export const listPosts = Object.assign( async function listPosts(client: Client): Promise<listPosts.Result[]> { return client.all<listPosts.Result>(query); }, { sql, query },);
export namespace listPosts { export type Result = { id: number; slug: string; };}tsconfig allowImportingTsExtensions switches the barrel to .ts by default
Section titled “tsconfig allowImportingTsExtensions switches the barrel to .ts by default”input
create table posts (id integer primary key, slug text not null);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql',};{"compilerOptions": {"allowImportingTsExtensions": true}}select id, slug from posts;output
export * from "./tables.ts";export * from "./list-posts.sql.ts";explicit generate.importExtension overrides tsconfig detection
Section titled “explicit generate.importExtension overrides tsconfig detection”input
create table posts (id integer primary key, slug text not null);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql', generate: {importExtension: '.js'},};{"compilerOptions": {"allowImportingTsExtensions": true}}select id, slug from posts;output
export * from "./tables.js";export * from "./list-posts.sql.js";preserves nested query directories in output, name, and functionName
Section titled “preserves nested query directories in output, name, and functionName”input
create table profiles (id integer primary key, name text not null);create table orders (id integer primary key, total integer not null);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql',};select id, name from profiles;select id, total from orders;output
export * from "./tables.js";export * from "./orders/list-orders.sql.js";export * from "./users/list-profiles.sql.js";import type {Client} from 'sqlfu';
const sql = `select id, name from profiles;`;const query = { sql, args: [], name: "usersListProfiles" };
export const usersListProfiles = Object.assign( async function usersListProfiles(client: Client): Promise<usersListProfiles.Result[]> { return client.all<usersListProfiles.Result>(query); }, { sql, query },);
export namespace usersListProfiles { export type Result = { id: number; name: string; };}import type {Client} from 'sqlfu';
const sql = `select id, total from orders;`;const query = { sql, args: [], name: "ordersListOrders" };
export const ordersListOrders = Object.assign( async function ordersListOrders(client: Client): Promise<ordersListOrders.Result[]> { return client.all<ordersListOrders.Result>(query); }, { sql, query },);
export namespace ordersListOrders { export type Result = { id: number; total: number; };}DDL wrappers: drop / alter / pragma / multi-statement / comments
Section titled “DDL wrappers: drop / alter / pragma / multi-statement / comments”input
create table posts (id integer primary key, slug text not null);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql',};drop table posts;alter table posts add column title text;pragma foreign_keys = on;drop table if exists posts;create table posts (id integer primary key, slug text not null);-- ensure the drafts table exists before we import/* multi-line comment */create table if not exists drafts (id integer primary key, body text not null);output
import type {Client} from 'sqlfu';
const sql = `drop table posts;`;const query = { sql, args: [], name: "dropPosts" };
export const dropPosts = Object.assign( async function dropPosts(client: Client) { return client.run(query); }, { sql, query },);import type {Client} from 'sqlfu';
const sql = `alter table posts add column title text;`;const query = { sql, args: [], name: "alterPostsAddTitle" };
export const alterPostsAddTitle = Object.assign( async function alterPostsAddTitle(client: Client) { return client.run(query); }, { sql, query },);import type {Client} from 'sqlfu';
const sql = `pragma foreign_keys = on;`;const query = { sql, args: [], name: "enableForeignKeys" };
export const enableForeignKeys = Object.assign( async function enableForeignKeys(client: Client) { return client.run(query); }, { sql, query },);import type {Client} from 'sqlfu';
const sql = `drop table if exists posts;create table posts (id integer primary key, slug text not null);`.trim();const query = { sql, args: [], name: "resetPosts" };
export const resetPosts = Object.assign( async function resetPosts(client: Client) { return client.run(query); }, { sql, query },);import type {Client} from 'sqlfu';
const sql = `-- ensure the drafts table exists before we import/* multi-line comment */create table if not exists drafts (id integer primary key, body text not null);`.trim();const query = { sql, args: [], name: "commentedCreate" };
export const commentedCreate = Object.assign( async function commentedCreate(client: Client) { return client.run(query); }, { sql, query },);{ "queries": []}writes a runtime query catalog with json schema for forms
Section titled “writes a runtime query catalog with json schema for forms”input
create table posts ( id integer primary key, slug text not null, title text, is_published boolean not null, status text not null check (status in ('draft', 'published')));export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql',};select id, slug, title, is_published, statusfrom postswhere status = :status and is_published = :is_publishedlimit 10;output
{ "queries": [ { "kind": "query", "id": "find-posts", "sqlFile": "sql/find-posts.sql", "functionName": "findPosts", "queryType": "Select", "resultMode": "many", "args": [ { "scope": "params", "name": "status", "tsType": "('draft' | 'published')", "driverEncoding": "identity" }, { "scope": "params", "name": "is_published", "tsType": "number", "driverEncoding": "identity" } ], "paramsSchema": { "type": "object", "required": ["status", "is_published"], "properties": { "status": { "type": "string", "enum": ["draft", "published"] }, "is_published": { "type": "number" } } }, "resultSchema": { "type": "object", "properties": { "id": {"type": "number"}, "slug": {"type": "string"}, "title": {"anyOf": [{"type": "string"}, {"type": "null"}]}, "is_published": {"type": "number"}, "status": {"type": "string", "enum": ["draft", "published"]} } } } ]}includes invalid queries in the runtime query catalog
Section titled “includes invalid queries in the runtime query catalog”input
create table posts (id integer primary key, slug text not null);export default { db: './app.db', migrations: './migrations', definitions: './definitions.sql', queries: './sql',};select nope from missing_table;output
{ "queries": [ { "kind": "error", "id": "broken", "sqlFile": "sql/broken.sql", "functionName": "broken", "error": { "name": "Invalid sql" } } ]}