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

220 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```bash
git clone https://git.metona.cn/MetonaTeam/MetonaSqlark.git
cd MetonaSqlark
npm install
```
## Development
```bash
# 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.ts``tests/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
```bash
# 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:
```typescript
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](https://git.metona.cn/MetonaTeam/MetonaSqlark/issues).