实时数据
实时数据
这就是租户应用接触数据的方式。读取是 实时查询 ,写入是 乐观更新 ,两者都通过 $bolt/client ——你永远不需要打开连接、管理缓存或使任何东西失效。Bolt 的 同步引擎 让每个客户端保持最新;本页是该约定面向编写者的一半。
读取是实时查询
每次读取都是一个 实时查询 ,在服务器注册,并按操作主体的策略由服务器求值。使用 client.db.<collection>.findMany 、 findFirst 或 count 。带连续 limit 的 findMany 与 findFirst 是在 sync.connect 上登记的实时前缀。count、findGrouped、带 after 游标的分页以及语义搜索都是一次性读取,不会登记为实时。浏览器只在内存中保留当前答案。提交改变某个实时前缀的依赖项时,宿主推进该前缀,流上发送带版本栅栏的按键增量——或一次迫使浏览器重新注册的重置。
import { client } from '$bolt/client';
const orders = client.db.orders.findMany({
where: { status: { eq: 'open' } },
with: { customer: true },
orderBy: { created_at: 'desc' }
});
// Mounted once, registered with the server, then updated by SSE apply frames. 首次挂载时,客户端发送一次 sync.connect 握手 ,登记每个实时前缀,并返回当前行以及宿主将要归档的计划。重连会重新登记这些前缀;错过一次唤醒会关闭流。没有 changelog 可供重放,也没有已持有 id 的摘要。
写入是乐观更新
浏览器写入使用 client.collection.<collection>.create(input) 。它返回持久性为 memory 的乐观结果与结算句柄。Machine 通过 HTTP 推出幂等图,权威端则经同步通道报告结果。 client.collection.<collection>.pending 计数入队操作仍在进行的写入;权威状态属于每个返回的结算句柄。
client.collection.cost_estimates.update(id, input)
input = the declared columns + explicit relation actions
│ enqueue in this tab's memory
▼
optimistic row projects over held in-memory query answers
│ collections.write push with idempotency key
▼
server: refuse anything outside the selection → policy → transform →
approval route → commit the root + every nested action
│ → history + SyncChange capture (one transaction)
▼
host advances registered live prefixes for changed collections
│ one ordered SSE apply frame
▼
keyed deltas or resets + authoritative write settlement
(accepted | rebased | rejected | quarantined)
> 输入就是集合声明的选择:它的列,以及每个关联之下它接受的显式操作——`create`、`update`、`upsert`、`link`、`unlink`、`delete`。省略的关联或空数组什么都不做;任何东西都不会因省略而被删除。create 不携带 id——由服务器分配。根记录与每个嵌套操作原子提交。
生成的类型会精确描述该嵌套图,无需类型断言或兼容包装。查询拥有 current、loading 和 error;变更拥有 pending。组件不复制查询数据、刷新、加载、错误或变更状态。
import { client } from '$bolt/client';
const write = await client.collection.cost_estimates.update(id, {
status: 'submitted',
line_items: {
create: [{ description: 'Scaffolding', amount: 1200 }],
update: [{ id: lineId, set: { amount: 950 } }],
delete: [{ id: staleId }]
}
});
// Relation actions are explicit. An omitted relation or an empty array does
// nothing; nothing is ever deleted by omission. The root and every nested
// action commit atomically.
write.row; // optimistic projection; durability is this tab's memory
await write.settlement.settled; // authoritative outcome arrives through sync 写入返回乐观行,而非持久的服务器记录。只写与行过滤策略可能允许写入,却不允许相应读取,因此已注册实时查询仍是已授权当前数据的来源。结算句柄会报告 accepted、rebased、rejected 或 quarantined;被路由到审批的写入会在挂起标记下临时提交,并以待审批结算。
不变量
以服务器为权威的答案是唯一已提交事实。 浏览器只在内存中保留已挂载答案,并且只应用带版本栅栏的按键增量;应用代码中没有任何 invalidate 、 refetch 或 revalidate 。