Commit Graph
5 Commits
Author SHA1 Message Date
thzxx 4ab04df882 fix(A15): 三值逻辑求值器统一 —— 消除 WHERE 的第二套语义(静默错值根治)
背景(PLAN-v0.7.5.md 根因 1/7、缺陷 A15):
项目里 `matchWhere`(布尔版,自带 matchField)与三值求值器并存。同一条 SQL 的
语义取决于走哪个函数,实测三类静默错值:
  - `WHERE n = NULL` 命中 NULL 行、`WHERE n != NULL` 返回所有非 NULL 行;
  - `WHERE s NOT LIKE 'x'` 会把 NULL 行判真(布尔取反);
  - `WHERE n NOT BETWEEN 1 AND 2` 恒空集 —— parser 生成的字段级
    `{ n: { $or: [ {$lt:1}, {$gt:2} ] } }` 递归进了 where 子句级求值器,
    子项 `{ $lt: 1 }` 被当成"查询列 `$lt`" → 每行 UNKNOWN。

根治方式(不是打补丁,而是取消第二套实现):
1. where-matcher.ts 重写为**唯一一个递归求值器**,同时理解 where 子句级
   (键是列名/逻辑连接词)与操作符级(键是 `$gt` …),位置由上下文承载而非
   由另一个函数承载;`matchWhere` 退化为"三值结果是否恰为 TRUE"。
   行上下文随求值上下文下传,`$col` 在任意嵌套深度都能解析。
2. parser:`IS NULL` / `IS NOT NULL` 生成 `$isNull` / `$isNotNull` **谓词**
   (此前与 `= NULL` / `!= NULL` 共用 `$eq: null` / `$ne: null`,两者语义无法区分);
   `BETWEEN` 生成真正的范围条件(此前把同一对象同时当操作符对象与操作数);
   `NOT BETWEEN` 展开为 `$or: [{$lt}, {$gt}]`。
3. executor 新增 enginePreFilter:逐行求值谓词(`$col` / `$exists` / CASE 键)
   必须整体移出引擎层 —— 引擎无外层行上下文,会把它们判 UNKNOWN 并把**所有行**
   过滤掉,逐行求值再正确也无行可算。粒度按连接词决定:`$and` 成员可单独移除,
   `$or`/`$not` 成员一移除就改变结果集(漏行/多行),故整条下推放弃。

契约变更(旧测试编码了错误语义,已按 SQL 标准改正并注明理由):
  - a) `{ $eq: null }` 不再命中 NULL 行(`= NULL` 恒 UNKNOWN)→ 用 `$isNull`;
  - b) `IN` 列表含 NULL:`x IN (NULL, 'a')` 只命中 'a'(`null = NULL` 为 UNKNOWN),
       未命中的行仍因 UNKNOWN 不保留。
  - c) 引擎层 `$in: [null, ...]` 与 `$eq: null` 的断言同步修正。

验证:
  - 新增 tests/v080-sql-three-valued.test.ts:26 条 SQL 语义矩阵 × 4 引擎
    (memory/disk/hybrid/aria)+ UPDATE/DELETE 写路径,共 104 断言;
  - 全量 83 套件 / 1458 测试通过(含 Aria 生产负载 10 万行);
  - typecheck(src+tests) 与 lint 零错误。
2026-09-14 23:22:26 +08:00
thzxx 7526951804 fix(A19/A20/A21/A2): 词法器标准化 —— 双引号标识符、未闭合注释报错、去递归、移除方言转义
A19 双引号是分隔标识符(SQL 标准)
  此前 '"' 与 "'" 一起交给 readString,于是 SELECT "name" FROM t 静默产出
  一个名为 'name' 的**常量列**(行数正确、值全错、无报错),且被 lexer.test.ts
  钉死为期望。新增 TokenType.QUOTED_IDENTIFIER;双引号内 "" 表示一个双引号;
  可用于引用保留字列名(SELECT "order" FROM t)。parser 的 expectIdentifier
  显式接受 QUOTED_IDENTIFIER。

A20 未闭合块注释必须报错
  此前 skipBlockComment 循环到 EOF 就返回、不抛错,实测
  db.query("DELETE FROM t WHERE id = '4' /*") **真的删掉了 1 行**;
  SQLite 会报 unterminated comment。任何被截断/拼接的 SQL 都会静默改变语义。

A21 注释跳过改为循环(消除递归爆栈)
  此前 default 分支用 return this.nextToken() 递归,栈深 = 连续注释数,
  两万个连续块注释直接 RangeError(原生错误,调用方无法按 code 分类)。

A2 移除 MySQL 方言的反斜杠转义
  此前只识别反斜杠+单引号:双反斜杠不解转义,以反斜杠结尾的 Windows 路径会
  吞掉闭引号并报出与输入无关的解析错误。更严重的是参数绑定器只翻倍单引号、
  不处理反斜杠 —— 两份词法规则不一致,"参数不改变 SQL 结构"在文本层不成立。
  SQL 标准中反斜杠是普通字符,移除后词法器与绑定器的字符串边界判定完全一致。

更新 2 处把旧行为钉死的测试(lexer.test 双引号=字符串、v033 反斜杠转义)。
2026-09-14 21:08:20 +08:00
thzxx 0dba1abf2a test(P0): v0.8.0 验证基座与工程门禁根治
工作流 C-1 / C-3 前半 + 测试代码类型检查。

【故障注入基座】新增 tests/helpers/storage-harness.ts + faulty-backend.ts
- TransactionalFileStore:忠实 OPFS 提交语义(close 才可见)+ 字节级故障注入
  (failNextWrite/Append/Delete、truncateAppendTo 撕裂写、crashPending 真崩溃)
- 删除旧 opfs-mock:读返回内部引用、keepExistingData:false 不截断、close 空实现
  导致"提交前可见"等真实缺陷无法被测出(31 个测试文件迁移至新 harness)
- 删除 aria-opfs-backend 内的第三份重复 mock(含从未被断言使用的 writeCalls 死代码
  与 entry.content.subarray 恒等分支)
- FaultyBackend:包装任意 IStorageBackend 注入故障;crash() 明确区别于 close()
  (后者是优雅停机,会刷完写队列 —— 这正是此前所有"崩溃恢复"测试的真相)
- 16 条基座自测证明注入真的生效(含 close 不能当崩溃的对照组)

【覆盖率口径】jest.config.cjs
- 移除 '!src/**/index.ts'(该 glob 把 AriaEngine 主实现等 15 个实现文件整体
  排除出统计,与 v0.2.6 曾承认过的问题同源),改为只排除纯类型声明文件并附理由
- 新增 coverageThreshold 门禁(此前完全不存在)
- 真实基线:语句 90.66% / 分支 82.94% / 函数 94.36% / 行 93.43%
- 修正 testMatch 使 tests/helpers 下的测试可被发现

【测试代码类型检查】tsconfig.test.json + npm run typecheck:tests
- 修复 103 个测试代码类型错误(此前 babel 剥离类型 + tsconfig 排除 tests,全部隐藏)
- 新增 tests/helpers/assertions.ts:nonNull/decode/rows/object/engineMethod/expectCode
  以断言收窄替代 as any
- 消除 21 个 lint warning(含 v043-hardening 中定义后从未调用的 mockOPFS 死代码)
- parser.test.ts 12 处 toBeDefined() 空断言升级为结构断言(并新增 AND/OR 优先级用例,
  当前红灯,对应总账第 11 项,将在工作流 A 修复)

【版本契约】新增 tests/version-contract.test.ts
- 校验 src VERSION / package.json / dist 三者一致,替代两处硬编码版本字面量

【CI 门禁】.gitea/workflows/ci.yml
- lint 去掉 continue-on-error(此前永远不让 CI 变红)
- 新增 tests 类型检查、--coverage 覆盖率门禁、dist 与源码同步校验
- 版本 0.7.4 升至 0.8.0
2026-09-14 21:03:06 +08:00
thzxx 1f8e11bf72 feat: SQL 语法支持 BETWEEN AND、DROP TABLE IF EXISTS
CI / test (18.x) (push) Successful in 9m56s
CI / test (20.x) (push) Successful in 9m54s
CI / test (22.x) (push) Successful in 9m50s
CI / test (24.x) (push) Successful in 9m49s
2026-07-26 17:55:45 +08:00
thzxx e2a590c5b1 feat: metona-sqlark v0.1.12 — 前端TypeScript关系型数据库
- 4种存储引擎:Memory / IndexedDB / OPFS / Hybrid
- 完整SQL支持:SELECT/INSERT/UPDATE/DELETE/JOIN/GROUP BY/HAVING/DISTINCT
- Query Builder链式API + TypeScript泛型支持
- 聚合函数:COUNT/SUM/AVG/MIN/MAX
- 事务、插件系统(14 hooks)、发布订阅、数据迁移、导入导出
- React/Vue框架集成
- 264个测试用例,93.46%覆盖率
- 零运行时依赖
2026-07-26 15:00:01 +08:00