release: v0.4.2 — 生产就绪与崩溃自愈 + 问题清单修复 + 版本迭代
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
# MetonaSqlark
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/version-0.4.1-blue?style=flat-square" alt="version">
|
||||
<img src="https://img.shields.io/badge/version-0.4.2-blue?style=flat-square" alt="version">
|
||||
<img src="https://img.shields.io/badge/license-MIT-green?style=flat-square" alt="license">
|
||||
<img src="https://img.shields.io/badge/coverage-81.5%25-brightgreen?style=flat-square" alt="coverage">
|
||||
<img src="https://img.shields.io/badge/tests-894%20passed-success?style=flat-square" alt="tests">
|
||||
<img src="https://img.shields.io/badge/coverage-84.2%25-brightgreen?style=flat-square" alt="coverage">
|
||||
<img src="https://img.shields.io/badge/tests-944%20passed-success?style=flat-square" alt="tests">
|
||||
</p>
|
||||
|
||||
> 基于 TypeScript 的**前端关系型数据库**,支持完整 SQL 查询、Query Builder 链式 API、与 **AriaEngine 自研页面式存储引擎**。
|
||||
@@ -14,19 +14,21 @@
|
||||
## ✨ 特性
|
||||
|
||||
- 🚀 **AriaEngine 自研存储引擎** — LSM-Tree 页面式存储,4KB Slotted Page、WAL 崩溃恢复(full 模式真正同步)、LZ4 压缩
|
||||
- 💾 **OPFS 自研存储后端** — 纯浏览器文件系统,零 IndexedDB 依赖,二进制页面文件
|
||||
- 🔒 **生产级数据安全** — WAL CRC 完整性校验、`RESTRICT` 外键约束、Hybrid 提交原子性、SQL 注入防护
|
||||
- 💾 **OPFS 自研存储后端** — 纯浏览器文件系统,零 IndexedDB 依赖,二进制页面文件,schema 持久化(空表/索引跨重启完整保留)
|
||||
- 🔒 **生产级数据安全** — WAL 原子写入 + CRC 完整性校验、`RESTRICT` 外键约束、崩溃恢复自愈(`repair()` 无需删库重建)、SQL 注入防护
|
||||
- 🛡 **输入校验全覆盖** — `maxLength`/`min`/`max` 约束、类型检查、必填验证
|
||||
- 💾 **多引擎架构** — Memory / IndexedDB / OPFS / Hybrid(write-through) / Aria 五种模式
|
||||
- 📝 **完整 SQL 支持** — SELECT/JOIN/子查询/GROUP BY/HAVING/ORDER BY/LIMIT/BETWEEN/IF NOT EXISTS/ALTER TABLE/TRUNCATE TABLE/UNION/INSERT...SELECT/事务语句/CREATE INDEX/EXISTS(v0.3.0)+ CASE WHEN/哈希连接/组提交(v0.3.1)+ 多标签页同步(v0.3.2)
|
||||
- 🚰 **流式查询** — `queryStream`/`stream()` 逐行回调,Aria LSM 惰性扫描不物化结果集(v0.4.1)
|
||||
- 🧩 **派生表** — `FROM (SELECT ...)` 子查询作为行源,多列 ON 哈希连接,COUNT(DISTINCT),NULLS FIRST/LAST(v0.4.1)
|
||||
- 🚰 **流式查询** — `queryStream`/`stream()` 逐行回调,Aria LSM 惰性扫描不物化结果集(v0.4.0)
|
||||
- 🧩 **派生表** — `FROM (SELECT ...)` 子查询作为行源,多列 ON 哈希连接,COUNT(DISTINCT),NULLS FIRST/LAST(v0.4.0)
|
||||
- 🔗 **Query Builder API** — 链式 `.select().where().orderBy().limit().execute()`
|
||||
- 🔄 **事务回滚** — Memory/IndexedDB/Hybrid/Aria 四引擎事务原子性,自动回滚,MVCC 版本链接入读写路径
|
||||
- 🔗 **外键级联** — ON DELETE + ON UPDATE(CASCADE / SET NULL / RESTRICT)全引擎支持,支持更新主键(v0.4.2)
|
||||
- 🛡 **崩溃恢复自愈** — 残缺 SSTable 打开自动跳过、`db.repair()` 自愈、`db.clearAll()` 重置、迁移版本持久化(v0.4.2)
|
||||
- 🌲 **RB-Tree 完整实现** — 标准红黑树插入+删除修复,O(log n) 保证
|
||||
- ⚡ **性能优化** — SSTableReader 二分查找统一、IndexedDB 索引利用、crypto 实例化避免全局状态
|
||||
- 🌐 **浏览器兼容** — Chrome 80+ / Firefox 80+ / Safari 14+ / Edge 80+ / Node.js 16+
|
||||
- 🧪 **894 测试 · 81.5% 覆盖率** — 47 套件,生产级质量保证
|
||||
- 🧪 **944 测试 · 84.2% 覆盖率** — 50 套件,生产级质量保证
|
||||
|
||||
---
|
||||
|
||||
@@ -167,17 +169,24 @@ const hasOrders = await db.query('SELECT * FROM users u WHERE EXISTS (SELECT 1 F
|
||||
const labeled = await db.query("SELECT name, CASE WHEN age >= 18 THEN 'adult' ELSE 'minor' END AS status FROM users");
|
||||
const joinExists = await db.query('SELECT u.name FROM users u JOIN orders o ON u.id = o.user_id WHERE EXISTS (SELECT 1 FROM orders o2 WHERE o2.user_id = u.id AND o2.amount > 150)');
|
||||
|
||||
// v0.4.1 — 流式查询(大表逐行回调,不物化全部结果)
|
||||
// v0.4.0 — 流式查询(大表逐行回调,不物化全部结果)
|
||||
let count = 0;
|
||||
await db.queryStream('SELECT * FROM logs WHERE level = \'error\'', (row) => {
|
||||
count++;
|
||||
processRow(row);
|
||||
});
|
||||
// v0.4.1 — 派生表 / 多列哈希连接 / COUNT(DISTINCT) / NULLS 排序
|
||||
// v0.4.0 — 派生表 / 多列哈希连接 / COUNT(DISTINCT) / NULLS 排序
|
||||
const top = await db.query('SELECT dept, total FROM (SELECT dept, SUM(salary) AS total FROM emp GROUP BY dept) AS t WHERE total > 100 ORDER BY total DESC');
|
||||
await db.query('SELECT COUNT(DISTINCT city) AS n FROM users');
|
||||
await db.query('SELECT name FROM users ORDER BY age ASC NULLS FIRST');
|
||||
|
||||
// v0.4.2 — 崩溃恢复自愈(无需删库重建)
|
||||
await db.repair(); // 校验清理损坏数据,恢复一致性
|
||||
await db.clearAll(); // 清空全部数据与表结构(保留库本身)
|
||||
// v0.4.2 — 迁移版本持久化(重启后从持久化版本继续,不重跑不跳跑)
|
||||
db.addMigration(1, async (d) => { /* ... */ });
|
||||
await db.migrateTo(1);
|
||||
|
||||
// 事务 — 自动回滚 v0.1.13
|
||||
await db.transaction(async (trx) => {
|
||||
await trx.table('users').insert({ id: '3', name: 'Charlie' });
|
||||
@@ -218,8 +227,8 @@ await db2.disconnect(); // 引用计数 -1
|
||||
| `index` | `boolean` | 创建哈希索引 |
|
||||
| `default` | `unknown` | 默认值 |
|
||||
| `references` | `string` | 外键引用 `'table.column'` |
|
||||
| `onDelete` | `'CASCADE'\|'SET NULL'\|'RESTRICT'` | 删除级联 🆕 |
|
||||
| `onUpdate` | `'CASCADE'\|'SET NULL'\|'RESTRICT'` | 更新级联 🆕 |
|
||||
| `onDelete` | `'CASCADE'\|'SET NULL'\|'RESTRICT'` | 删除级联 ✅ v0.4.1 |
|
||||
| `onUpdate` | `'CASCADE'\|'SET NULL'\|'RESTRICT'` | 更新级联(更新主键时触发)✅ v0.4.2 |
|
||||
|
||||
### WHERE 操作符
|
||||
|
||||
@@ -239,9 +248,11 @@ await db2.disconnect(); // 引用计数 -1
|
||||
| `db.table(name)` | 获取表操作对象 |
|
||||
| `db.defineTable(name, cols)` | 定义表结构 |
|
||||
| `db.transaction(fn)` | 执行事务(自动回滚)🆕 |
|
||||
| `db.repair()` | 崩溃恢复自愈:校验清理损坏数据、恢复索引一致性(无需删库重建)🆕 v0.4.2 |
|
||||
| `db.clearAll()` | 清空全部数据与表结构(保留库本身,实例可继续使用)🆕 v0.4.2 |
|
||||
| `db.exportTable(name)` / `db.exportAll()` | 导出数据 JSON |
|
||||
| `db.importTable(name, data)` | 导入数据 |
|
||||
| `db.addMigration(v, fn)` / `db.migrateTo(v)` | 数据迁移 |
|
||||
| `db.addMigration(v, fn)` / `db.migrateTo(v)` | 数据迁移(版本持久化到库内,重启不重跑)🆕 v0.4.2 |
|
||||
| `db.subscribe(table, fn)` | 订阅表变更 |
|
||||
| `db.on(hook, fn)` | 注册钩子 (14 种) |
|
||||
|
||||
@@ -272,14 +283,14 @@ const { data, loading, refresh } = useSqlarkQuery(db, 'SELECT * FROM users');
|
||||
|
||||
| 特性 | Memory | Disk (IndexedDB) | Disk (OPFS) | Hybrid | Aria |
|
||||
|------|--------|------------------|-------------|--------|------|
|
||||
| **持久化** | ❌ 重启丢失 | ✅ IndexedDB | ✅ OPFS文件系统 | ✅ 内存+磁盘 | ✅ 后端决定 |
|
||||
| **持久化** | ❌ 重启丢失 | ✅ IndexedDB | ✅ OPFS(schema 持久化) | ✅ 内存+磁盘 | ✅ 后端决定 |
|
||||
| **事务回滚** | ✅ 快照 | ✅ 原子flush | ✅ 快照 | ✅ 双引擎 | ✅ MVCC |
|
||||
| **二级索引** | ✅ Hash | ✅ Hash | ✅ Hash | ✅ Hash | ✅ LSM |
|
||||
| **二级索引** | ✅ Hash | ✅ Hash | ✅ Hash(重启恢复) | ✅ Hash | ✅ LSM(重启恢复) |
|
||||
| **查询性能** | ⚡ O(1) PK | 🟡 O(1) PK | 🟡 O(1) PK | ⚡ O(1) PK | ⚡ O(log n) |
|
||||
| **数据上限** | 内存限制 | ~2GB(IDB限制) | ~磁盘可用 | ~2GB(IDB) | 内存限制 |
|
||||
| **数据上限** | 内存限制 | ~2GB(IDB限制) | ~磁盘可用(整表重写,≤1000行/表为宜) | ~2GB(IDB) | 内存限制 |
|
||||
| **浏览器** | 全部 | 全部 | Chrome/Edge 102+ | 全部 | 全部 |
|
||||
| **适用场景** | 缓存/测试 | 标准持久化 | Chromium专有 | 速度+持久化 | 大规模/分析 |
|
||||
| **测试覆盖** | 30+ | 30+ | 12 | 15+ | 200+ |
|
||||
| **测试覆盖** | 30+ | 30+ | 15 | 15+ | 200+ |
|
||||
|
||||
### Memory 模式
|
||||
- **环境**: 所有浏览器、Node.js
|
||||
@@ -296,7 +307,7 @@ const { data, loading, refresh } = useSqlarkQuery(db, 'SELECT * FROM users');
|
||||
### Disk (OPFS) 模式
|
||||
- **环境**: **仅限** Chrome 102+ / Edge 102+(Origin Private File System)
|
||||
- **限制**: Firefox/Safari 不支持 OPFS API;每次写入重写整表 JSON 文件(大表性能差,不建议 >1000 行)
|
||||
- **能力**: 完整 CRUD、重启自动加载数据、事务回滚
|
||||
- **能力**: 完整 CRUD、重启自动加载数据(空表/索引/schema 完整保留,v0.4.2)、事务回滚、并发写安全(内存快照一致)
|
||||
- **适用**: Chromium 独占场景、小数据集持久化
|
||||
|
||||
### Hybrid 模式
|
||||
@@ -308,7 +319,7 @@ const { data, loading, refresh } = useSqlarkQuery(db, 'SELECT * FROM users');
|
||||
### Aria 模式
|
||||
- **环境**: 所有浏览器(后端可选 IndexedDB / OPFS / Memory)
|
||||
- **限制**: Memory 后端重启丢失;IndexedDB 后端受配额限制;OPFS 后端仅 Chromium
|
||||
- **能力**: LSM-Tree 存储引擎、二级索引、MVCC 事务、WAL 崩溃恢复、Bloom Filter、AES-GCM 加密、Savepoint、EXPLAIN、ANALYZE、REINDEX、VACUUM
|
||||
- **能力**: LSM-Tree 存储引擎、二级索引(跨重启恢复)、MVCC 事务、WAL 原子写入崩溃恢复(残缺 SSTable 打开自动跳过)、ON UPDATE/DELETE 外键级联、Bloom Filter、AES-GCM 加密、Savepoint、EXPLAIN、ANALYZE、REINDEX、VACUUM、`repair()` 自愈
|
||||
- **适用**: 大规模数据分析、需要自研引擎可控性的高级场景
|
||||
|
||||
---
|
||||
@@ -358,12 +369,13 @@ const rows = await db.query('SELECT * FROM users');
|
||||
|
||||
| 特性 | 说明 |
|
||||
|------|------|
|
||||
| **LSM-Tree** | MemTable (红黑树) → SSTable 多级索引,异步 Compaction,写背压 |
|
||||
| **WAL** | Write-Ahead Log 二进制格式,CRC 校验,full/batch/none 三种模式(full 模式真正同步 ✅ v0.2.5),16MB 阈值自动 checkpoint |
|
||||
| **MVCC** | 版本链 + 快照隔离,事务读写不互斥,自动 GC(每10次检查点),读写路径接入版本链 ✅ v0.2.5 |
|
||||
| **LSM-Tree** | MemTable (红黑树) → SSTable 多级索引,异步 Compaction(从存储兜底加载,不依赖缓存),写背压 |
|
||||
| **WAL** | Write-Ahead Log 二进制格式,CRC 校验,记录与计数单事务原子写入,full/batch/none 三种模式(full 模式真正同步 ✅ v0.2.5),16MB 阈值自动 checkpoint(活跃事务期间不截断 ✅ v0.4.2) |
|
||||
| **崩溃恢复** | 打开时完整性校验(残缺 SSTable 自动跳过并清理)、WAL 按 key 扫描恢复(不丢记录)、恢复后自动重建二级索引 ✅ v0.4.2 |
|
||||
| **MVCC** | 版本链 + 快照隔离,事务读写不互斥,提交/回滚按事务写入 key 精准清理,自动 GC |
|
||||
| **Buffer Pool** | SSTable 缓存 LRU 上限(`bufferPoolPages` × `pageSize`,默认 256 页 ≈ 1MB 可控内存)✅ v0.2.6 生效,查询前异步预加载兜底,缓存驱逐不丢数据 |
|
||||
| **Bloom Filter** | FNV-1a + Murmur 双哈希,SSTable footer 序列化,查询时 probe |
|
||||
| **二级索引** | 每列独立 LSM Tree,支持 $eq/$in/$gt/$lt 范围扫描,SSTableReader 二分查找统一 ✅ v0.2.5 |
|
||||
| **二级索引** | 每列独立 LSM Tree,支持 $eq/$in/$gt/$lt 范围扫描,跨重启自动恢复,WAL 恢复后自动重建 ✅ v0.4.2 |
|
||||
| **AES-GCM** | PBKDF2 密钥派生 + AES-256-GCM 页面级加密,CryptoManager 实例化 ✅ v0.2.5 |
|
||||
| **Compaction** | 异步 Leveled Compaction,Level 0 > 8 触发同步背压,compactLevel public 接口 ✅ v0.2.5 |
|
||||
| **OPFS Backend** | 纯浏览器文件系统,Promise 队列串行写,零外部依赖 |
|
||||
@@ -387,9 +399,9 @@ npm run typecheck # 类型检查
|
||||
|
||||
| 指标 | 数值 |
|
||||
|------|------|
|
||||
| 测试用例 | 894 |
|
||||
| 测试套件 | 47 |
|
||||
| 行覆盖率 | 81.5% |
|
||||
| 测试用例 | 944 |
|
||||
| 测试套件 | 51 |
|
||||
| 行覆盖率 | 84.2% |
|
||||
| SQL 关键字 | 36 |
|
||||
| 存储引擎 | 5(Memory / IndexedDB / OPFS / Hybrid / **Aria**) |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user