Files
Genarrative/.codex/skills/genarrative-admin-backoffice/references/admin-database-table-query-2026-05-08.md
T
kdletters 071faa482c 统一 Rust 与 TypeScript 格式化门禁
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
2026-09-01 16:28:34 +08:00

2.8 KiB
Raw Blame History

本次后台表查询接入的可复用经验

需求落点

  • 后台“总览”页的表统计仍保留,只把每张表的表名改成可点击跳转到 #tables?table=<name>
  • 新增独立 #tables 页承载表选择、关键词搜索、结构化字段筛选、limit、行详情弹窗(详情内保留字段复制,列头漏斗按钮可按列添加条件;每条条件可勾选启用或停用,停用时保留字段和值;in / notIn 使用逐项值标签,支持粘贴多行值,逗号不再作为隐式分隔符)。

后端实现要点

  • 新增只读接口:
    • GET /admin/api/database/tables
    • GET /admin/api/database/tables/{table_name}/rows
  • 表名必须来自 schema 白名单;再加一层 identifier 校验,避免任意 SQL 表名注入。
  • limit 必须 clamp;本次实现使用默认 100、最大 500。
  • search / filters 不进入 SQL 字符串:
    • SQL 只负责 SELECT * FROM {table_name} LIMIT {limit}
    • 返回后在 api-server 内存中过滤
    • filters 接受两种 JSON 形式:object(列名到等值,如 {"user_id":"u1"})与条件数组(如 [{"column":"points","op":"gt","value":"5"}],运算符含 eqnegtgteltltecontainsnotContainsstartsWithendsWithinnotInisEmptyisNotEmpty,允许同列多条件,条件间为 AND);非 object 且非数组直接 400,未知运算符或 value 形态不匹配也 400。数组中的 eq / ne 和其他标量运算符一样必须提供 value;显式空值判断使用 isEmpty / isNotEmpty
  • SpacetimeDB HTTP SQL 返回可能是 statement array + rows,解析时要兼容这一层结构。

前端实现要点

  • adminRoutes 必须新增 tablesAdminShell.routeIcons 也要同步覆盖。
  • AdminApp 需要显式渲染 AdminDatabaseTablesPage
  • 预览表格数据行直接点击(或行自身聚焦后按 Enter / Space)打开详情,行内按钮 / 输入控件的键盘操作不冒泡打开详情;详情按钮不单独占列。详情字段仅提供复制操作,成功、剪贴板失败和空字段复制都使用右下角自动消失的 Toast,JSON 预览与平台亮色 / 暗色主题保持一致,表头保持单行并在空间不足时省略显示。表单和标题区查询按钮共用筛选完整性校验。
  • worktree 下可能没有本地 node_modules/typescript/bin/tsc,而根目录有依赖;在验证前可以临时把根目录 node_modules 软链到 worktree 再执行 npm run admin-web:typecheck,验证后删除软链,避免污染 git 状态。

验证结果

  • cargo test -p api-server admin_database -- --nocapture 通过。
  • cargo fmt --manifest-path Cargo.toml -p api-server -p shared-contracts --check 通过。
  • npm run admin-web:typecheck 通过。
  • npm run admin-web:build 通过。
  • npm run check:encoding 通过。