Add design spec for SQL CRUD practice feature

Lets students select a preset teaching table, write SQL against it,
and see the resulting table state via the existing Judge0 pipeline.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 23:34:24 -06:00
parent d798d56dbe
commit c9eb5fa12f

View File

@@ -0,0 +1,74 @@
# SQL 增删改查练习功能 设计文档
日期2026-07-04
## 背景与目标
老师需要在现有在线代码编辑器codenext中考察学生的 SQL 增删改查CRUD能力。功能不是自动判题/评分系统,而是一个"候选数据表 + SQL 执行 + 结果展示"的沙箱:学生从几张预设的教学表中选一张,写 SQL 语句,执行后看到该表的最终状态,由老师人工判断学生写得对不对。
## 范围
- 仅涉及 `codenext/`(前端)。`codeapinew/`后端不需要任何改动——SQL 执行复用现有的 Judge0 直连链路,与 C/C++ 的执行方式一致。
- 不做自动判题/评分、不做前后对比高亮、不做多语句持久会话。这些是明确排除的非目标(见"已排除的方案")。
## 架构与执行流程
将 SQL 作为一门新语言接入现有语言体系(与 python / c / cpp / turtle 同级),复用 `api.ts` 中现有的 Judge0 提交链路。
每次点击"运行"时:
1. 学生已从候选表下拉框选定一张表(如 `students`)。
2. 学生在编辑器中只写自己的 SQL`DELETE FROM students WHERE score < 60;`)。
3. 前端拼接完整脚本:`<该候选表的建表+初始数据 SQL>` + `\n` + `<学生的 SQL>` + `\n` + `SELECT * FROM <该表名>;`(自动追加)。
4. 整体脚本作为 source`language_id = 82`Judge0 的 SQLite提交执行。
5. 每次提交都是全新的临时 SQLite 数据库,因此天然满足"每次都从预设初始数据重新执行"的要求,不需要任何服务端状态管理。
6. Judge0 返回的 stdout即自动追加的那条 `SELECT *` 的结果)作为执行结果展示。
**统一处理原则**:无论学生写的是 INSERT / UPDATE / DELETE 还是 SELECT都统一在脚本末尾追加一次针对该候选表的 `SELECT * FROM 表名;` 来展示表的最终状态。这样处理逻辑不需要按语句类型分支。如果学生自己写的也是 SELECT输出里会同时包含学生查询的结果和追加查询的表状态两者都展示不做去重。
## 候选数据表内容
新增配置文件 `codenext/src/data/sqlTables.ts`(格式参考现有 `templates.ts`),包含 3 张独立的单表教学数据:
1. **`students`(学生成绩表)**`id, name, class, score`8 条示例数据,分数、班级有区分度,适合 WHERE / UPDATE / DELETE 练习。
2. **`employees`(员工工资表)**`id, name, department, salary, hire_date`8 条示例数据,适合按部门分组、调整工资、按日期筛选。
3. **`products`(商品库存表)**`id, name, category, price, stock`8 条示例数据适合新增商品INSERT、调整库存UPDATE、下架缺货商品DELETE
每张表都是独立单表,不带外键关联,保持题目简单易懂。每条配置包含:`{ id, label, description, tableName, setupSql, previewRows }`
## UI 改动
沿用"每种语言一套专属布局"的现有模式Turtle 已是先例):
- **`SelectLanguage.vue`**:语言列表新增 `["sql", "SQL"]`
- **`CodeEditor.vue`**`language === "sql"` 时引入 `@codemirror/lang-sql`(新依赖)做语法高亮,替换现有 python()/cpp() 的判断分支。
- **`Content.vue`**:新增分支 `v-else-if="code.language === 'sql'"`,渲染新组件 `SqlSection.vue`,替代原有的 Input/Output 分栏SQL 场景不需要 stdin
**`SqlSection.vue` 内部结构**
1. 顶部:候选表下拉选择器。
2. 表结构 + 初始数据只读预览(帮助学生了解字段和数据,避免瞎猜)。
3. 中间:复用现有 `CodeSection`(学生写 SQL 的编辑器,本身不需要改动)。
4. 底部:结果区,复用现有 `OutputSection`(纯文本展示 Judge0 返回的 stdout不做高亮/diff保持简单。
**其他必改点**(沿用现有语言接入的固定套路):
- `types.ts``LANGUAGE` 联合类型新增 `"sql"`
- `templates.ts``languageToId` 新增 `sql: 82`
- `composables/code.ts``cache.code` 及分享链接(`?share=`)白名单加入 `sql`
- 新增 `composables/sqlTable.ts`:管理"当前选中的候选表"这一状态(选中的表 id随语言切换重置为默认表
后端 `codeapinew` 不需要任何改动。
## 已排除的方案(非目标)
- **不做自动判题/评分**:没有"标准答案"比对,考察由老师人工完成。
- **不做持久会话/状态累积**:每次运行都基于预设初始数据重新执行,不支持像真实数据库会话那样跨多次提交累积状态(若未来需要,需引入客户端 SQLite WASM如 sql.js这是一次单独的架构变更
- **不做前后对比高亮**:只展示执行后的最终表状态文本,不做逐行 diff 或颜色标注。
## 风险与待确认事项
- **需要确认自建 Judge0 实例是否已启用 `language_id = 82`SQLite**。这一点无法从代码层面确认,需要访问该 Judge0 实例的 `/languages` 接口核实;若未启用,需要找 Judge0 管理员开启对应语言镜像后此功能才能工作。
## 测试计划
- 手动验证:针对三张候选表分别执行 INSERT / UPDATE / DELETE / SELECT确认输出符合预期。
- 回归验证:语言切换、分享链接(`?share=`、localStorage 缓存机制在新增 `sql` 语言后对其他既有语言python/c/cpp/turtle无影响。