UNPKG

dbshift

Version:

A simple and powerful MySQL database migration tool inspired by Flyway

478 lines (404 loc) 14.5 kB
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview DBShift 是一个现代化的 MySQL 数据库迁移工具,灵感来自 Flyway。项目采用创新的双模式架构:交互模式(基于 React + Ink)和 CLI 模式(基于 Commander.js),为不同使用场景提供最佳的用户体验。 ### 核心特性 - 🎯 **双模式架构**: 交互模式(React + Ink 终端 UI)+ CLI 模式(Commander.js) -**React 交互界面**: 基于 Ink 的现代终端用户界面,支持对话框和实时反馈 - 🔄 **统一错误处理**: ErrorHandler 提供一致的错误处理机制 - 🔢 **作者分组序号**: 每个开发者独立的序号系统,避免团队协作冲突 - 📜 **丰富历史功能**: 详细的迁移执行历史,支持按作者过滤和多环境查看 - ⚙️ **灵活配置管理**: 支持 .env 和 schema.config.js 两种配置方式 - 🏓 **连接测试**: ping 命令快速测试数据库连接,支持临时参数和多环境 - 🌍 **多环境支持**: development, staging, production 环境隔离 ## 技术架构 ### 技术栈 - **交互 UI**: React (^17.0.2) + Ink (^3.2.0) - 现代终端 UI 框架 - **CLI**: Commander.js (^14.0.0) - 命令行参数解析和路由 - **数据库**: MySQL2 (^3.11.0) - Promise-based MySQL 驱动 - **用户交互**: Inquirer (^8.2.6) - 对话框和表单交互 - **样式**: Chalk (4.1.2) - 终端颜色输出 - **配置**: dotenv (^16.0.1) - 环境变量管理 - **测试**: Jest (^30.0.2) - 测试框架 - **编译**: Babel - React/JSX 支持 ### 项目结构 ``` dbshift/ ├── bin/ │ └── dbshift.js # 主入口(双模式路由器) ├── lib/ │ ├── cli/ │ │ └── CLIRunner.js # CLI 模式命令路由器 │ ├── commands/ # 业务命令处理器 │ │ ├── config/ # 配置管理命令组 │ │ │ ├── index.js # 显示当前配置 │ │ │ ├── init.js # 交互式配置初始化 │ │ │ └── set.js # 命令行配置设置 │ │ ├── create.js # 创建迁移文件 │ │ ├── history.js # 历史记录查看 │ │ ├── init.js # 项目初始化 │ │ ├── migrate.js # 执行迁移 │ │ ├── status.js # 迁移状态检查 │ │ └── test-connection.js # 数据库连接测试 │ ├── core/ # 核心业务模块 │ │ ├── config.js # 配置管理和加载 │ │ ├── database.js # 数据库连接和 SQL 执行 │ │ └── migration.js # 迁移文件管理和执行逻辑 │ ├── templates/ # 文件模板 │ │ ├── migration.sql # 迁移文件模板 │ │ └── schema.config.js # 配置文件模板 │ ├── ui/ # React + Ink 交互界面 │ │ ├── InteractiveApp.js # 主交互应用组件 │ │ ├── components/ # React UI 组件 │ │ │ ├── Layout.js # 布局组件(Logo、输入框等) │ │ │ └── dialogs/ # 对话框组件 │ │ │ ├── ConfigDialog.js │ │ │ ├── ConfigInitDialog.js │ │ │ ├── ConfigSetDialog.js │ │ │ ├── CreateDialog.js │ │ │ └── InitDialog.js │ │ ├── hooks/ # React Hooks │ │ │ ├── useCommandHistory.js # 命令历史管理 │ │ │ └── useProjectStatus.js # 项目状态管理 │ │ └── utils/ │ │ └── CommandProcessor.js # 命令处理逻辑 │ └── utils/ # 工具类库 │ ├── connectionTester.js # 数据库连接测试工具 │ ├── errorHandler.js # 统一错误处理机制 │ ├── errors.js # 自定义错误类定义 │ ├── fileUtils.js # 文件操作和序号生成 │ ├── logger.js # 彩色日志输出 │ ├── progress.js # 进度指示器 │ └── validator.js # 输入验证 ``` ## 核心架构设计 ### 双模式入口设计 #### 主入口 (`bin/dbshift.js`) ```javascript // 命令行参数检测 if (args.includes('-p')) { // CLI 模式:dbshift -p -- command args executeCommandLine(command); } else { // 交互模式:React + Ink 应用 startInteractiveMode(); } ``` **路由逻辑**: - **交互模式**: 直接启动 `startInteractiveMode()` - React + Ink 应用 - **CLI 模式**: 通过 `-p --` 参数触发 `executeCommandLine()` - Commander.js 处理 - **帮助模式**: `-h``--help` 显示使用说明 #### 交互模式 (`lib/ui/InteractiveApp.js`) ```javascript // React + Ink 应用架构 function startInteractiveMode() { // TTY 检查和环境初始化 // 渲染主 React 组件 render(<DBShiftApp />); } // 主应用组件 function DBShiftApp() { // useState hooks 管理应用状态 // useInput hook 处理用户输入 // 对话框状态管理 // 命令执行和反馈显示 } ``` **特性**: - **React 组件架构**: 使用 useState、useEffect 等 Hooks - **对话框系统**: 复杂命令使用专门的对话框组件 - **实时反馈**: Ink 提供的终端 UI 更新 - **TTY 检测**: 自动回退到 CLI 模式(非终端环境) #### CLI 模式 (`lib/cli/CLIRunner.js`) ```javascript // Commander.js 程序配置 function executeCommandLine(command) { const { program } = require('commander'); // 注册所有命令 program.command('init').action(initCommand); program.command('create <name>').action(createCommand); program.command('migrate').action(migrateCommand); // ...其他命令 // 解析和执行 program.parse(['node', 'dbshift', ...commandArgs]); } ``` **特性**: - **Commander.js 路由**: 标准的 CLI 命令解析 - **参数验证**: 自动处理必需参数和选项 - **批处理友好**: 适合脚本和 CI/CD 环境 - **错误退出**: 失败时正确设置退出码 ### 配置管理系统 #### 配置加载策略 (`lib/core/config.js`) ```javascript class Config { static getCurrentConfig(env = 'development') { // 1. 优先加载 schema.config.js(多环境) if (FileUtils.exists('schema.config.js')) { const config = require('./schema.config.js'); return config[env] || config; } // 2. 回退到 .env 文件(简单配置) if (FileUtils.exists('.env')) { dotenv.config(); return extractFromEnv(); } // 3. 使用环境变量(生产环境) return extractFromEnv(); } } ``` **配置格式支持**: 1. **schema.config.js** - 多环境配置 ```javascript module.exports = { development: { host: 'localhost', port: 3306, user: 'root', password: 'dev', database: 'myapp_dev' }, production: { host: 'prod-host', port: 3306, user: 'root', password: 'prod', database: 'myapp_prod' } }; ``` 2. **.env** - 简单配置 ```env MYSQL_HOST=localhost MYSQL_PORT=3306 MYSQL_USERNAME=root MYSQL_PASSWORD=password MYSQL_DATABASE=myapp ``` ### 迁移文件管理 #### 文件命名系统 (`lib/utils/fileUtils.js`) ``` 格式: YYYYMMDDNN_Author_description.sql 示例: 20250714001_Greddy_create_users_table.sql ``` **作者分组序号机制**: ```javascript // 每个作者独立序号,避免冲突 generateSequence(dir, date, author) { // 1. 扫描同日期、同作者的文件 // 2. 解析序号,找出最大值 // 3. 返回 max + 1 } // 示例:同一天不同作者可用相同序号 20250714001_Alice_feature_a.sql // Alice 的第 1 个 20250714001_Bob_feature_b.sql // Bob 的第 1 个(无冲突) 20250714002_Alice_feature_c.sql // Alice 的第 2 个 ``` #### 迁移模板系统 (`lib/templates/migration.sql`) ```sql -- Migration: {{DESCRIPTION}} -- Author: {{AUTHOR}} -- Created: {{DATE}} -- Version: {{VERSION}} -- Create database if it doesn't exist CREATE DATABASE IF NOT EXISTS `{{DATABASE_NAME}}` DEFAULT CHARACTER SET utf8mb4; USE `{{DATABASE_NAME}}`; -- Add your SQL statements here -- 支持标准 SQL 语法和注释 ``` ### 数据库架构 #### 迁移历史表 ```sql CREATE TABLE `dbshift`.`migration_history` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `version` varchar(20) NOT NULL COMMENT '版本号', `author` varchar(20) NOT NULL COMMENT '作者', `file_desc` varchar(100) NOT NULL COMMENT '文件描述', `file_name` varchar(200) NOT NULL COMMENT '文件名', `status` tinyint(1) DEFAULT '0' COMMENT '0=待执行, 1=已完成', `create_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `modify_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_version_author` (`version`, `author`) ); ``` **失败重试机制**: - 唯一约束 `(version, author)` 防止重复记录 - 失败时 `status=0`,可重新执行 - 成功时更新 `status=1``modify_date` ### 错误处理系统 #### 统一错误处理 (`lib/utils/errorHandler.js`) ```javascript class ErrorHandler { static async executeWithErrorHandling(fn) { try { await fn(); // 交互模式:不退出进程 if (!process.env.DBSHIFT_INTERACTIVE_MODE) { process.exit(0); } } catch (error) { const exitCode = this.handle(error); if (!process.env.DBSHIFT_INTERACTIVE_MODE) { process.exit(exitCode); // CLI 模式:退出进程 } else { throw error; // 交互模式:抛出给 React 处理 } } } } ``` **模式区分**: - **CLI 模式**: 错误时 `process.exit()` 设置正确退出码 - **交互模式**: 错误时抛出异常,由 React 组件捕获并显示 ## 开发指南 ### 本地开发测试 ```bash # 交互模式开发测试 node bin/dbshift.js # CLI 模式开发测试 node bin/dbshift.js -p -- init node bin/dbshift.js -p -- create "test_migration" --author="developer" node bin/dbshift.js -p -- migrate node bin/dbshift.js -p -- status node bin/dbshift.js -p -- history node bin/dbshift.js -p -- config node bin/dbshift.js -p -- ping ``` ### 全局安装测试 ```bash npm link # 链接到全局 dbshift # 测试交互模式 dbshift -p -- status # 测试 CLI 模式 npm unlink -g dbshift # 取消链接 ``` ### 关键开发要点 #### 1. 添加新命令 ```javascript // 1. 创建命令处理器: lib/commands/newcommand.js async function newCommand(options) { await ErrorHandler.executeWithErrorHandling(async () => { // 命令逻辑实现 }); } // 2. 注册 CLI 路由: lib/cli/CLIRunner.js program .command('newcommand') .description('Command description') .action(newCommand); // 3. 添加交互模式支持: lib/ui/InteractiveApp.js // 在对话框或命令处理中集成 ``` #### 2. React 组件开发 ```javascript // 使用 Ink 组件和 React Hooks const { Box, Text, useInput } = require('ink'); const { useState, useEffect } = require('react'); function NewDialog({ onSubmit, onCancel }) { const [input, setInput] = useState(''); useInput((input, key) => { if (key.return) { onSubmit(input); } if (key.escape) { onCancel(); } }); return ( <Box flexDirection="column"> <Text>Input something:</Text> <Text>{input}</Text> </Box> ); } ``` #### 3. 配置扩展 ```javascript // 在 lib/core/config.js 中扩展配置加载 static getCurrentConfig(env) { // 添加新的配置格式支持 if (FileUtils.exists('newconfig.json')) { return JSON.parse(fs.readFileSync('newconfig.json')); } // 现有逻辑... } ``` ## 用户使用指南 ### 交互模式使用 ```bash # 启动交互模式 dbshift # 主要功能 - 项目初始化对话框 - 创建迁移文件向导 - 配置管理界面 - 实时状态显示 - 错误反馈和重试 ``` **交互模式特性**: - **对话框驱动**: 复杂操作通过表单对话框引导 - **实时反馈**: 命令执行状态实时更新 - **错误恢复**: 错误后自动返回主界面 - **键盘导航**: ESC 取消,回车确认,箭头键选择 ### CLI 模式使用 ```bash # 基本命令格式 dbshift -p -- <command> [options] # 项目管理 dbshift -p -- init dbshift -p -- create "create_users_table" --author=john dbshift -p -- create "add_email_index" -a john # 迁移操作 dbshift -p -- migrate dbshift -p -- migrate -e production dbshift -p -- status dbshift -p -- status -e staging # 历史查看 dbshift -p -- history dbshift -p -- history --author=john dbshift -p -- history -e production # 配置管理 dbshift -p -- config dbshift -p -- config-init dbshift -p -- config-set --host=localhost --user=root --password=123456 # 连接测试 dbshift -p -- ping dbshift -p -- ping -e production dbshift -p -- ping --host=localhost --user=root --password=123456 ``` ## 测试和部署 ### 测试命令 ```bash npm test # 运行 Jest 测试套件 npm run test:watch # 监视模式测试 npm run test:coverage # 生成覆盖率报告 ``` ### NPM 脚本 ```bash npm start # 启动交互模式 npm run cli # 测试 CLI 模式 npm run dev # 开发模式 npm run demo # 演示命令 ``` ### 部署配置 ```json { "bin": { "dbshift": "bin/dbshift.js" }, "engines": { "node": ">=14.0.0" } } ``` ## SQL 迁移文件编写 ### 标准模板结构 - **元数据注释**: 描述、作者、日期、版本 - **数据库创建**: CREATE DATABASE IF NOT EXISTS - **表结构定义**: CREATE TABLE、ALTER TABLE - **索引管理**: CREATE INDEX、DROP INDEX - **数据操作**: INSERT、UPDATE(谨慎使用) ### 最佳实践 1. **幂等性**: 使用 `IF NOT EXISTS``IF EXISTS` 语句 2. **单一职责**: 每个文件只处理一个功能或表 3. **向前兼容**: 避免破坏性更改 4. **备份策略**: 重要数据变更前备份 --- 这份重写的文档准确反映了当前代码架构,特别是 React + Ink 交互模式和 Commander.js CLI 模式的双模式设计。