feat: MetonaSqlark v0.1.12 — 前端TypeScript关系型数据库
CI / test (18.x) (push) Successful in 9m49s
CI / test (20.x) (push) Successful in 9m50s
CI / test (22.x) (push) Successful in 9m48s
CI / test (24.x) (push) Successful in 9m45s

- 4种存储引擎:Memory / IndexedDB / OPFS / Hybrid
- 完整SQL:SELECT/INSERT/UPDATE/DELETE/JOIN/GROUP BY/HAVING/DISTINCT
- Query Builder链式API + TypeScript泛型
- 聚合/事务/插件/发布订阅/迁移/导入导出
- React/Vue集成,264测试,93.46%覆盖率,零运行时依赖
This commit is contained in:
thzxx
2026-07-26 15:18:45 +08:00
parent e2a590c5b1
commit 7858cf3720
14 changed files with 9086 additions and 62 deletions
-1
View File
@@ -1,5 +1,4 @@
node_modules/
dist/
coverage/
.DS_Store
+85 -43
View File
@@ -1,4 +1,4 @@
# metona-sqlark
# MetonaSqlark
<p align="center">
<img src="https://img.shields.io/badge/version-0.1.12-blue?style=flat-square" alt="version">
@@ -11,35 +11,74 @@
---
## ✨ 核心特性
- 🧠 **双模式存储** — Memory / Disk / Hybrid,内存极速 + 磁盘持久化
-**完整 SQL** — SELECT / INSERT / UPDATE / DELETE / JOIN / GROUP BY / HAVING / DISTINCT
- 🔗 **Query Builder** — 链式 APITypeScript 类型友好
- 📊 **聚合函数** — COUNT / SUM / AVG / MIN / MAX
- 🔒 **事务支持** — 原子性操作,失败自动回滚
- 🧩 **插件系统** — 14 种生命周期钩子
- 📡 **发布订阅** — 表级变更监听
- 🔄 **数据迁移** — 版本化 migration 系统
- 📤 **导入导出** — JSON 格式全库/单表导入导出
- ⚛️ **React / Vue** — 原生 hooks & composables
- 📦 **零运行时依赖** — 纯 TypeScript,约 42KB min+gzip
---
## 📦 安装
```bash
npm install @metona-team/metona-sqlark
```
```typescript
// ESM / TypeScript
import { MetonaSqlark, MeSqlark } from '@metona-team/metona-sqlark';
> 如果提示找不到包,先配置 scope registry(一次性):
> ```bash
> npm config set @metona-team:registry https://git.metona.cn/api/packages/MetonaTeam/npm/
> ```
// Browser UMD
### CDN / 直接下载
```html
<!-- UMD 格式,暴露 window.MetonaSqlark 和 window.MeSqlark -->
<script src="https://git.metona.cn/MetonaTeam/MetonaSqlark/raw/branch/master/dist/metona-sqlark.min.js"></script>
```
或从 [`dist/`](./dist/) 目录下载:
- `metona-sqlark.js` — UMD 开发版(含 sourcemap
- `metona-sqlark.min.js` — UMD 压缩版(~42KB
- `metona-sqlark.esm.js` — ES Module
- `metona-sqlark.cjs.js` — CommonJS
- `metona-sqlark.d.ts` — TypeScript 类型声明
---
## 🚀 引入方式
### ESM / TypeScript
```typescript
import { MetonaSqlark } from '@metona-team/metona-sqlark';
// 别名
import { MeSqlark } from '@metona-team/metona-sqlark';
const db = await MetonaSqlark.create({ name: 'my-app', mode: 'hybrid' });
```
### CommonJS
```javascript
const { MetonaSqlark } = require('@metona-team/metona-sqlark');
(async () => {
const db = await MetonaSqlark.create({ name: 'my-app', mode: 'hybrid' });
})();
```
### Browser UMD
```html
<script src="metona-sqlark.min.js"></script>
// → window.MetonaSqlark / window.MeSqlark
<script>
(async () => {
const db = await window.MetonaSqlark.create({ name: 'my-app', mode: 'hybrid' });
// 或 window.MeSqlark(完全等价)
})();
</script>
```
### ES Module in Browser
```html
<script type="module">
import { MetonaSqlark } from './metona-sqlark.esm.js';
const db = await MetonaSqlark.create({ name: 'my-app', mode: 'hybrid' });
</script>
```
---
@@ -49,11 +88,10 @@ import { MetonaSqlark, MeSqlark } from '@metona-team/metona-sqlark';
```typescript
import { MetonaSqlark } from '@metona-team/metona-sqlark';
// 创建数据库
const db = await MetonaSqlark.create({
name: 'my-app',
mode: 'hybrid',
diskEngine: 'indexeddb',
mode: 'hybrid', // 'memory' | 'disk' | 'hybrid'
diskEngine: 'indexeddb', // 'indexeddb' | 'opfs'
});
// 定义表
@@ -69,9 +107,12 @@ await db.query("INSERT INTO users VALUES ('1', 'Alice', 30, 'alice@demo.com')");
const rows = await db.query('SELECT * FROM users WHERE age > 18 ORDER BY name');
// Query Builder
const users = db.table('users');
await users.insert({ id: '2', name: 'Bob', age: 25, email: 'bob@demo.com' });
const result = await users.select().where({ age: { $gt: 18 } }).orderBy('age', 'desc').execute();
const result = await db.table('users')
.select(['name', 'age'])
.where({ age: { $gt: 18 } })
.orderBy('age', 'desc')
.limit(10)
.execute();
// JOIN
await db.query(`SELECT u.name, o.product FROM users u INNER JOIN orders o ON u.id = o.user_id`);
@@ -116,7 +157,8 @@ await db.transaction(async (trx) => {
| `db.table(name)` | 获取表操作对象 |
| `db.defineTable(name, cols)` | 定义表结构 |
| `db.transaction(fn)` | 执行事务 |
| `db.exportTable(name)` / `db.exportAll()` | 导出数据 |
| `db.exportTable(name)` / `db.exportAll()` | 导出数据 JSON |
| `db.importTable(name, data)` | 导入数据 |
| `db.addMigration(v, fn)` / `db.migrateTo(v)` | 数据迁移 |
| `db.subscribe(table, fn)` | 订阅表变更 |
| `db.on(hook, fn)` | 注册钩子 |
@@ -135,6 +177,19 @@ const { data, loading, refresh } = useSqlarkQuery(db, 'SELECT * FROM users');
---
## 🛠 开发
```bash
npm install # 安装依赖
npm run dev # 开发模式(localhost:3001
npm run build # 生产构建(生成 dist/
npm test # 运行测试
npm run lint # 代码检查
npm run typecheck # 类型检查
```
---
## 📊 项目状态
| 指标 | 数值 |
@@ -147,19 +202,6 @@ const { data, loading, refresh } = useSqlarkQuery(db, 'SELECT * FROM users');
---
## 🛠 开发
```bash
npm install # 安装依赖
npm run dev # 开发模式(localhost:3001
npm run build # 生产构建
npm test # 运行测试
npm run lint # 代码检查
npm run typecheck # 类型检查
```
---
## 📂 项目结构
```
@@ -181,4 +223,4 @@ src/
## 📄 License
MIT © [MetonaTeam](https://git.metona.cn/MetonaTeam)
MIT © [MetonaTeam](https://git.metona.cn/MetonaTeam/MetonaSqlark)
+2732
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+733
View File
@@ -0,0 +1,733 @@
/**
* metona-sqlark Constants — 类型定义 / 默认配置 / 枚举
* @module constants
*/
/** 存储模式 */
type StorageMode = 'memory' | 'disk' | 'hybrid';
/** 磁盘引擎类型 */
type DiskEngine = 'indexeddb' | 'opfs';
/** 字段数据类型 */
type FieldType = 'string' | 'number' | 'boolean' | 'date' | 'json';
/** 列定义 */
interface ColumnDef {
/** 字段类型 */
type: FieldType;
/** 是否主键 */
primaryKey?: boolean;
/** 是否必填 */
required?: boolean;
/** 是否唯一 */
unique?: boolean;
/** 默认值 */
default?: unknown;
/** 是否创建索引 */
index?: boolean;
/** 外键引用: 'table.column' */
references?: string;
/** 字符串最大长度 */
maxLength?: number;
/** 数字最小值 */
min?: number;
/** 数字最大值 */
max?: number;
}
/** 表结构定义 */
interface TableSchema {
/** 表名 */
name: string;
/** 列定义映射 */
columns: Record<string, ColumnDef>;
}
/** 数据库配置 */
interface DatabaseConfig {
/** 数据库名称 */
name: string;
/** 存储模式 */
mode?: StorageMode;
/** 磁盘引擎(仅 mode='disk'|'hybrid' 时生效) */
diskEngine?: DiskEngine;
/** 版本号 */
version?: number;
/** 插件列表 */
plugins?: MetonaPlugin[];
/** 数据库就绪回调 */
onReady?: (db: unknown) => void;
/** 错误回调 */
onError?: (error: Error) => void;
}
/** Where 条件操作符 */
type WhereOperator = '$eq' | '$ne' | '$gt' | '$gte' | '$lt' | '$lte' | '$in' | '$nin' | '$like' | '$and' | '$or' | '$not';
/** 简单条件值:直接相等 */
type SimpleCondition = unknown;
/** 操作符条件 */
type OperatorCondition = Partial<Record<WhereOperator, unknown>>;
/** 字段条件:简单值 | 操作符对象 */
type FieldCondition = SimpleCondition | OperatorCondition;
/** Where 条件对象 */
type WhereCondition = Record<string, FieldCondition>;
/** 排序方向 */
type SortDirection = 'asc' | 'desc';
/** 排序定义 */
interface OrderBy {
/** 列名 */
column: string;
/** 排序方向 */
direction: SortDirection;
}
/** 查询计划 — 由 Executor 编译 AST 后生成 */
interface QueryPlan {
/** 表名 */
table: string;
/** 要返回的列(undefined = 全部,['*'] = 全部) */
columns?: string[];
/** 过滤条件 */
where?: WhereCondition;
/** 排序 */
orderBy?: OrderBy[];
/** 限制条数 */
limit?: number;
/** 偏移量 */
offset?: number;
}
/** 钩子名称 */
type HookName = 'beforeCreateTable' | 'afterCreateTable' | 'beforeDropTable' | 'afterDropTable' | 'beforeInsert' | 'afterInsert' | 'beforeUpdate' | 'afterUpdate' | 'beforeDelete' | 'afterDelete' | 'beforeQuery' | 'afterQuery' | 'beforeTransaction' | 'afterTransaction';
/** 插件定义 */
interface MetonaPlugin {
/** 插件名称 */
name: string;
/** 插件版本 */
version: string;
/** 描述 */
description?: string;
/** 优先级,越大越先执行 */
priority?: number;
/** 安装 */
install(db: unknown): void;
/** 销毁 */
destroy(): void;
}
declare const VERSION = "0.1.12";
/**
* metona-sqlark Plugin — 插件系统
* @module plugin
*
* 管理插件的注册、生命周期和钩子调度。
*/
type HookCallback = (...args: unknown[]) => void | Promise<void>;
declare class PluginManager {
private plugins;
private hooks;
/** 注册插件 */
register(plugin: MetonaPlugin): void;
/** 卸载插件 */
unregister(pluginName: string): void;
/** 获取所有已注册插件 */
getPlugins(): MetonaPlugin[];
/** 添加钩子回调 */
on(hook: HookName, callback: HookCallback): void;
/** 移除钩子回调 */
off(hook: HookName, callback: HookCallback): void;
/** 触发钩子 */
trigger(hook: HookName, ...args: unknown[]): Promise<void>;
/** 销毁所有插件 */
destroy(): void;
}
/**
* metona-sqlark Engine Interface — 存储引擎抽象接口
* @module engine/interface
*/
interface IStorageEngine {
/** 引擎名称 */
readonly name: string;
/** 打开数据库 */
open(dbName: string, version: number): Promise<void>;
/** 关闭数据库 */
close(): Promise<void>;
/** 检查数据库是否已打开 */
isOpen(): boolean;
/** 创建表 */
createTable(schema: TableSchema): Promise<void>;
/** 删除表 */
dropTable(tableName: string): Promise<void>;
/** 检查表是否存在 */
hasTable(tableName: string): Promise<boolean>;
/** 获取所有表名 */
getTableNames(): Promise<string[]>;
/** 获取表结构 */
getTableSchema(tableName: string): Promise<TableSchema | null>;
/** 插入行,返回主键值列表 */
insert(tableName: string, rows: Record<string, unknown>[]): Promise<string[]>;
/** 查询行 */
find(tableName: string, query: QueryPlan): Promise<Record<string, unknown>[]>;
/** 更新行,返回影响行数 */
update(tableName: string, query: QueryPlan, updates: Record<string, unknown>): Promise<number>;
/** 删除行,返回影响行数 */
delete(tableName: string, query: QueryPlan): Promise<number>;
/** 计数 */
count(tableName: string, query?: QueryPlan): Promise<number>;
/** 清空表数据(保留结构) */
clear(tableName: string): Promise<void>;
}
/**
* metona-sqlark Query AST — 查询抽象语法树类型定义
* @module query/ast
*
* QueryBuilder 和 SQL Parser 统一输出此 AST
* Executor 只认 AST,保证两种查询接口行为一致。
*/
/** 列引用,'*' 表示所有列;支持 'table.column' 格式 */
type ColumnRef = string;
/** JOIN 类型 */
type JoinType = 'INNER' | 'LEFT' | 'RIGHT' | 'CROSS';
/** JOIN 子句 */
interface JoinClause {
type: JoinType;
table: string;
alias?: string;
on: WhereCondition;
}
interface ASTColumnDef {
name: string;
type: string;
primaryKey?: boolean;
unique?: boolean;
required?: boolean;
default?: unknown;
index?: boolean;
maxLength?: number;
min?: number;
max?: number;
}
interface CreateTableStatement {
type: 'CREATE_TABLE';
name: string;
columns: ASTColumnDef[];
}
interface DropTableStatement {
type: 'DROP_TABLE';
name: string;
}
interface InsertStatement {
type: 'INSERT';
into: string;
columns?: string[];
values: unknown[][];
}
interface UpdateStatement {
type: 'UPDATE';
table: string;
sets: Record<string, unknown>;
where: WhereCondition;
}
interface DeleteStatement {
type: 'DELETE';
from: string;
where: WhereCondition;
}
interface SelectStatement {
type: 'SELECT';
columns: ColumnRef[];
distinct?: boolean;
from: string;
/** 主表别名 */
alias?: string;
/** JOIN 子句列表 */
joins?: JoinClause[];
where: WhereCondition;
/** GROUP BY */
groupBy?: string[];
/** HAVING */
having?: WhereCondition;
orderBy?: OrderBy[];
limit?: number;
offset?: number;
}
type Statement = SelectStatement | InsertStatement | UpdateStatement | DeleteStatement | CreateTableStatement | DropTableStatement;
/**
* metona-sqlark Query Executor — AST 执行器
* @module query/executor
*
* JOIN / GROUP BY / DISTINCT 逻辑在此层处理。
*/
declare class QueryExecutor {
private engine;
constructor(engine: IStorageEngine);
execute(stmt: Statement): Promise<unknown>;
private executeSelect;
private executeJoinSelect;
private prefixRow;
/** 嵌套循环连接(优化:避免 ON 时对象扩散) */
private joinRows;
private executeGroupBy;
private computeAggregate;
private executeDistinct;
private executeInsert;
private executeUpdate;
private executeDelete;
private executeCreateTable;
private executeDropTable;
getEngine(): IStorageEngine;
}
/**
* metona-sqlark Query Builder — 链式查询构建器
* @module query/builder
*
* 链式调用 → 构建 AST → 执行引擎操作。
* 支持 JOIN(需要 Executor)。
*/
declare class SelectQueryBuilder {
private engine;
private tableName;
private _columns;
private _where;
private _orderBy;
private _limit?;
private _offset?;
private _joins;
private _alias?;
private _executor?;
constructor(engine: IStorageEngine, tableName: string, _columns?: string[], executor?: QueryExecutor);
/** 主表别名 */
as(alias: string): this;
/** INNER JOIN */
innerJoin(table: string, on: WhereCondition, alias?: string): this;
/** LEFT JOIN */
leftJoin(table: string, on: WhereCondition, alias?: string): this;
/** RIGHT JOIN */
rightJoin(table: string, on: WhereCondition, alias?: string): this;
/** CROSS JOIN */
crossJoin(table: string, alias?: string): this;
/** 通用 JOIN */
join(table: string, on: WhereCondition, alias?: string): this;
private _addJoin;
/** 添加过滤条件 */
where(condition: WhereCondition): this;
/** 排序 */
orderBy(column: string, direction?: SortDirection): this;
/** 限制返回条数 */
limit(n: number): this;
/** 偏移量 */
offset(n: number): this;
/** 执行查询 */
execute(): Promise<Record<string, unknown>[]>;
/** 获取 AST */
toAST(): SelectStatement;
}
declare class UpdateQueryBuilder {
private engine;
private tableName;
private _updates;
private _where;
constructor(engine: IStorageEngine, tableName: string, _updates: Record<string, unknown>);
where(condition: WhereCondition): this;
execute(): Promise<number>;
toAST(): UpdateStatement;
}
declare class DeleteQueryBuilder {
private engine;
private tableName;
private _where;
constructor(engine: IStorageEngine, tableName: string);
where(condition: WhereCondition): this;
execute(): Promise<number>;
toAST(): DeleteStatement;
}
/**
* metona-sqlark Table — 表操作 API
* @module table/table
*/
declare class Table<T = Record<string, unknown>> {
readonly name: string;
private engine;
private schema;
private executor;
constructor(engine: IStorageEngine, tableName: string, executor?: QueryExecutor);
getSchema(): Promise<TableSchema>;
insert(row: T & Record<string, unknown>): Promise<string>;
insertMany(rows: (T & Record<string, unknown>)[]): Promise<string[]>;
select(columns?: string[]): SelectQueryBuilder;
update(updates: Partial<T> & Record<string, unknown>): UpdateQueryBuilder;
delete(): DeleteQueryBuilder;
count(where?: Record<string, unknown>): Promise<number>;
clear(): Promise<void>;
drop(): Promise<void>;
}
/**
* metona-sqlark Transaction — 事务管理
* @module transaction
*
* 封装多操作事务,保证原子性。
* v0.0.1: 基于引擎层操作实现,IndexedDB 引擎利用原生事务。
*/
declare class Transaction {
private engine;
private tables;
private completed;
constructor(engine: IStorageEngine);
/** 获取表操作对象 */
table(tableName: string): Table;
/** 标记事务完成(由 TransactionManager 调用) */
_markCompleted(): void;
/** 是否已完成 */
isCompleted(): boolean;
}
declare class MetonaSqlark {
/** 数据库名称 */
readonly name: string;
/** 存储模式 */
readonly mode: string;
/** 版本号 */
private _version;
/** 获取版本号 */
get version(): number;
private engine;
private executor;
private transactionManager;
private pluginManager;
private config;
private ready;
private tableCache;
constructor(config: DatabaseConfig);
/** 初始化数据库(创建引擎、打开连接) */
init(): Promise<void>;
/** 检查是否就绪 */
isReady(): boolean;
/** 创建表 */
defineTable(name: string, columns: Record<string, ColumnDef>): Promise<void>;
/** 获取表操作对象 */
table(name: string): Table;
/** 删除表 */
dropTable(name: string): Promise<void>;
/** 获取所有表名 */
getTableNames(): Promise<string[]>;
/** 执行 SQL 字符串查询 */
query(sql: string): Promise<unknown>;
/** 执行事务 */
transaction<T>(fn: (trx: Transaction) => Promise<T>): Promise<T>;
/** 导出表数据为 JSON */
exportTable(tableName: string): Promise<Record<string, unknown>[]>;
/** 导入 JSON 数据到表 */
importTable(tableName: string, data: Record<string, unknown>[]): Promise<string[]>;
/** 导出整个数据库为 JSON */
exportAll(): Promise<Record<string, Record<string, unknown>[]>>;
private listeners;
/** 订阅表变更 */
subscribe(tableName: string, callback: (event: {
type: string;
row?: unknown;
}) => void): () => void;
/** 触发变更事件 */
emit(tableName: string, event: {
type: string;
row?: unknown;
}): void;
private migrations;
/** 注册迁移 */
addMigration(version: number, up: (db: MetonaSqlark) => Promise<void>): void;
/** 执行迁移到指定版本 */
migrateTo(targetVersion: number): Promise<void>;
/** 获取插件管理器 */
getPluginManager(): PluginManager;
/** 注册钩子 */
on(hook: HookName, callback: HookCallback): void;
/** 关闭数据库 */
close(): Promise<void>;
/** 获取底层引擎 */
getEngine(): IStorageEngine;
private createEngine;
private ensureReady;
}
/**
* metona-sqlark Memory Engine — 基于 Map 的内存存储引擎
* @module engine/memory
*/
declare class MemoryEngine implements IStorageEngine {
readonly name = "memory";
private tables;
private schemas;
private indexes;
private opened;
open(_dbName: string, _version: number): Promise<void>;
close(): Promise<void>;
isOpen(): boolean;
createTable(schema: TableSchema): Promise<void>;
dropTable(tableName: string): Promise<void>;
hasTable(tableName: string): Promise<boolean>;
getTableNames(): Promise<string[]>;
getTableSchema(tableName: string): Promise<TableSchema | null>;
insert(tableName: string, rows: Record<string, unknown>[]): Promise<string[]>;
find(tableName: string, query: QueryPlan): Promise<Record<string, unknown>[]>;
update(tableName: string, query: QueryPlan, updates: Record<string, unknown>): Promise<number>;
delete(tableName: string, query: QueryPlan): Promise<number>;
count(tableName: string, query?: QueryPlan): Promise<number>;
clear(tableName: string): Promise<void>;
private ensureTable;
private getPrimaryKey;
private validateRow;
private checkType;
/** O(1) 唯一性检查:利用哈希索引 */
private checkUniqueness;
/** 索引查找 */
private tryIndexLookup;
/** 更新索引 */
private updateIndexes;
}
/**
* metona-sqlark IndexedDB Engine — 基于 IndexedDB 的持久化存储引擎
* @module engine/indexeddb
*/
declare class IndexedDBEngine implements IStorageEngine {
readonly name = "indexeddb";
private db;
private dbName;
private version;
private memoryCache;
open(dbName: string, version: number): Promise<void>;
close(): Promise<void>;
isOpen(): boolean;
createTable(schema: TableSchema): Promise<void>;
dropTable(tableName: string): Promise<void>;
hasTable(tableName: string): Promise<boolean>;
getTableNames(): Promise<string[]>;
getTableSchema(tableName: string): Promise<TableSchema | null>;
insert(tableName: string, rows: Record<string, unknown>[]): Promise<string[]>;
find(tableName: string, query: QueryPlan): Promise<Record<string, unknown>[]>;
update(tableName: string, query: QueryPlan, updates: Record<string, unknown>): Promise<number>;
delete(tableName: string, query: QueryPlan): Promise<number>;
count(tableName: string, query?: QueryPlan): Promise<number>;
clear(tableName: string): Promise<void>;
private ensureDB;
}
/**
* metona-sqlark OPFS Engine — 基于 Origin Private File System 的持久化存储引擎
* @module engine/opfs
*
* 使用 JSON-per-table 文件存储方案。
* 目录结构:{dbName}/tables/{tableName}.json
*/
declare class OPFSEngine implements IStorageEngine {
readonly name = "opfs";
private root;
private tablesDir;
private dbName;
private memoryCache;
open(dbName: string, version: number): Promise<void>;
close(): Promise<void>;
isOpen(): boolean;
createTable(schema: TableSchema): Promise<void>;
dropTable(tableName: string): Promise<void>;
hasTable(tableName: string): Promise<boolean>;
getTableNames(): Promise<string[]>;
getTableSchema(tableName: string): Promise<TableSchema | null>;
insert(tableName: string, rows: Record<string, unknown>[]): Promise<string[]>;
find(tableName: string, query: QueryPlan): Promise<Record<string, unknown>[]>;
update(tableName: string, query: QueryPlan, updates: Record<string, unknown>): Promise<number>;
delete(tableName: string, query: QueryPlan): Promise<number>;
count(tableName: string, query?: QueryPlan): Promise<number>;
clear(tableName: string): Promise<void>;
private ensureDir;
private writeTableData;
private readTableData;
/** 从 OPFS 加载表数据到内存缓存 */
loadTableIntoMemory(tableName: string, schema: TableSchema): Promise<void>;
}
/**
* metona-sqlark Hybrid Engine — 内存 + 磁盘混合存储引擎
* @module hybrid/index
*
* 采用 write-through 策略:
* - 所有写操作同时写入内存和磁盘
* - 所有读操作直接从内存返回
* - 数据库打开时从磁盘加载数据到内存
*/
declare class HybridEngine implements IStorageEngine {
readonly name = "hybrid";
private memoryEngine;
private diskEngine;
private diskEngineType;
constructor(diskEngine?: DiskEngine);
open(dbName: string, version: number): Promise<void>;
close(): Promise<void>;
isOpen(): boolean;
createTable(schema: TableSchema): Promise<void>;
dropTable(tableName: string): Promise<void>;
hasTable(tableName: string): Promise<boolean>;
getTableNames(): Promise<string[]>;
getTableSchema(tableName: string): Promise<TableSchema | null>;
insert(tableName: string, rows: Record<string, unknown>[]): Promise<string[]>;
find(tableName: string, query: QueryPlan): Promise<Record<string, unknown>[]>;
update(tableName: string, query: QueryPlan, updates: Record<string, unknown>): Promise<number>;
delete(tableName: string, query: QueryPlan): Promise<number>;
count(tableName: string, query?: QueryPlan): Promise<number>;
clear(tableName: string): Promise<void>;
/** 获取磁盘引擎类型 */
getDiskEngineType(): DiskEngine;
/** 获取内存引擎(供内部使用) */
getMemoryEngine(): MemoryEngine;
}
/**
* metona-sqlark SQL Parser — 递归下降语法分析器
* @module sql/parser
*
* Token 流 → AST Statement。
* 支持的语法是标准 SQL 的子集。
*/
/** 解析 SQL 字符串为 AST Statement */
declare function parse(sql: string): Statement;
/**
* metona-sqlark SQL Token Types — 词法单元定义
* @module sql/tokens
*/
declare enum TokenType {
SELECT = "SELECT",
FROM = "FROM",
WHERE = "WHERE",
INSERT = "INSERT",
INTO = "INTO",
VALUES = "VALUES",
UPDATE = "UPDATE",
SET = "SET",
DELETE = "DELETE",
CREATE = "CREATE",
TABLE = "TABLE",
DROP = "DROP",
ORDER = "ORDER",
BY = "BY",
ASC = "ASC",
DESC = "DESC",
LIMIT = "LIMIT",
OFFSET = "OFFSET",
AND = "AND",
OR = "OR",
NOT = "NOT",
LIKE = "LIKE",
IN = "IN",
PRIMARY = "PRIMARY",
KEY = "KEY",
UNIQUE = "UNIQUE",
DEFAULT = "DEFAULT",
NULL = "NULL",
TRUE = "TRUE",
FALSE = "FALSE",
INNER = "INNER",
LEFT = "LEFT",
RIGHT = "RIGHT",
CROSS = "CROSS",
JOIN = "JOIN",
ON = "ON",
AS = "AS",
OUTER = "OUTER",
GROUP = "GROUP",
HAVING = "HAVING",
COUNT = "COUNT",
SUM = "SUM",
AVG = "AVG",
MIN = "MIN",
MAX = "MAX",
DISTINCT = "DISTINCT",
IDENTIFIER = "IDENTIFIER",
STRING = "STRING",
NUMBER = "NUMBER",
COMMA = "COMMA",
LPAREN = "LPAREN",
RPAREN = "RPAREN",
SEMICOLON = "SEMICOLON",
EQ = "EQ",
NEQ = "NEQ",
GT = "GT",
GTE = "GTE",
LT = "LT",
LTE = "LTE",
STAR = "STAR",
DOT = "DOT",
EOF = "EOF",
ILLEGAL = "ILLEGAL"
}
interface Token {
type: TokenType;
value: string;
position: number;
}
/**
* metona-sqlark SQL Lexer — 词法分析器
* @module sql/lexer
*
* 将 SQL 字符串切分为 Token 流。
*/
/** 将 SQL 字符串解析为 Token 列表 */
declare function tokenize(sql: string): Token[];
/**
* metona-sqlark — 入口文件
* @module metona-sqlark
* @version 0.1.12
*
* 前端关系型数据库,内存与磁盘双模式。
* 支持 Query Builder 链式 API 和 SQL 字符串查询。
*/
/**
* 创建数据库实例并初始化
*
* @example
* ```ts
* const db = await MetonaSqlark.create({
* name: 'my-app',
* mode: 'hybrid',
* });
*
* await db.defineTable('users', {
* id: { type: 'string', primaryKey: true },
* name: { type: 'string', required: true },
* });
*
* await db.table('users').insert({ id: '1', name: 'Alice' });
* const results = await db.query('SELECT * FROM users');
* ```
*/
declare function create(config: DatabaseConfig): Promise<MetonaSqlark>;
declare const api: {
VERSION: string;
version: string;
create: typeof create;
MetonaSqlark: typeof MetonaSqlark;
MeSqlark: typeof MetonaSqlark;
};
declare global {
interface Window {
MetonaSqlark: typeof api;
MeSqlark: typeof api;
}
}
declare const MeSqlark: typeof MetonaSqlark;
export { ColumnDef, DatabaseConfig, DeleteStatement, DiskEngine, FieldType, HybridEngine, IStorageEngine, IndexedDBEngine, InsertStatement, MeSqlark, MemoryEngine, MetonaSqlark, OPFSEngine, SelectStatement, Statement, StorageMode, Table, TableSchema, UpdateStatement, VERSION, api, create, api as default, parse, tokenize };
+2716
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+2738
View File
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+3 -3
View File
@@ -34,7 +34,7 @@
},
"repository": {
"type": "git",
"url": "git+https://git.metona.cn/MetonaTeam/metona-sqlark.git"
"url": "git+https://git.metona.cn/MetonaTeam/MetonaSqlark.git"
},
"keywords": [
"database",
@@ -49,9 +49,9 @@
"author": "thzxx",
"license": "MIT",
"bugs": {
"url": "https://git.metona.cn/MetonaTeam/metona-sqlark/issues"
"url": "https://git.metona.cn/MetonaTeam/MetonaSqlark/issues"
},
"homepage": "https://git.metona.cn/MetonaTeam/metona-sqlark#readme",
"homepage": "https://git.metona.cn/MetonaTeam/MetonaSqlark#readme",
"devDependencies": {
"@babel/core": "^7.22.0",
"@babel/plugin-transform-modules-commonjs": "^7.22.0",
+4 -4
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>在线演示 — metona-sqlark</title>
<title>在线演示 — MetonaSqlark</title>
<style>
:root {
--bg:#0a0a0f; --surface:#0d1117; --surface2:#161b22; --border:#30363d;
@@ -87,7 +87,7 @@
<body>
<header>
<div class="logo"><div class="icon"></div><span>metona-sqlark</span></div>
<div class="logo"><div class="icon"></div><span>MetonaSqlark</span></div>
<nav>
<a href="index.html">首页</a>
<a href="docs.html">文档</a>
@@ -104,7 +104,7 @@
<div class="tab" data-tab="builder">Query Builder</div>
</div>
<div class="editor-area">
<textarea id="sql-input" placeholder="输入 SQL 语句...&#10;&#10;SELECT * FROM users WHERE age > 18&#10;INSERT INTO users VALUES ('4', 'Diana', 'diana@test.com', 28)&#10;SELECT u.name, o.amount FROM users u INNER JOIN orders o ON u.id = o.user_id">-- 欢迎使用 metona-sqlark 在线演示 🚀
<textarea id="sql-input" placeholder="输入 SQL 语句...&#10;&#10;SELECT * FROM users WHERE age > 18&#10;INSERT INTO users VALUES ('4', 'Diana', 'diana@test.com', 28)&#10;SELECT u.name, o.amount FROM users u INNER JOIN orders o ON u.id = o.user_id">-- 欢迎使用 MetonaSqlark 在线演示 🚀
-- 已预置 users / orders 表数据,试试以下查询:
SELECT * FROM users;
@@ -335,7 +335,7 @@ document.querySelectorAll('.tab').forEach(tab => {
// Boot
initDB().then(() => {
console.log('✅ metona-sqlark demo ready');
console.log('✅ MetonaSqlark demo ready');
// Auto-run initial query
setTimeout(runQuery, 200);
});
+5 -5
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>API 文档 — metona-sqlark</title>
<title>API 文档 — MetonaSqlark</title>
<style>
:root {
--bg:#0a0a0f; --surface:#14141f; --surface2:#1a1a2e; --border:#2a2a45;
@@ -67,7 +67,7 @@
<header>
<div class="inner">
<div class="logo"><div class="icon"></div><span>metona-sqlark</span></div>
<div class="logo"><div class="icon"></div><span>MetonaSqlark</span></div>
<nav>
<a href="index.html">首页</a>
<a href="docs.html" class="nav-active">文档</a>
@@ -102,10 +102,10 @@
<h2 id="install">📦 安装</h2>
<pre><span class="c">// npm</span>
npm install @metona-team/metona-sqlark
npm install @metona-team/MetonaSqlark
<span class="c">// ESM</span>
<span class="k">import</span> { MetonaSqlark, MeSqlark } <span class="k">from</span> <span class="s">'metona-sqlark'</span>;
<span class="k">import</span> { MetonaSqlark, MeSqlark } <span class="k">from</span> <span class="s">'MetonaSqlark'</span>;
<span class="c">// Browser</span>
&lt;script src=<span class="s">"metona-sqlark.min.js"</span>&gt;&lt;/script&gt;
@@ -273,7 +273,7 @@ db.<span class="f">on</span>(<span class="s">'afterQuery'</span>, <span class="k
<span class="k">await</span> users.<span class="f">insert</span>({ <span class="s">id</span>: <span class="s">'1'</span>, <span class="s">name</span>: <span class="s">'Alice'</span>, <span class="s">age</span>: <span class="n">30</span> }); <span class="c">// ✅ 类型安全</span></pre>
<h2 id="config">⚙️ 配置项</h2>
<pre><span class="k">import</span> { MetonaSqlark, MeSqlark } <span class="k">from</span> <span class="s">'metona-sqlark'</span>;
<pre><span class="k">import</span> { MetonaSqlark, MeSqlark } <span class="k">from</span> <span class="s">'MetonaSqlark'</span>;
<span class="c">// MeSqlark 是 MetonaSqlark 的别名,完全等价</span></pre>
</main>
+66 -6
View File
@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>metona-sqlark — 前端 TypeScript 数据库</title>
<title>MetonaSqlark — 前端 TypeScript 数据库</title>
<style>
:root {
--bg: #0a0a0f;
@@ -136,13 +136,13 @@
<div class="container">
<div class="logo">
<div class="icon"></div>
<span>metona-sqlark</span>
<span>MetonaSqlark</span>
</div>
<nav>
<a href="index.html">首页</a>
<a href="docs.html">文档</a>
<a href="demo.html">演示</a>
<a href="https://git.metona.cn/MetonaTeam/metona-sqlark" target="_blank">GitHub</a>
<a href="https://git.metona.cn/MetonaTeam/MetonaSqlark" target="_blank">GitHub</a>
</nav>
<a href="demo.html" class="btn btn-primary">立即体验</a>
</div>
@@ -161,11 +161,71 @@
</div>
</section>
<!-- Install -->
<section style="padding:20px 0 60px;">
<div class="container">
<div class="section-title">
<h2>📦 <span>安装</span>引入</h2>
<p>多种方式,按需选择</p>
</div>
<div class="feature-grid">
<div class="feature-card">
<div class="icon">📦</div>
<h3>npm (Gitea Registry)</h3>
<div class="code-block" style="font-size:0.8rem;margin-top:12px;padding:14px;">
<span class="comment"># 配置 registry</span>
npm config set @metona-team:registry https://git.metona.cn/api/packages/MetonaTeam/npm/
<span class="comment"># 安装</span>
npm install @metona-team/metona-sqlark
</div>
</div>
<div class="feature-card">
<div class="icon">🌐</div>
<h3>CDN / Browser UMD</h3>
<div class="code-block" style="font-size:0.8rem;margin-top:12px;padding:14px;">
<span class="comment">&lt;!-- 直接引用 dist 产物 --&gt;</span>
&lt;<span class="keyword">script</span> src=<span class="string">"metona-sqlark.min.js"</span>&gt;&lt;/script&gt;
&lt;<span class="keyword">script</span>&gt;
<span class="keyword">const</span> db = <span class="keyword">await</span> window.<span class="func">MetonaSqlark</span>.create({...});
<span class="comment">// 或 window.MeSqlark(别名)</span>
&lt;/script&gt;
</div>
</div>
<div class="feature-card">
<div class="icon"></div>
<h3>ESM / TypeScript</h3>
<div class="code-block" style="font-size:0.8rem;margin-top:12px;padding:14px;">
<span class="keyword">import</span> { MetonaSqlark, MeSqlark }
<span class="keyword">from</span> <span class="string">'@metona-team/metona-sqlark'</span>;
<span class="keyword">const</span> db = <span class="keyword">await</span> <span class="func">MetonaSqlark</span>.create({
<span class="string">name</span>: <span class="string">'my-app'</span>,
<span class="string">mode</span>: <span class="string">'hybrid'</span>,
});
</div>
</div>
<div class="feature-card">
<div class="icon">🔧</div>
<h3>CommonJS</h3>
<div class="code-block" style="font-size:0.8rem;margin-top:12px;padding:14px;">
<span class="keyword">const</span> { MetonaSqlark } =
<span class="func">require</span>(<span class="string">'@metona-team/metona-sqlark'</span>);
(<span class="keyword">async</span> () => {
<span class="keyword">const</span> db = <span class="keyword">await</span> <span class="func">MetonaSqlark</span>.create({...});
})();
</div>
</div>
</div>
</div>
</section>
<!-- Features -->
<section>
<div class="container">
<div class="section-title">
<h2>为什么选择 <span>metona-sqlark</span></h2>
<h2>为什么选择 <span>MetonaSqlark</span></h2>
<p>专为前端打造的数据库引擎</p>
</div>
<div class="feature-grid">
@@ -238,7 +298,7 @@
<div class="container">
<div class="section-title">
<h2><span>数字</span>说话</h2>
<p>metona-sqlark 的核心指标</p>
<p>MetonaSqlark 的核心指标</p>
</div>
<div class="stats">
<div class="stat-card"><div class="num">235+</div><div class="label">测试用例</div></div>
@@ -251,7 +311,7 @@
<footer>
<div class="container">
<p>© 2026 <a href="https://git.metona.cn/MetonaTeam/metona-sqlark">MetonaTeam</a>. MIT License. Built with TypeScript.</p>
<p>© 2026 <a href="https://git.metona.cn/MetonaTeam/MetonaSqlark">MetonaTeam</a>. MIT License. Built with TypeScript.</p>
</div>
</footer>