release: v0.2.2 AriaEngine OPFS 自研存储后端 — 零依赖纯文件系统
CI / test (18.x) (push) Successful in 10m0s
CI / test (20.x) (push) Successful in 9m56s
CI / test (22.x) (push) Successful in 9m56s
CI / test (24.x) (push) Successful in 9m52s

This commit is contained in:
thzxx
2026-07-27 21:08:57 +08:00
parent eab58adc37
commit fef4db44ca
18 changed files with 450 additions and 73 deletions
+88 -1
View File
@@ -2780,6 +2780,89 @@ class MemoryBackend {
}
}
class OPFSBackend {
constructor() {
this.root = null;
this.dbDir = null;
this.dbName = '';
}
async open(name) {
this.dbName = name;
this.root = await navigator.storage.getDirectory();
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
}
async close() {
this.dbDir = null;
this.root = null;
}
isOpen() {
return this.dbDir !== null;
}
async read(key) {
if (!this.dbDir)
return null;
try {
const fh = await this.dbDir.getFileHandle(key);
const file = await fh.getFile();
return await file.arrayBuffer();
}
catch {
return null;
}
}
async write(key, data) {
if (!this.dbDir)
return;
const fh = await this.dbDir.getFileHandle(key, { create: true });
const writable = await fh.createWritable();
await writable.write(data);
await writable.close();
}
async delete(key) {
if (!this.dbDir)
return;
try {
await this.dbDir.removeEntry(key);
}
catch {
// 文件不存在则忽略
}
}
async listKeys() {
if (!this.dbDir)
return [];
const keys = [];
// FileSystemDirectoryHandle.entries() 返回 AsyncIterable,使用 any 绕过 dts 生成限制
const dir = this.dbDir;
for await (const [name] of dir.entries()) {
keys.push(name);
}
return keys;
}
async exists(key) {
if (!this.dbDir)
return false;
try {
await this.dbDir.getFileHandle(key);
return true;
}
catch {
return false;
}
}
async clear() {
if (!this.dbDir)
return;
const dir = this.dbDir;
for await (const [name] of dir.entries()) {
try {
await this.dbDir.removeEntry(name);
}
catch { /* ignore */ }
}
}
}
/**
* AriaEngine — 自研页面式存储引擎主类
* @module engine/aria/index
@@ -2817,7 +2900,10 @@ class AriaEngine {
return;
this.dbName = dbName;
// 1. 存储后端
if (this.config.storageBackend === 'indexeddb') {
if (this.config.storageBackend === 'opfs') {
this.backend = new OPFSBackend();
}
else if (this.config.storageBackend === 'indexeddb') {
this.backend = new IndexedDBBackend();
}
else {
@@ -5825,6 +5911,7 @@ exports.IndexedDBEngine = IndexedDBEngine;
exports.MeSqlark = MeSqlark;
exports.MemoryEngine = MemoryEngine;
exports.MetonaSqlark = MetonaSqlark;
exports.OPFSBackend = OPFSBackend;
exports.OPFSEngine = OPFSEngine;
exports.Table = Table;
exports.VERSION = VERSION;
+1 -1
View File
File diff suppressed because one or more lines are too long
+54 -1
View File
@@ -851,6 +851,59 @@ interface Token {
/** 将 SQL 字符串解析为 Token 列表 */
declare function tokenize(sql: string): Token[];
/**
* AriaEngine Storage Backend — 存储后端抽象层
* @module engine/aria/store/backend
*
* 封装底层浏览器存储 APIIndexedDB / OPFS / Memory 回退),
* 供 Buffer Pool 的 PageIO 和 WAL 的 WALStore 使用。
*/
interface IStorageBackend {
/** 打开存储 */
open(name: string): Promise<void>;
/** 关闭存储 */
close(): Promise<void>;
/** 是否已打开 */
isOpen(): boolean;
/** 读取数据块 */
read(key: string): Promise<ArrayBuffer | null>;
/** 写入数据块 */
write(key: string, data: ArrayBuffer): Promise<void>;
/** 删除数据块 */
delete(key: string): Promise<void>;
/** 列出所有 key */
listKeys(): Promise<string[]>;
/** 检查 key 是否存在 */
exists(key: string): Promise<boolean>;
/** 清空所有数据 */
clear(): Promise<void>;
}
/**
* AriaEngine OPFS Backend — 基于 Origin Private File System 的自研存储后端
* @module engine/aria/store/opfs_backend
*
* 零外部依赖,纯浏览器文件系统 API。
* 每个 key 对应 OPFS 目录下的一个二进制文件。
*
* 浏览器要求:Chrome 102+ / Edge 102+
*/
declare class OPFSBackend implements IStorageBackend {
private root;
private dbDir;
private dbName;
open(name: string): Promise<void>;
close(): Promise<void>;
isOpen(): boolean;
read(key: string): Promise<ArrayBuffer | null>;
write(key: string, data: ArrayBuffer): Promise<void>;
delete(key: string): Promise<void>;
listKeys(): Promise<string[]>;
exists(key: string): Promise<boolean>;
clear(): Promise<void>;
}
/**
* metona-sqlark — 入口文件
* @module metona-sqlark
@@ -896,4 +949,4 @@ declare global {
declare const MeSqlark: typeof MetonaSqlark;
export { AriaEngine, AriaEngineConfig, 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 };
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 };
+88 -2
View File
@@ -2776,6 +2776,89 @@ class MemoryBackend {
}
}
class OPFSBackend {
constructor() {
this.root = null;
this.dbDir = null;
this.dbName = '';
}
async open(name) {
this.dbName = name;
this.root = await navigator.storage.getDirectory();
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
}
async close() {
this.dbDir = null;
this.root = null;
}
isOpen() {
return this.dbDir !== null;
}
async read(key) {
if (!this.dbDir)
return null;
try {
const fh = await this.dbDir.getFileHandle(key);
const file = await fh.getFile();
return await file.arrayBuffer();
}
catch {
return null;
}
}
async write(key, data) {
if (!this.dbDir)
return;
const fh = await this.dbDir.getFileHandle(key, { create: true });
const writable = await fh.createWritable();
await writable.write(data);
await writable.close();
}
async delete(key) {
if (!this.dbDir)
return;
try {
await this.dbDir.removeEntry(key);
}
catch {
// 文件不存在则忽略
}
}
async listKeys() {
if (!this.dbDir)
return [];
const keys = [];
// FileSystemDirectoryHandle.entries() 返回 AsyncIterable,使用 any 绕过 dts 生成限制
const dir = this.dbDir;
for await (const [name] of dir.entries()) {
keys.push(name);
}
return keys;
}
async exists(key) {
if (!this.dbDir)
return false;
try {
await this.dbDir.getFileHandle(key);
return true;
}
catch {
return false;
}
}
async clear() {
if (!this.dbDir)
return;
const dir = this.dbDir;
for await (const [name] of dir.entries()) {
try {
await this.dbDir.removeEntry(name);
}
catch { /* ignore */ }
}
}
}
/**
* AriaEngine — 自研页面式存储引擎主类
* @module engine/aria/index
@@ -2813,7 +2896,10 @@ class AriaEngine {
return;
this.dbName = dbName;
// 1. 存储后端
if (this.config.storageBackend === 'indexeddb') {
if (this.config.storageBackend === 'opfs') {
this.backend = new OPFSBackend();
}
else if (this.config.storageBackend === 'indexeddb') {
this.backend = new IndexedDBBackend();
}
else {
@@ -5815,5 +5901,5 @@ if (typeof window !== 'undefined') {
// 别名
const MeSqlark = MetonaSqlark;
export { AriaEngine, HybridEngine, IndexedDBEngine, MeSqlark, MemoryEngine, MetonaSqlark, OPFSEngine, Table, VERSION, api, create, api as default, parse, tokenize };
export { AriaEngine, HybridEngine, IndexedDBEngine, MeSqlark, MemoryEngine, MetonaSqlark, OPFSBackend, OPFSEngine, Table, VERSION, api, create, api as default, parse, tokenize };
//# sourceMappingURL=metona-sqlark.esm.js.map
+1 -1
View File
File diff suppressed because one or more lines are too long
+88 -1
View File
@@ -2782,6 +2782,89 @@
}
}
class OPFSBackend {
constructor() {
this.root = null;
this.dbDir = null;
this.dbName = '';
}
async open(name) {
this.dbName = name;
this.root = await navigator.storage.getDirectory();
this.dbDir = await this.root.getDirectoryHandle(name, { create: true });
}
async close() {
this.dbDir = null;
this.root = null;
}
isOpen() {
return this.dbDir !== null;
}
async read(key) {
if (!this.dbDir)
return null;
try {
const fh = await this.dbDir.getFileHandle(key);
const file = await fh.getFile();
return await file.arrayBuffer();
}
catch {
return null;
}
}
async write(key, data) {
if (!this.dbDir)
return;
const fh = await this.dbDir.getFileHandle(key, { create: true });
const writable = await fh.createWritable();
await writable.write(data);
await writable.close();
}
async delete(key) {
if (!this.dbDir)
return;
try {
await this.dbDir.removeEntry(key);
}
catch {
// 文件不存在则忽略
}
}
async listKeys() {
if (!this.dbDir)
return [];
const keys = [];
// FileSystemDirectoryHandle.entries() 返回 AsyncIterable,使用 any 绕过 dts 生成限制
const dir = this.dbDir;
for await (const [name] of dir.entries()) {
keys.push(name);
}
return keys;
}
async exists(key) {
if (!this.dbDir)
return false;
try {
await this.dbDir.getFileHandle(key);
return true;
}
catch {
return false;
}
}
async clear() {
if (!this.dbDir)
return;
const dir = this.dbDir;
for await (const [name] of dir.entries()) {
try {
await this.dbDir.removeEntry(name);
}
catch { /* ignore */ }
}
}
}
/**
* AriaEngine 自研页面式存储引擎主类
* @module engine/aria/index
@@ -2819,7 +2902,10 @@
return;
this.dbName = dbName;
// 1. 存储后端
if (this.config.storageBackend === 'indexeddb') {
if (this.config.storageBackend === 'opfs') {
this.backend = new OPFSBackend();
}
else if (this.config.storageBackend === 'indexeddb') {
this.backend = new IndexedDBBackend();
}
else {
@@ -5827,6 +5913,7 @@
exports.MeSqlark = MeSqlark;
exports.MemoryEngine = MemoryEngine;
exports.MetonaSqlark = MetonaSqlark;
exports.OPFSBackend = OPFSBackend;
exports.OPFSEngine = OPFSEngine;
exports.Table = Table;
exports.VERSION = VERSION;
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long