release: v0.3.2 — 质量加固 + SQL扩展 + 表达式 + 并发同步
v0.2.6 质量加固: - 修复 AriaEngine 二级索引 SSTable 互相覆盖(命名空间隔离) - 修复 LSM 多版本读取顺序错误 + MergeIterator 取最新来源 - 重写 LZ4 压缩器(往返一致性 + 缓冲区溢出) - sstableCache LRU 上限 + 预加载兜底(BufferPool 配置生效) - 修复 React/Vue 集成 import type 运行时 bug + exports 子路径 - 新增 38 个测试(LZ4往返/Crypto/集成), 删除伪测试 v0.3.0 SQL 功能扩展: - 多语句 parseAll + 事务语句 BEGIN/COMMIT/ROLLBACK - INSERT INTO ... SELECT + UNION/UNION ALL + EXISTS 关联子查询 - CREATE/DROP INDEX 五引擎实现 + 别名 WHERE 修复 - benchmark 页面 + 36 个新测试 v0.3.1 表达式与性能: - CASE WHEN 表达式(SELECT 列/WHERE/聚合) - JOIN + 关联子查询逐行绑定 - WAL 批量组提交(写放大 O(N)→O(1)) - 修复 pending frozen 可见性 + flush 缓存竞争 v0.3.2 并发: - CASE WHEN 用于 WHERE/聚合 + JOIN 哈希连接 - 多标签页同步(multiTabSync + BroadcastChannel) - IndexedDB schema 持久化(reopen 后表结构恢复) - 修复 where-matcher 顶层 $not - 修复 CJS 产物 .js 被 ESM 解析(exports 空) — .cjs 后缀 + exports 修正 - 836 测试 / 44 套件 / 81.0% 覆盖率
This commit is contained in:
+2056
-591
File diff suppressed because it is too large
Load Diff
Vendored
-1
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+152
-7
@@ -62,6 +62,8 @@ interface DatabaseConfig {
|
||||
maxRowsPerQuery?: number;
|
||||
/** 调试模式(启用后输出详细操作日志) */
|
||||
debug?: boolean;
|
||||
/** 多标签页同步(v0.3.2):BroadcastChannel 广播表变更,其他标签页自动刷新 */
|
||||
multiTabSync?: boolean;
|
||||
}
|
||||
/** Where 条件操作符 */
|
||||
type WhereOperator = '$eq' | '$ne' | '$gt' | '$gte' | '$lt' | '$lte' | '$in' | '$nin' | '$like' | '$and' | '$or' | '$not';
|
||||
@@ -114,7 +116,7 @@ interface MetonaPlugin {
|
||||
/** 销毁 */
|
||||
destroy(): void;
|
||||
}
|
||||
declare const VERSION = "0.2.5";
|
||||
declare const VERSION = "0.3.2";
|
||||
|
||||
/**
|
||||
* metona-sqlark Plugin — 插件系统
|
||||
@@ -179,6 +181,10 @@ interface IStorageEngine {
|
||||
count(tableName: string, query?: QueryPlan): Promise<number>;
|
||||
/** 清空表数据(保留结构) */
|
||||
clear(tableName: string): Promise<void>;
|
||||
/** 创建二级索引(CREATE INDEX) */
|
||||
createIndex?(tableName: string, column: string, unique?: boolean): Promise<void>;
|
||||
/** 删除二级索引(DROP INDEX) */
|
||||
dropIndex?(tableName: string, column: string, indexName?: string): Promise<void>;
|
||||
/** 开始事务 */
|
||||
beginTransaction(): Promise<void>;
|
||||
/** 提交事务 */
|
||||
@@ -254,7 +260,10 @@ interface InsertStatement {
|
||||
type: 'INSERT';
|
||||
into: string;
|
||||
columns?: string[];
|
||||
values: unknown[][];
|
||||
/** VALUES 字面量 */
|
||||
values?: unknown[][];
|
||||
/** INSERT INTO ... SELECT ...(v0.3.0) */
|
||||
select?: SelectStatement | SelectUnionStatement;
|
||||
}
|
||||
interface UpdateStatement {
|
||||
type: 'UPDATE';
|
||||
@@ -285,6 +294,15 @@ interface SelectStatement {
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
interface SelectUnionStatement {
|
||||
type: 'SELECT_UNION';
|
||||
/** 左操作数(可以是 SELECT 或嵌套 UNION) */
|
||||
left: SelectStatement | SelectUnionStatement;
|
||||
/** 右操作数 */
|
||||
right: SelectStatement | SelectUnionStatement;
|
||||
/** UNION ALL 不去重 */
|
||||
all?: boolean;
|
||||
}
|
||||
interface AlterTableStatement {
|
||||
type: 'ALTER_TABLE';
|
||||
name: string;
|
||||
@@ -295,7 +313,31 @@ interface TruncateTableStatement {
|
||||
type: 'TRUNCATE_TABLE';
|
||||
name: string;
|
||||
}
|
||||
type Statement = SelectStatement | ExplainStatement | InsertStatement | UpdateStatement | DeleteStatement | CreateTableStatement | DropTableStatement | AlterTableStatement | TruncateTableStatement;
|
||||
interface CreateIndexStatement {
|
||||
type: 'CREATE_INDEX';
|
||||
/** 索引名(语法占位) */
|
||||
name: string;
|
||||
table: string;
|
||||
column: string;
|
||||
/** UNIQUE 索引 */
|
||||
unique?: boolean;
|
||||
}
|
||||
interface DropIndexStatement {
|
||||
type: 'DROP_INDEX';
|
||||
name: string;
|
||||
table: string;
|
||||
column: string;
|
||||
}
|
||||
interface BeginTransactionStatement {
|
||||
type: 'BEGIN';
|
||||
}
|
||||
interface CommitTransactionStatement {
|
||||
type: 'COMMIT';
|
||||
}
|
||||
interface RollbackTransactionStatement {
|
||||
type: 'ROLLBACK';
|
||||
}
|
||||
type Statement = SelectStatement | SelectUnionStatement | ExplainStatement | InsertStatement | UpdateStatement | DeleteStatement | CreateTableStatement | DropTableStatement | AlterTableStatement | TruncateTableStatement | CreateIndexStatement | DropIndexStatement | BeginTransactionStatement | CommitTransactionStatement | RollbackTransactionStatement;
|
||||
|
||||
/**
|
||||
* metona-sqlark Query Executor — AST 执行器
|
||||
@@ -311,11 +353,23 @@ declare class QueryExecutor {
|
||||
/** 设置查询结果行数上限 */
|
||||
setMaxRowsPerQuery(max: number): void;
|
||||
execute(stmt: Statement): Promise<unknown>;
|
||||
/** 递归执行 UNION / UNION ALL,返回合并结果 */
|
||||
private executeSelectUnion;
|
||||
private executeSelectPart;
|
||||
/** 将 UNION 右侧行投影为左侧列结构(按位置取值) */
|
||||
private projectUnionRow;
|
||||
/** EXPLAIN: 输出查询计划 */
|
||||
private executeExplain;
|
||||
private executeSelect;
|
||||
private executeJoinSelect;
|
||||
private prefixRow;
|
||||
/**
|
||||
* 哈希连接(v0.3.2):ON 为单一等值条件且右表列为索引/主键时,
|
||||
* 收集左表连接值 → 一次 $in 查询右表 → 哈希映射匹配。
|
||||
* 替代嵌套循环,大表 INNER/LEFT JOIN 复杂度 O(N + M)。
|
||||
* 不适用时返回 null(回退嵌套循环)。
|
||||
*/
|
||||
private tryHashJoin;
|
||||
/** 嵌套循环连接(优化:避免 ON 时对象扩散) */
|
||||
private joinRows;
|
||||
private executeGroupBy;
|
||||
@@ -328,14 +382,47 @@ declare class QueryExecutor {
|
||||
private executeDropTable;
|
||||
private executeAlterTable;
|
||||
private executeTruncateTable;
|
||||
private executeCreateIndex;
|
||||
private executeDropIndex;
|
||||
private executeBegin;
|
||||
private executeCommit;
|
||||
private executeRollback;
|
||||
/** 列列表是否包含 CASE WHEN 表达式 */
|
||||
private hasCaseColumn;
|
||||
/** WHERE 是否包含 CASE WHEN 表达式键 */
|
||||
private whereHasCase;
|
||||
getEngine(): IStorageEngine;
|
||||
/**
|
||||
* 列投影(v0.3.1):普通列走 projectColumns,CASE WHEN 表达式逐行求值
|
||||
*/
|
||||
private projectRow;
|
||||
/** 检查 SELECT 列列表中是否包含聚合函数 */
|
||||
private _hasAggregateColumn;
|
||||
/** 计算单行聚合结果(无 GROUP BY) */
|
||||
private computeSingleAggregate;
|
||||
/** 剥离主表别名前缀:'u.id' → 'id'(键与 $col 值均处理,支持多层别名) */
|
||||
private normalizeWhereColumns;
|
||||
private normalizeExistsValue;
|
||||
private normalizeFieldValue;
|
||||
private stripAlias;
|
||||
/** WHERE 是否含关联引用($col 或关联 EXISTS)或 CASE WHEN 表达式键 */
|
||||
private hasCorrelatedRefs;
|
||||
private fieldHasColRef;
|
||||
/** 移除关联 EXISTS 标记(引擎层先执行无 EXISTS 条件的查询) */
|
||||
private stripCorrelatedExists;
|
||||
/** 逐行绑定外层行上下文,求值关联 EXISTS、$col 引用与 CASE WHEN 键 */
|
||||
private filterCorrelated;
|
||||
/** 将 WHERE 中的 CASE WHEN 表达式键求值为布尔条件($caseResult) */
|
||||
private resolveCaseKeys;
|
||||
/** CASE 求值结果与操作符条件比较 */
|
||||
private caseConditionMatches;
|
||||
/** 将 where 中的 $col 引用替换为上下文行值 */
|
||||
private bindColumnRefs;
|
||||
private bindWhereRefs;
|
||||
/**
|
||||
* 递归扫描 WHERE 条件,找到 $subquery 标记并执行子查询,
|
||||
* 将结果替换为具体值。
|
||||
* @param contextRow 关联子查询的外层行上下文(用于绑定 $col 引用)
|
||||
*/
|
||||
private resolveSubqueries;
|
||||
/**
|
||||
@@ -395,7 +482,8 @@ declare class UpdateQueryBuilder {
|
||||
private tableName;
|
||||
private _updates;
|
||||
private _where;
|
||||
constructor(engine: IStorageEngine, tableName: string, _updates: Record<string, unknown>);
|
||||
private onWrite?;
|
||||
constructor(engine: IStorageEngine, tableName: string, _updates: Record<string, unknown>, onWrite?: (table: string) => void);
|
||||
where(condition: WhereCondition): this;
|
||||
execute(): Promise<number>;
|
||||
toAST(): UpdateStatement;
|
||||
@@ -404,7 +492,8 @@ declare class DeleteQueryBuilder {
|
||||
private engine;
|
||||
private tableName;
|
||||
private _where;
|
||||
constructor(engine: IStorageEngine, tableName: string);
|
||||
private onWrite?;
|
||||
constructor(engine: IStorageEngine, tableName: string, onWrite?: (table: string) => void);
|
||||
where(condition: WhereCondition): this;
|
||||
execute(): Promise<number>;
|
||||
toAST(): DeleteStatement;
|
||||
@@ -420,7 +509,9 @@ declare class Table<T = Record<string, unknown>> {
|
||||
private engine;
|
||||
private schema;
|
||||
private executor;
|
||||
constructor(engine: IStorageEngine, tableName: string, executor?: QueryExecutor);
|
||||
/** 写入回调(多标签页广播,v0.3.2) */
|
||||
private onWrite?;
|
||||
constructor(engine: IStorageEngine, tableName: string, executor?: QueryExecutor, onWrite?: (table: string) => void);
|
||||
getSchema(): Promise<TableSchema>;
|
||||
insert(row: T & Record<string, unknown>): Promise<string>;
|
||||
insertMany(rows: (T & Record<string, unknown>)[]): Promise<string[]>;
|
||||
@@ -472,6 +563,8 @@ declare class MetonaSqlark {
|
||||
get maxRowsPerQuery(): number;
|
||||
/** 调试模式 */
|
||||
get debug(): boolean;
|
||||
/** 多标签页同步通道(v0.3.2) */
|
||||
private channel;
|
||||
constructor(config: DatabaseConfig);
|
||||
/** 初始化数据库(创建引擎、打开连接) */
|
||||
init(): Promise<void>;
|
||||
@@ -500,12 +593,18 @@ declare class MetonaSqlark {
|
||||
subscribe(tableName: string, callback: (event: {
|
||||
type: string;
|
||||
row?: unknown;
|
||||
table?: string;
|
||||
}) => void): () => void;
|
||||
/** 触发变更事件 */
|
||||
emit(tableName: string, event: {
|
||||
type: string;
|
||||
row?: unknown;
|
||||
table?: string;
|
||||
}): void;
|
||||
/** 广播表变更到其他标签页(多标签页同步) */
|
||||
broadcastChange(tableName: string): void;
|
||||
/** 写语句对应的表名(多标签页广播用) */
|
||||
private writeStatementTable;
|
||||
private migrations;
|
||||
/** 注册迁移 */
|
||||
addMigration(version: number, up: (db: MetonaSqlark) => Promise<void>): void;
|
||||
@@ -553,6 +652,8 @@ declare class MemoryEngine implements IStorageEngine {
|
||||
delete(tableName: string, query: QueryPlan): Promise<number>;
|
||||
count(tableName: string, query?: QueryPlan): Promise<number>;
|
||||
clear(tableName: string): Promise<void>;
|
||||
createIndex(tableName: string, column: string, unique?: boolean): Promise<void>;
|
||||
dropIndex(tableName: string, column: string, _indexName?: string): Promise<void>;
|
||||
beginTransaction(): Promise<void>;
|
||||
commitTransaction(): Promise<void>;
|
||||
rollbackTransaction(): Promise<void>;
|
||||
@@ -590,6 +691,12 @@ declare class IndexedDBEngine implements IStorageEngine {
|
||||
private memoryCache;
|
||||
private txActive;
|
||||
open(dbName: string, version: number): Promise<void>;
|
||||
/**
|
||||
* 从 IDB 恢复内存 schema:
|
||||
* 1. 优先读取持久化的 schema 记录('__metona_schema' store,v0.3.2)
|
||||
* 2. 旧数据回退:从 objectStore 主键 / 索引 / 样例数据推断
|
||||
*/
|
||||
private rebuildSchemaFromIDB;
|
||||
close(): Promise<void>;
|
||||
isOpen(): boolean;
|
||||
createTable(schema: TableSchema): Promise<void>;
|
||||
@@ -603,6 +710,8 @@ declare class IndexedDBEngine implements IStorageEngine {
|
||||
delete(tableName: string, query: QueryPlan): Promise<number>;
|
||||
count(tableName: string, query?: QueryPlan): Promise<number>;
|
||||
clear(tableName: string): Promise<void>;
|
||||
createIndex(tableName: string, column: string, unique?: boolean): Promise<void>;
|
||||
dropIndex(tableName: string, column: string, _indexName?: string): Promise<void>;
|
||||
beginTransaction(): Promise<void>;
|
||||
commitTransaction(): Promise<void>;
|
||||
rollbackTransaction(): Promise<void>;
|
||||
@@ -648,6 +757,8 @@ declare class OPFSEngine implements IStorageEngine {
|
||||
delete(tableName: string, query: QueryPlan): Promise<number>;
|
||||
count(tableName: string, query?: QueryPlan): Promise<number>;
|
||||
clear(tableName: string): Promise<void>;
|
||||
createIndex(tableName: string, column: string, unique?: boolean): Promise<void>;
|
||||
dropIndex(tableName: string, column: string, indexName?: string): Promise<void>;
|
||||
beginTransaction(): Promise<void>;
|
||||
commitTransaction(): Promise<void>;
|
||||
rollbackTransaction(): Promise<void>;
|
||||
@@ -727,6 +838,8 @@ declare class AriaEngine implements IStorageEngine {
|
||||
delete(tableName: string, query: QueryPlan): Promise<number>;
|
||||
count(tableName: string, query?: QueryPlan): Promise<number>;
|
||||
clear(tableName: string): Promise<void>;
|
||||
createIndex(tableName: string, column: string, unique?: boolean): Promise<void>;
|
||||
dropIndex(tableName: string, column: string, _indexName?: string): Promise<void>;
|
||||
beginTransaction(): Promise<void>;
|
||||
commitTransaction(): Promise<void>;
|
||||
rollbackTransaction(): Promise<void>;
|
||||
@@ -741,6 +854,14 @@ declare class AriaEngine implements IStorageEngine {
|
||||
private checkType;
|
||||
private persistSchemas;
|
||||
private loadSchemas;
|
||||
/**
|
||||
* 创建命名空间隔离的 SSTableStore。
|
||||
*
|
||||
* 主 LSM 与每个二级索引 LSM 各持有独立实例:
|
||||
* - 文件 key 前缀隔离(sst_ / sst_idx_${table}_${col}_)
|
||||
* - 元数据 key 隔离(__aria_lsm_meta / __aria_lsm_meta_${ns})
|
||||
* - id 序列独立(避免 v0.2.4 共享 id 空间导致的文件互相覆盖)
|
||||
*/
|
||||
private createSSTableStore;
|
||||
private applyWALRecord;
|
||||
/** 更新行的二级索引条目 */
|
||||
@@ -751,6 +872,8 @@ declare class AriaEngine implements IStorageEngine {
|
||||
private indexScanToRows;
|
||||
/** 每 10 次 gc 计数器触发一次 MVCC 垃圾回收 */
|
||||
private tryGC;
|
||||
/** 回收主 LSM 与所有二级索引 LSM 的临时缓存超限 */
|
||||
private trimAllCaches;
|
||||
/** 检查内存预算,超出时强制 flush + GC */
|
||||
private checkMemoryBudget;
|
||||
/** 估算 WAL 大小(字节) */
|
||||
@@ -801,8 +924,15 @@ declare class HybridEngine implements IStorageEngine {
|
||||
private memoryEngine;
|
||||
private diskEngine;
|
||||
private diskEngineType;
|
||||
private dbName;
|
||||
private version;
|
||||
constructor(diskEngine?: DiskEngine);
|
||||
open(dbName: string, version: number): Promise<void>;
|
||||
/**
|
||||
* 从磁盘重载内存缓存(v0.3.2:多标签页同步)。
|
||||
* 其他标签页写入磁盘后调用,使本标签页读到最新数据。
|
||||
*/
|
||||
reloadMemoryFromDisk(): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
isOpen(): boolean;
|
||||
createTable(schema: TableSchema): Promise<void>;
|
||||
@@ -816,6 +946,8 @@ declare class HybridEngine implements IStorageEngine {
|
||||
delete(tableName: string, query: QueryPlan): Promise<number>;
|
||||
count(tableName: string, query?: QueryPlan): Promise<number>;
|
||||
clear(tableName: string): Promise<void>;
|
||||
createIndex(tableName: string, column: string, unique?: boolean): Promise<void>;
|
||||
dropIndex(tableName: string, column: string, indexName?: string): Promise<void>;
|
||||
beginTransaction(): Promise<void>;
|
||||
commitTransaction(): Promise<void>;
|
||||
rollbackTransaction(): Promise<void>;
|
||||
@@ -835,6 +967,8 @@ declare class HybridEngine implements IStorageEngine {
|
||||
|
||||
/** 解析 SQL 字符串为 AST Statement */
|
||||
declare function parse(sql: string): Statement;
|
||||
/** 解析 SQL 字符串为 AST Statement 数组(分号分隔的多语句支持,v0.3.0) */
|
||||
declare function parseAll(sql: string): Statement[];
|
||||
|
||||
/**
|
||||
* metona-sqlark SQL Token Types — 词法单元定义
|
||||
@@ -895,6 +1029,17 @@ declare enum TokenType {
|
||||
MIN = "MIN",
|
||||
MAX = "MAX",
|
||||
DISTINCT = "DISTINCT",
|
||||
BEGIN = "BEGIN",
|
||||
COMMIT = "COMMIT",
|
||||
ROLLBACK = "ROLLBACK",
|
||||
UNION = "UNION",
|
||||
ALL = "ALL",
|
||||
INDEX = "INDEX",
|
||||
CASE = "CASE",
|
||||
WHEN = "WHEN",
|
||||
THEN = "THEN",
|
||||
ELSE = "ELSE",
|
||||
END = "END",
|
||||
IDENTIFIER = "IDENTIFIER",
|
||||
STRING = "STRING",
|
||||
NUMBER = "NUMBER",
|
||||
@@ -1028,4 +1173,4 @@ declare global {
|
||||
|
||||
declare const MeSqlark: typeof MetonaSqlark;
|
||||
|
||||
export { AriaEngine, AriaEngineConfig, ColumnDef, DatabaseConfig, DeleteStatement, DiskEngine, FieldType, HybridEngine, IStorageEngine, IndexedDBEngine, InsertStatement, MeSqlark, MemoryEngine, MetonaSqlark, OPFSBackend, OPFSEngine, SelectStatement, Statement, StorageMode, Table, TableSchema, UpdateStatement, VERSION, api, create, api as default, parse, tokenize };
|
||||
export { AriaEngine, AriaEngineConfig, ColumnDef, DatabaseConfig, DeleteStatement, DiskEngine, FieldType, HybridEngine, IStorageEngine, IndexedDBEngine, InsertStatement, MeSqlark, MemoryEngine, MetonaSqlark, OPFSBackend, OPFSEngine, SelectStatement, Statement, StorageMode, Table, TableSchema, UpdateStatement, VERSION, api, create, api as default, parse, parseAll, tokenize };
|
||||
|
||||
Vendored
+2055
-591
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+2055
-590
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user