Files
MetonaSqlark/CONTRIBUTING.md
T
thzxx 05e6823bf1
CI / test (22.x) (push) Successful in 24m26s
CI / e2e (push) Successful in 10m0s
CI / test (18.x) (push) Successful in 27m14s
CI / test (20.x) (push) Failing after 1h19m9s
CI / test (24.x) (push) Successful in 37m49s
fix: v0.7.2 语句级原子性 + 事务 DDL 拒绝 + 约束/绑定硬化 — 6 项修复 + 43 回归 + CI 重型套件串行
- UPDATE 语句级部分提交(P1,四引擎):两阶段全量预检后执行,批内唯一互查,
  任何一行失败整句不执行(aria 场景 WAL 与内存不再错位)
- 事务内 ALTER/CREATE INDEX/DROP INDEX 残留(P1):Memory/KVStore 显式拒绝
  (对齐 Aria),createTable/dropTable 保持可回滚
- SET NULL 级联绕过 required 约束(P1):预检阶段整体拒绝 FOREIGN_KEY_VIOLATION
- bindParameters 注释误判(P2):行注释/块注释中的 ? 与引号不再参与绑定
- 未闭合字符串静默接受 → lexer 抛 PARSE_ERROR;未知 where 操作符抛 QUERY_ERROR
- UPDATE undefined 覆盖列值 → 语义化为不更新(null 仍置空)
- Hybrid 写穿透非原子(P1):磁盘失败自动重载内存对齐磁盘再抛原错误
- CI:Run tests 拆常规并行 + 重型串行(runInBand),重型测试超时余量提升,
  性能护栏 kv 120→240s / opfs 150→300s(仍拦截悬崖回归)
- 测试 1155 → 1198(74 套件),覆盖率 89.82% 保持
2026-08-13 15:31:16 +08:00

8.2 KiB
Raw Blame History

Contributing to MetonaSqlark

Thanks for your interest in contributing! This document outlines the development workflow and conventions.

Prerequisites

  • Node.js >= 16.0.0
  • npm >= 8.0.0

Setup

git clone https://git.metona.cn/MetonaTeam/MetonaSqlark.git
cd MetonaSqlark
npm install

Development

# Start dev server with hot reload (port 3001)
npm run dev

# Run tests in watch mode
npm run test:watch

# Type check
npm run typecheck

# Lint
npm run lint
npm run lint:fix

# Format
npm run format

Project Structure

src/
├── index.ts              # Entry point, global API (MetonaSqlark + MeSqlark)
├── core.ts               # MetonaSqlark main class
├── constants.ts          # Types, defaults, enums, errors
├── connection-manager.ts # Connection pool (connect/disconnect)
├── engine/               # Storage engines
│   ├── interface.ts      # IStorageEngine interface
│   ├── memory.ts         # MemoryEngine (Map-based)
│   ├── kvstore_engine.ts # KVStoreEngine (disk mode, self-built KV store)
│   ├── kvstore/          # KVStore (log + snapshot + atomic multi-key write)
│   └── aria/             # AriaEngine (LSM-Tree page storage engine)
│       ├── index/        # LSM / MemTable / SSTable / Bloom / MergeIterator
│       ├── page/         # 4KB slotted page format
│       ├── buffer/       # Buffer Pool (LRU eviction)
│       ├── wal/          # Write-Ahead Log + Checkpoint
│       ├── transaction/  # MVCC manager
│       ├── store/        # Backends (OPFS / KVStore / Memory / Encrypted)
│       ├── locks.ts      # Web Locks multi-tab exclusive lock
│       └── compression/  # LZ4
├── hybrid/               # HybridEngine (write-through)
├── migration/            # Legacy IndexedDB migration tool (one-shot)
├── table/                # Table management & Schema validation
├── query/                # Query system
│   ├── ast.ts            # SQL AST type definitions
│   ├── builder.ts        # Chainable QueryBuilder API
│   ├── compiler.ts       # AST → QueryPlan compiler
│   ├── executor.ts       # QueryExecutor with JOIN/GROUP BY support
│   └── where-matcher.ts  # Unified WHERE matching logic
├── sql/                  # SQL parser
│   ├── tokens.ts         # Token types & keywords
│   ├── lexer.ts          # Tokenizer
│   ├── parser.ts         # Recursive descent parser
│   └── params.ts         # Parameter binding (? placeholders)
├── transaction/          # Transaction manager
├── plugin/               # Plugin system (14 lifecycle hooks)
└── integrations/         # React & Vue hooks

tests/                    # Test suite (1198 test cases, 74 suites + 12 e2e)
tests/helpers/             # 共享测试工具(OPFS mock 等)
tests/e2e/                # Playwright e2e(真实 Chromium + OPFS
site/                     # Documentation site (index / docs / demo)

Code Conventions

TypeScript

  • Strict mode is enabled — all code must pass tsc --noEmit.
  • Export types explicitly. Avoid any where possible.
  • Use interface for object shapes, type for unions/primitives.

Style

  • Run npm run format before committing (uses Prettier).
  • Follow existing comment patterns: JSDoc /** */ for public APIs, // for inline notes.
  • Keep functions focused and under ~60 lines where practical.

Testing

  • Every new feature must include tests.
  • Test files mirror source structure: src/foo.tstests/foo.test.ts.
  • Use descriptive test names: ('does X when Y').
  • Run the full suite before submitting: npm test.

Commits

  • Use conventional commit messages:
    • feat: add SQL GROUP BY support
    • fix: JOIN with multiple ON conditions
    • docs: update API reference
    • test: add edge case coverage
    • chore: optimize rollup dev build

Architecture

MetonaSqlark follows a layered architecture:

┌──────────────────────────────────────────────────┐
│         MetonaSqlark / MeSqlark (Public API)      │
├──────────────────────────────────────────────────┤
│  SQL Parser  │ QueryBuilder │ Transaction │ Plugin │
│  (Lexer→AST) │ (.select…)   │  Manager    │ System │
├──────────────────────────────────────────────────┤
│         QueryExecutor (AST → Results)             │
│    JOIN · GROUP BY · HAVING · DISTINCT · Agg     │
├──────────────────────────────────────────────────┤
│         IStorageEngine (Interface)                │
├─────────┬──────────┬──────────┬──────────────────┤
│ Memory  │ IndexedDB │ OPFS     │ Hybrid           │
│ Engine  │ Engine    │ Engine   │ Engine           │
└─────────┴──────────┴──────────┴──────────────────┘

Key Design Decisions

  1. AST as Universal Intermediate Representation: Both SQL strings and Query Builder produce the same AST, ensuring consistent behavior regardless of API used.

  2. Write-Through Hybrid Strategy: When using mode: 'hybrid', all writes go to both memory and disk simultaneously. Reads always hit memory for maximum speed.

  3. Plugin Hook Pipeline: 14 lifecycle hooks allow intercepting database operations without modifying core code.

  4. Hand-Written SQL Parser: No dependencies on parser generators — a recursive-descent parser keeps the bundle size minimal.

Building

# Production build (all formats)
npm run build

# Output in dist/
# ├── metona-sqlark.js        UMD
# ├── metona-sqlark.min.js    UMD minified (~105KB / ~27KB gzip)
# ├── metona-sqlark.esm.js    ES Module
# ├── metona-sqlark.cjs    CommonJS
# └── metona-sqlark.d.ts      TypeScript declarations

Plugin Development

Plugins follow a simple convention:

import type { MetonaPlugin } from '@metona-team/metona-sqlark';

const myPlugin: MetonaPlugin = {
  name: 'myPlugin',
  version: '1.0.0',
  description: 'Description of my plugin',
  priority: 50,  // higher = executed first

  install(db) {
    // Use db.on() to subscribe to hooks
    db.on('beforeInsert', async (rows) => {
      // Validate or transform data
    });
    db.on('afterQuery', async (sql, result) => {
      // Log or cache query results
    });
  },

  destroy() {
    // Clean up event listeners, timers, etc.
  },
};

// Register in config
const db = await MetonaSqlark.create({
  name: 'my-app',
  plugins: [myPlugin],
});

Available Lifecycle Hooks

Hook Trigger Parameters
beforeCreateTable Before table creation schema
afterCreateTable After table creation schema
beforeDropTable Before table drop tableName
afterDropTable After table drop tableName
beforeInsert Before row insert rows[]
afterInsert After row insert rows[]
beforeUpdate Before row update query, updates
afterUpdate After row update query, updates, count
beforeDelete Before row delete query
afterDelete After row delete query, count
beforeQuery Before SQL query sql
afterQuery After SQL query sql, result
beforeTransaction Before transaction -
afterTransaction After transaction -

Releasing

  1. Update version in package.json and src/constants.ts (VERSION constant).
  2. Update CHANGELOG.md.
  3. Run full test suite: npm test.
  4. Build: npm run build.
  5. Publish: npm publish.

Questions?

Open an issue at git.metona.cn/MetonaTeam/MetonaSqlark/issues.