Skip to content
pre-alpha — the TypeScript API may still shift. The SQL won't.

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
definitions.sql
create table posts (id integer primary key, slug text not null, title text);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
generate: {sync: true},
};
sql/list-posts.sql
select id, slug, title from posts;
sql/find-post.sql
select id, slug, title from posts where slug = :slug limit 1;
sql/insert-post.sql
insert into posts (slug, title) values (:slug, :title);
output
sql/.generated/list-posts.sql.ts
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;
};
}
sql/.generated/find-post.sql.ts
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;
};
}
sql/.generated/insert-post.sql.ts
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
definitions.sql
create table posts (id integer primary key, slug text not null);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
generate: {importExtension: '.ts'},
};
sql/list-posts.sql
select id, slug from posts;
output
sql/.generated/index.ts
export * from "./tables.ts";
export * from "./list-posts.sql.ts";
sql/.generated/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
definitions.sql
create table posts (id integer primary key, slug text not null);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
};
tsconfig.json
{"compilerOptions": {"allowImportingTsExtensions": true}}
sql/list-posts.sql
select id, slug from posts;
output
sql/.generated/index.ts
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
definitions.sql
create table posts (id integer primary key, slug text not null);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
generate: {importExtension: '.js'},
};
tsconfig.json
{"compilerOptions": {"allowImportingTsExtensions": true}}
sql/list-posts.sql
select id, slug from posts;
output
sql/.generated/index.ts
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
definitions.sql
create table profiles (id integer primary key, name text not null);
create table orders (id integer primary key, total integer not null);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
};
sql/users/list-profiles.sql
select id, name from profiles;
sql/orders/list-orders.sql
select id, total from orders;
output
sql/.generated/index.ts
export * from "./tables.js";
export * from "./orders/list-orders.sql.js";
export * from "./users/list-profiles.sql.js";
sql/.generated/users/list-profiles.sql.ts
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;
};
}
sql/.generated/orders/list-orders.sql.ts
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
definitions.sql
create table posts (id integer primary key, slug text not null);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
};
sql/drop-posts.sql
drop table posts;
sql/alter-posts-add-title.sql
alter table posts add column title text;
sql/enable-foreign-keys.sql
pragma foreign_keys = on;
sql/reset-posts.sql
drop table if exists posts;
create table posts (id integer primary key, slug text not null);
sql/commented-create.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);
output
sql/.generated/drop-posts.sql.ts
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 },
);
sql/.generated/alter-posts-add-title.sql.ts
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 },
);
sql/.generated/enable-foreign-keys.sql.ts
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 },
);
sql/.generated/reset-posts.sql.ts
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 },
);
sql/.generated/commented-create.sql.ts
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 },
);
.sqlfu/query-catalog.json
{
"queries": []
}

writes a runtime query catalog with json schema for forms

Section titled “writes a runtime query catalog with json schema for forms”
input
definitions.sql
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'))
);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
};
sql/find-posts.sql
select id, slug, title, is_published, status
from posts
where status = :status and is_published = :is_published
limit 10;
output
.sqlfu/query-catalog.json
{
"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
definitions.sql
create table posts (id integer primary key, slug text not null);
sqlfu.config.ts
export default {
db: './app.db',
migrations: './migrations',
definitions: './definitions.sql',
queries: './sql',
};
sql/broken.sql
select nope from missing_table;
output
.sqlfu/query-catalog.json
{
"queries": [
{
"kind": "error",
"id": "broken",
"sqlFile": "sql/broken.sql",
"functionName": "broken",
"error": {
"name": "Invalid sql"
}
}
]
}