Convex 表历史组件
注:本构成部分目前为BETA。 其前身为 convex-table-history。 。 。 .
Convex桌上的历史
在您的 Convex 表格中附加历史组件以跟踪变化.
- 查看 Convex Dashboard 或自定义反应组件中所有表格变化的审计日志.
- 回答“文件A在文件B之前更新了吗?”
- 查看单个文档中更改的审计日志
- 回答诸如"在用户更改电子邮件地址之前,是哪个地址?"等问题
- 随时看桌子的快照.
// Paginate through all history on the "documents" table, from newest to oldest.
documentAuditLog.listHistory(ctx, args.maxTs, args.paginationOpts);
// Paginate through all history for a specific document, from newest to oldest.
documentAuditLog.listDocumentHistory(ctx, args.documentId, args.maxTs, args.paginationOpts);
// Paginate through all documents in the "documents" table at a specific timestamp.
documentAuditLog.listSnapshot(ctx, args.snapshotTs, args.currentTs, args.paginationOpts);
找到窃听器了吗? 特质请求? 放在这。 。 。 .
预先要求: Convex
你需要一个现有的 Convex 项目来使用组件. Convex是一个主机后端平台,包括数据库,无服务器功能, 还要多学一吨 这里。 。 。 .
运行 npm create convex 或遵循其中任何一条 快速启动 来设置一个.
安装
安装组件包 :
npm install @convex-dev/table-history
创建一个 convex.config.ts 应用程序中的文件 convex/ 通过调用文件夹并安装组件 use数字 :
// convex/convex.config.ts
import { defineApp } from "convex/server";
import tableHistory from "@convex-dev/table-history/convex.config";
const app = defineApp();
app.use(tableHistory, { name: "documentAuditLog" });
export default app;
要将历史添加到多个表格中, 您可以调用 app.use 多次时间
不同名称。 将在您的应用中提供
new TableHistory(components.<name>, ...)。 。 。 .
使用量
import { components } from "./_generated/api";
import { TableHistory } from "@convex-dev/table-history";
const documentAuditLog = new TableHistory<DataModel, "documents">(components.documentAuditLog);
当文档更改时, 在历史表中添加一个项目 :
async function patchDocument(ctx: MutationCtx, documentId: Id<"documents">, patch: Partial<Doc<"documents">>) {
await ctx.db.patch(documentId, patch);
const document = await ctx.db.get(documentId);
await documentAuditLog.update(ctx, documentId, document);
}
async function insertDocument(ctx: MutationCtx, documentId: Id<"documents">, newDoc: WithoutSystemFields<Doc<"documents">>) {
const documentId = await ctx.db.insert("documents", newDoc);
const document = await ctx.db.get(documentId);
await documentAuditLog.update(ctx, documentId, document);
}
async function deleteDocument(ctx: MutationCtx, documentId: Id<"documents">) {
await ctx.db.delete(documentId);
await documentAuditLog.update(ctx, documentId, null);
}
或者附加一个 触发 当突变更改文档时, 自动写入历史表 :
const triggers = new Triggers<DataModel>();
triggers.register("documents", documentAuditLog.trigger());
export const mutation = customMutation(rawMutation, customCtx(triggers.wrapDB));
现在,你写到历史表, 你可以使用 listHistory, (中文(简体) ), listDocumentHistory,以及 listSnapshot 函数来查询历史.
这些功能是被分解的,所以您可以用 usePaginatedQuery 以渐进方式获得所有条目.
这些网页包括: HistoryEntry 对象,其字段如下:
id: 已更改文件的编号doc: 已修改的文档新版本, 如果删除则无效ts:变化的时间戳. 见 可序列性。 。 。 .isDeleted: 文档是否被删除attribution: 将随历史条目一起存储的可选任意对象
更多实例使用 实例.ts。 。 。 .
使用详情
序列
Convex变异是可序列交易,对维护非常有益 表格中的一致性.
但是,如果你需要保证 历史时间戳匹配突变' 序列式的顺序,这需要序列化您的全部更改 数据库,您的数据库会缓慢到爬行并获得OCC错误.
您可以通过设置历史表格的序列
serializability 选项。 三种选择是:
"table"- 即表格的最新t,加1- 历史条目与同一表格上的其他更新可序列化
"document"- 即文档的最新 ts, 加上 1- 历史条目与同一文档上的其他更新可序列化.
"wallclock"- 即日期,现在()- 历史的入门时间戳没有保障 但也不需要额外 依赖性通常足够.
默认可序列性是 "wallclock"。 。 。 .
currentTs 财务报告和审定财务报表 maxTs 需求
const [currentTs] = useState(Date.now()); // stable and recent
const [yesterday] = useState(Date.now() - 24 * 60 * 60 * 1000); // stable
const snapshotOfUsersYesterday = usePaginatedQuery(
api.documents.listSnapshot,
{
currentTs,
snapshotTs: yesterday,
},
{ initialNumItems: 100 },
);
const auditLogBeforeYesterday = usePaginatedQuery(
api.documents.listHistory,
{
maxTs: yesterday,
},
{ initialNumItems: 100 },
);
- 对于
listSnapshot, (中文(简体) ),currentTs应该是一个稳定的最近的时间戳.- "平稳"表示其对所有页面应具有同值.
- 为了保持所有页面的稳定时间戳,在客户端上选择一个值并
把它当作是
usePaginatedQuery。 。 。 .
- 为了保持所有页面的稳定时间戳,在客户端上选择一个值并
把它当作是
- “最近”是相对于表格获得新插入的次数。 数额
查询完成的额外工作与数量成正比
ctx.db.insert(tableName, doc)自从..currentTs。 。 。 .- 如果时间戳不是最近,查询可能会读取过多的数据 单页并显示出错.
- 以后别挑时间戳,否则会出现相隔
如插入了新文档。 时间戳应该是
Date.now()或者说 略入过去.
- "平稳"表示其对所有页面应具有同值.
- 对于
listHistory财务报告和审定财务报表listDocumentHistory, (中文(简体) ),maxTs应该是稳定的,但 没必要是最近.
为什么有必要?
表历史部分支持以
usePaginatedQuery
财务报告和审定财务报表 手动标记。 。 。 .
但它需要你的帮助 使一切正常运转.
你想这样
完全反应式平面。 。 。 .
具体地说, usePaginatedQuery 结果不应有差距或重复.
为了执行这个功能,没有内置 .paginate 方法,
tableHistory 组件假定它自己的数据模型仅为附件(即
真实的,但真空时除外),并在最近稳定的时标中取入. 接下来
忽略在时间戳后创建的历史条目.
归属
存储更新 attribution 以跟踪用户生成的信息
改变,或者是什么突变导致的改变.
await documentAuditLog.update(ctx, documentId, document, {
attribution: {
actorIdentity: await ctx.auth.getUserIdentity(),
mutationName: "patchDocument",
source: "web",
},
});
使用时的默认属性 TableHistory.update 实值 null。 。 。 .
使用时的默认属性 TableHistory.trigger 是变异的
ctx.auth.getUserIdentity()。 。 。 .
真空
历史表可以变大,所以你可以使用 vacuumHistory 函数
删除旧历史条目。 此函数将
调度背景任务删除旧历史条目.
将删除的条目为不可见的条目
在快照时 >=minTsToKeep。 。 。 .
在吸尘后 minTsToKeep,你不能再打电话 listSnapshot
带有快照时间戳的小于 minTsToKeep。 。 。 .
限制
- 没有索引:您不能使用索引来改变排序顺序或获得一个子集的结果.
- 工作间:你可以一直工作到
isDone返回真,并排序或过滤器 无论是在客户身上还是在行动中. 考虑 手动标记。 。 。 .
- 工作间:你可以一直工作到