类型脚本的框DB
一个由 BoxDB Rust 核心支持的同步节点.js 和 Bun SQLite 客户端. 每个连接都拥有一名本地工人: SQL 执行和锁定等待离开 JavaScript事件循环自由. 二进制 SQLite 文件, 可读的 YAML 存储, 扩展 列类型和内置的 SQL 扩展使用相同的核心.
安装
npm install @boxdb/client
要求 macOS ARM64 (macOS 11+) 或 Linux x64 或 ARM64 上的节点 js 22.18+ 或 Bun 与 glibc 2.35+ (Ubuntu 22.04+或64位Raspberry Pi OS Booktrom+). 所有3个本地添加物被捆绑在npm包中; 安装不需要 Rust 编译器, 安装脚本或额外下载 . Alpine/ musl, Windows, Intel macOS 和 32-bit ARM 不支持这个 npm 释放。 此客户端不运行在浏览器中 .
从源头构建
需要节点.js 22.18+, Bun, Rust, 土建工具和 libclang; 见 仓库读取器从寄存器根 :
bun install --frozen-lockfile
bun run build
bun run check
bun run test
just ts-build 财务报告和审定财务报表 just ts-check ts-test 还构建和验证所有软件包.
对于最优化的加登,运行 bun run --cwd packages/typescript build:release, (中文(简体) ),
然后构建适配软件包。 构建针对当前操作系统和架构;
npm 释放建筑在 发布指南。 。 。 .
查询
查询行是 unknown[]。在使用图书库前验证这些图书
作为 佐德语Name数字 :
npm install zod
import { BoxDB, Changeset } from "@boxdb/client";
import { z } from "zod";
const User = z.object({ id: z.bigint(), name: z.string() });
await using db = await BoxDB.open("data.db", { busyTimeoutMs: 5000 });
await db.exec("CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY, name TEXT)");
const inserted = await db.query`INSERT INTO users(name) VALUES(${"Ada"})`.run();
const rows = User.array().parse(
await db.query`
SELECT * FROM ${db.identifier("users")}
${db.fragment`WHERE id = ${inserted.lastInsertRowid}`}
LIMIT ${100}
`,
); // { id: bigint; name: string }[] after runtime validation
Scalar 插值成为绑定参数; 不要将 SQL 引号绕行
他们. identifier("main", "users") 引用单独的组件;
identifier("user.name") 引用一个包含点的名称。 碎片快照
参数和不执行 SQL 的作曲.
查询执行一次,懒惰. await query 财务报告和审定财务报表 query.execute({ signal })
返回行对象为 unknown[]。 。 。 . query.get({ signal }) 返回第一行
或者说 undefined键入为 unknown。 。 。 . query.values({ signal }) 返回位置
行为 unknown[],保留重复的列名。 验证每项结果
对照查询选定的形状. query.run({ signal }) 返回时
{ changes, lastInsertRowid } ,需要不返回列的语句.
这些方法共享执行结果
或出错;第一个执行选择其信号. query.compile() 返回 a
存档副本 { sql, parameters } 不执行.
对于适配器或迁移工具的 SQL :
const result = await db.execute("SELECT name FROM users WHERE id=:id", { id: 1 });
// { rows, columns, changes, lastInsertRowid }
const names = User.pick({ name: true }).array().parse(result.rows);
const positional = await db.execute("SELECT 1 AS x, 2 AS x", [], { raw: true });
await db.exec("CREATE INDEX IF NOT EXISTS users_name ON users(name);");
execute 接受一个语句、位置或名称绑定和返回
rows: unknown[] 在对象和原始模式中. exec 接受没有
参数。 查询不接受结果类型参数;从
验证数据。 客户端不依赖验证库. 明确
准备的报表和流程不属于这个API.
交易和注销
使用类型脚本 5.2+; 转接 await using 没有本地语法的运行时间
支持(包括Node.js 22).
await using tx = await db.begin({ mode: "immediate", signal });
await tx.query`INSERT INTO users(name) VALUES(${"Grace"})`;
{
await using nested = await tx.begin();
await nested.query`INSERT INTO users(name) VALUES(${"temporary"})`;
// Exiting without commit rolls back this savepoint.
}
await tx.commit();
承诺是明确的。 处置和 rollback() 放弃未完成的工作。 根号
交易使用情况 immediate 默认,在交易前获取写入器
工作开始。 明确 deferred 财务报告和审定财务报表 exclusive 模式仍然可用.
使用 db.begin({ readOnly: true }) 拒绝 SQL 的延迟交易
写入 BOXDB_READONLY在二进制 WAL 数据库中,它可以读取一致
当另一个连接写入时快照 。 本地警卫负责调查
脚本,包括试图禁用 query_only; 上一个连接
设置在交易后恢复。 只读连接自动
开始只读交易。 将只读与直接或独家
模式抛出 TypeError。 。 。 .
await using tx = await db.begin({ readOnly: true });
const total = z.object({ count: z.bigint() }).parse(
await tx.query`SELECT count(*) AS count FROM users`.get(),
);
await tx.commit();
嵌入式交易使用保存点并继承外部只读限制
和最后期限。 它们没有独立的模式。 使用最内部的交易
处理交易内的工作; 父手处理 SQL 在嵌入时失败
handle 拥有连接。 根请求,包括 db.begin(),等待着
整个交易要完成。 Root SQL 然后在自动承诺中独立执行,
以提交令为准。 SQL 交易控制语句也必须使用手柄.
交易有5秒的寿命,默认从 BEGIN
成功 。 设定 transactionTimeoutMs 在客户端上,或者用 timeoutMs
打开 db.begin();两者均接受从1到2147483647毫秒的整数.
保存点继承了外部截止时间,而不予以延长. 过期中断
运行 SQL,取消队列交易工作并滚回。 等待根
清理后才能恢复请求
过期处理失败 BOXDB_TRANSACTION_TIMEOUT。 。 。 .
await using db = await BoxDB.open(":memory:", { transactionTimeoutMs: 10_000 });
await using tx = await db.begin({ timeoutMs: 2_000 });
const pending = db.query`SELECT 1 AS answer`.execute();
await tx.commit();
await pending; // Executes outside the completed transaction.
在完成您自己的交易之前等待根请求 等待到它
时出后出. 使用 tx 用于实施或退缩前所需的行动.
截止日期开始取消; 释放连接仍然需要本地
SQL中断并回滚完成.
tx.active 报告其交易是否存在。 失败的承诺叶
用于修复或重试的活跃 SQLite 交易。 如果 SQLite 本身
中断后将交易卷回, 通过这个手柄做进一步的工作
失败, 而不是自动承诺 .
const controller = new AbortController();
const pending = db.query`SELECT * FROM users`.execute({ signal: controller.signal });
controller.abort(new Error("request no longer needed"));
await pending; // Rejects with the cancellation reason if cancellation wins.
执行前信号取消队列请求并中断运行 SQL 或 锁等. 交易继承其信号; 也中止闲置交易 卷回已来. 这个信号不能取消回滚清理。 取消 无法撤消已执行的语句; 使用交易进行原子化 多说活.
close() 拒绝新的根请求, 排出已接受的工作并等待活动
交易要完成。 他们的手柄仍然可以犯规或退缩.
close({ mode: "abort" }) 取消待定和正在运行的工作, 滚动活动
交易和等待清理。 现有排水口可以升级
以中止. await using db 做一个排水关闭.
改变历史
交易可以记录其行变化并运行承诺触发器;见 改变历史 为SQL侧.
await using tx = await db.begin({ context: { label: "Rename task" } });
await tx.query`UPDATE tasks SET title = ${"New title"} WHERE id = ${3n}`;
await tx.commit(); // A BEFORE COMMIT trigger can store boxdb_changeset().
const row = z.object({ changes: z.instanceof(Changeset) }).parse(
await db.query`SELECT changes FROM history ORDER BY id DESC LIMIT 1`.get(),
);
const report = await db.apply(row.changes, { invert: true }); // Undo in its own transaction.
begin({ context }) 存储可读值通过 boxdb_context(key) 页:1
交易的寿命; begin({ record: true }) 记录更改如此
tx.changeset() 返回 a Changeset 或者说 null 承诺之前. tx.apply()
应用交易中的更改列表 db.apply() 在一个新的即时
交易; 两者都接受 invert 财务报告和审定财务报表 onConflict (单位:千美元)abort, (中文(简体) ), skip 或者说
replace返回时 { applied, skipped, conflicts }变化的一栏
返回时 Changeset 实例,它们也作为参数约束; changeset.bytes
持有编码的更改器.
备选办法、价值和诊断
BoxDB.open(path, options) 接受 format: "binary" | "readable", (中文(简体) ),
readOnly, (中文(简体) ), busyTimeoutMs, (中文(简体) ), transactionTimeoutMs, (中文(简体) ), maxPendingQueries,以及 signal。 。 。 .
现有内容决定格式。 只读可读连接读取
一个开口的快照 不拿作家的锁.
接受输入 null,字符串,有限数字,大写,布尔和 Uint8Array。 。 。 .
Bigint参数接受综合INT64/UINT64范围(-2^63 结束
2^64 - 1; 高于INT64 MAX的正值绑定为UINT64. 使用
CAST(? AS UINT8/16/32) 以选择更窄的无符号宽度.
安全整数和布尔作为整数绑定;分数绑定为
真实的。 明确排列对象 。 每个签名或未签名的整数单元格,写
计数和行 ID 返回为比宽; REAL 仍然是数字。 转换大写
明确在JSON的序列化时。 不安全的整数输入抛出而不是四舍五入 .
结果保留原生小数值为正文. DECIMAL 算术,比较
并命令在引擎中运行; NUMERIC 不支持。 UUID 和时间值
返回条形字符串:INSTANT使用UTC,TIME没有日期或时区,
DATETIME没有时区和时区
字符串保存微秒精度。 JSON和数组仍然不透明;
SQL JSON 处理被禁用. 集团是 Buffer 数值。 见
本地小数向导 财务报告和审定财务报表
时间类型。 。 。 .
BoxDBError 保留 code, (中文(简体) ), resultCode, (中文(简体) ), extendedCode 财务报告和审定财务报表 cause发动机
失败了 BOXDB_* 名称,例如 BOXDB_CONSTRAINT_UNIQUE审定,
封闭式连接和本土基础设施故障有不同的类别;
已用尽队列使用 BOXDB_QUEUE_FULL。 。 。 . findBoxDBError(error) 以下原因
和成员总数,而不循环循环。 丢弃无效的参数
TypeError 或者说 RangeError见 客户端出错合同。 。 。 .
可选的队列限制限制等待操作,包括root请求
等待交易; 清理总是通过.
db.diagnostics 报告待处理/正在/完成的操作和最后排队
等待和处决时间以毫秒为单位。 整个期限
定期操作,包括准备和本土处决.
文件诊断和康复
对现有文件使用 await BoxDB.checkFile(path, "full"), (中文(简体) ),
await BoxDB.repairFile(source, destination) 或者说
await BoxDB.recoverFile(source, destination, "binary") 独立生活
客户端。 报告区分无效数据与不完整的检查. 恢复可以
即使输出通过验证, 数据也会丢失; 见
诊断和康复。 。 。 .
SQL 迁移
import { MigrationSet } from "@boxdb/client";
const migrations = await MigrationSet.read("db/migrations");
await migrations.up(db);
使用 MigrationSet.fromFiles([{ filename, sql }]) 在应用程序中捆绑 SQL.
同一套曝光 status(db) 财务报告和审定财务报表 down(db); 执行方法接受
{ signal }。这些方法使用 CLI 的格式和历史,在
本地工人,并等待根客户端的积极交易. 见
移徙来源、取消和回滚。 。 。 .
一体化
适配器是独立的npm软件包,其库作为同级依赖. 他们借用客户而不关闭:
- 滴滴适配器: 同步查询、交易、, 批量和迁移.
- 更好的 Auth 适配器: 直接数据库适配器, 生化和原生原子证书/相机操作.
- db0 适配器: 接受数据库的 SQLite 连接器 或交易处理.
每个连接包括小数计算、 Unicode 文本函数, 正则 表达式, sqlite-vec, FTS5 和 R*Tree; 见 SQL 扩展指南。虚拟表格需要内存 或二进制存储.