查询写法
默认实时查询
业务接口使用 ctx.db。认证、组织权限、积分、订阅以及写入后的立即读取不能选 dbCached。缓存只在产品明确允许短期旧数据时使用。
按当前用户隔离
ts
const runs = await ctx.db.query.toolRun.findMany({
where: (run, { eq }) => eq(run.userId, ctx.user.id),
orderBy: (run, { desc }) => [desc(run.createdAt)],
limit: 20,
});示例需要私有接口提供有效 ctx.user。读取和更新都带身份条件,不能先仅按记录 ID 查出敏感数据,再依靠前端隐藏。
组织权限
活动组织 ID 只代表当前范围。对组织资源查询成员表,同时匹配组织和当前用户;管理操作再检查 owner 或 admin。成员移除后旧会话不能继续拥有原权限。
列表与性能
明确排序和数量上限,返回所需列即可。大量数据使用稳定分页字段;避免循环逐条查询形成多次数据库往返。索引应与实际过滤和排序匹配,通过查询计划检查后再添加。
事务与唯一约束
积分余额更新、流水插入和保存结果需要按业务语义形成事务。唯一事件键防止并发或重试重复发放;非负余额约束防止越界扣款。网络响应丢失不代表服务端没执行,不能无条件重试非幂等操作。
测试
验证跨用户读取、跨组织写入、并发重复事件、余额不足和事务失败回滚。使用真实数据库约束测试这些边界,避免仅模拟查询函数返回值。