@bob-kit/client
Official Bob client for JavaScript/TypeScriptOfficial Bob client for consuming the bob DSL from JavaScript/TypeScript.
This package loads Bob's runtime (WASM) and exposes a small API to:
This package loads Bob's runtime (WASM) and exposes a small API to:
- Transpile your bob input into SQL for a given engine (SQLite, MariaDB/MySQL, PostgreSQL).
- Automatically execute the generated SQL using a Driver you provide.
- Optionally cache transpilation results.
Bob is a lightweight, declarative transpiler that lets you define database schemas and queries using a simple, human-readable DSL called bob.
Bob then converts those definitions into SQL for multiple engines such as SQLite, MariaDB/MySQL, and PostgreSQL.
Instead of writing verbose SQL by hand, you describe tables, relationships, and queries concisely, and Bob generates the corresponding SQL.
Bob then converts those definitions into SQL for multiple engines such as SQLite, MariaDB/MySQL, and PostgreSQL.
Instead of writing verbose SQL by hand, you describe tables, relationships, and queries concisely, and Bob generates the corresponding SQL.
Installation
pnpm
pnpm add @bob-kit/client
npm
npm i @bob-kit/client
yarn
yarn add @bob-kit/client
Environment Requirements
Right now, @bob-kit/client loads the WASM using Node APIs (fs, vm).
That means it's currently Node.js-oriented (not browser) as implemented today.
That means it's currently Node.js-oriented (not browser) as implemented today.
Concepts: Driver and Cache
The client needs a Driver (from @bob-kit/types) to execute the generated SQL:
- driver: target engine ("sqlite" | "mariadb" | "mysql" | "postgres").
- querier(query, ...params): async function that executes SQL (and returns rows for SELECT).
- cache: optional implementation to cache transpilation results (memory, redis, etc.).
This package also exports a ready-to-use in-memory cache: MemoryCache.
Optional Drivers
Drivers are optional packages that you can install separately from the Bob ecosystem. They provide ready-to-use querier implementations for different database engines.
- @bob-kit/sqlite: Official SQLite driver. Install with pnpm add @bob-kit/sqlite, npm i @bob-kit/sqlite, or yarn add @bob-kit/sqlite.
- PostgreSQL, MariaDB, and MySQL: Official drivers are pending but coming soon. In the meantime, you're free to create your own driver libraries as long as they respect the querier contract required by Bob.
Custom Drivers: You can implement your own driver by creating a function that matches the querier interface: (query: string, ...params: any[]) => Promise<any[]>. This allows you to integrate Bob with any database or ORM that supports parameterized queries.
Quick Start (Node + SQLite)
Complete example using @bob-kit/sqlite as the querier:
import bob from "@bob-kit/client";
import { MemoryCache } from "@bob-kit/client/cache";
import { sqlite } from "@bob-kit/sqlite";
const querier = sqlite(":memory:");
const client = bob({
driver: "sqlite",
querier,
cache: new MemoryCache(),
});
// 1) Define multiple tables in a single query
await client.query`
table Profile {
id id
avatar string
}
table Users {
id id
name string
lastName string
Profile
}
`;
// 2) Insert one entity
await client.query`
new Profile {
avatar "bear"
}
`;
// 3) Bulk insert with multiple rows and columns
await client.query`
new Users name lastName Profile.id {
"John" "Doe" 1
"Mary" "Jane" 3
"Robert" "Smith" 3
}
`;
// 4) Create reusable query functions with types
const getUserByName = (name: string) => client.query`
get Users {
name
profile_id
-> Profile {
avatar
}
desc Profile.id
}
`;
const users = await getUserByName("John"); Advanced Examples
Joins and Relationships
Join with related table:
const usersWithProfiles = await client.query`
get Users {
id
name
lastName
-> Profile {
avatar
}
}
`; Filtering and Sorting
Filter and sort your queries:
const filteredUsers = await client.query`
get Users {
id
name
if name = "John" || "Mary"
}
`;
const sortedUsers = await client.query`
get Users {
id
name
desc id
}
`; Parameters
The API accepts parameters as arguments to query(...). Internally, the template literal is converted to a string using ? as the placeholder.
const userEmail = "ada@lovelace.dev"
const byEmail = await client.query`
get Users {
id
name
email
if email == ${userEmail}
}
`; API Reference
default export function bob(driver: Driver)
Creates a client instance.
Returns an object with:
Returns an object with:
- query<A>(input, ...params): Promise<A[]>: executes a bob input. You can destructure it for convenience: const { query: b } = bob(...).
- cache(id)(input, ...params): Promise<A[]>: same as query, but caches the transpilation result under a fixed id.
- factory.<id>(input, ...params): Promise<A[]>: shortcut for cache("<id>")(...).
bobQuery({ driver, input, id? })
Low-level function that only performs transpilation (and applies cache if present). You usually won't need it.
Driver Interface
The Driver interface (from @bob-kit/types) defines the contract that all drivers must implement:
- driver: string indicating the target engine ("sqlite" | "mariadb" | "mysql" | "postgres").
- querier(query: string, ...params: any[]): Promise<any[]>: async function that executes SQL queries. For SELECT queries, it should return an array of rows. For other queries (INSERT, UPDATE, DELETE), it can return an empty array or the result of the operation.
- cache: optional cache implementation to store transpilation results (can be MemoryCache, Redis, or any custom implementation).
Note: Drivers are optional packages that you can install separately. The official @bob-kit/sqlite driver is available now, while PostgreSQL, MariaDB, and MySQL drivers are pending. You can create your own driver libraries as long as they respect this interface contract.
@bob-kit/client/cache
Includes:
- [object Object]
Errors
When Bob returns a parsing/validation/transpilation error, the client throws BobError with:
- name a value from BobErrors (from @bob-kit/types/errors)
- message error details
Important Notes
- Multiple actions: if your input generates more than 1 SQL action, the client throws (MultipleActions). The current flow assumes 0 or 1 action per execution.
- Table execution: if the output includes tables, all of them are executed (in order) before the action/query.