Files
mcphub/docs/dao-layer.md
2025-08-27 15:21:30 +08:00

6.9 KiB
Raw Blame History

MCPHub DAO Layer 设计文档

概述

MCPHub的数据访问对象(DAO)层为项目中mcp_settings.json文件中的不同数据类型提供了统一的增删改查操作接口。这个设计使得未来从JSON文件存储切换到数据库存储变得更加容易。

架构设计

核心组件

src/dao/
├── base/
│   ├── BaseDao.ts          # 基础DAO接口和抽象实现
│   └── JsonFileBaseDao.ts  # JSON文件操作的基础类
├── UserDao.ts              # 用户数据访问对象
├── ServerDao.ts            # 服务器配置数据访问对象
├── GroupDao.ts             # 群组数据访问对象
├── SystemConfigDao.ts      # 系统配置数据访问对象
├── UserConfigDao.ts        # 用户配置数据访问对象
├── DaoFactory.ts           # DAO工厂类
├── examples.ts             # 使用示例
└── index.ts               # 统一导出

数据类型映射

数据类型 原始位置 DAO类 主要功能
IUser settings.users[] UserDao 用户管理、密码验证、权限控制
ServerConfig settings.mcpServers{} ServerDao 服务器配置、启用/禁用、工具管理
IGroup settings.groups[] GroupDao 群组管理、服务器分组、成员管理
SystemConfig settings.systemConfig SystemConfigDao 系统级配置、路由设置、安装配置
UserConfig settings.userConfigs{} UserConfigDao 用户个人配置

主要特性

1. 统一的CRUD接口

所有DAO都实现了基础的CRUD操作

interface BaseDao<T, K = string> {
  findAll(): Promise<T[]>;
  findById(id: K): Promise<T | null>;
  create(entity: Omit<T, 'id'>): Promise<T>;
  update(id: K, entity: Partial<T>): Promise<T | null>;
  delete(id: K): Promise<boolean>;
  exists(id: K): Promise<boolean>;
  count(): Promise<number>;
}

2. 特定业务操作

每个DAO还提供了针对其数据类型的特定操作

UserDao 特殊功能

  • createWithHashedPassword() - 创建用户时自动哈希密码
  • validateCredentials() - 验证用户凭据
  • updatePassword() - 更新用户密码
  • findAdmins() - 查找管理员用户

ServerDao 特殊功能

  • findByOwner() - 按所有者查找服务器
  • findEnabled() - 查找启用的服务器
  • findByType() - 按类型查找服务器
  • setEnabled() - 启用/禁用服务器
  • updateTools() - 更新服务器工具配置

GroupDao 特殊功能

  • findByOwner() - 按所有者查找群组
  • findByServer() - 查找包含特定服务器的群组
  • addServerToGroup() - 向群组添加服务器
  • removeServerFromGroup() - 从群组移除服务器
  • findByName() - 按名称查找群组

3. 配置管理特殊功能

SystemConfigDao

  • getSection() - 获取特定配置段
  • updateSection() - 更新特定配置段
  • reset() - 重置为默认配置

UserConfigDao

  • getSection() - 获取用户特定配置段
  • updateSection() - 更新用户特定配置段
  • getAll() - 获取所有用户配置

使用方法

1. 基本使用

import { getUserDao, getServerDao, getGroupDao } from './dao/index.js';

// 用户操作
const userDao = getUserDao();
const newUser = await userDao.createWithHashedPassword('username', 'password', false);
const user = await userDao.findByUsername('username');
const isValid = await userDao.validateCredentials('username', 'password');

// 服务器操作
const serverDao = getServerDao();
const server = await serverDao.create({
  name: 'my-server',
  command: 'node',
  args: ['server.js'],
  enabled: true
});

// 群组操作
const groupDao = getGroupDao();
const group = await groupDao.create({
  name: 'my-group',
  description: 'Test group',
  servers: ['my-server']
});

2. 配置服务集成

import { DaoConfigService, createDaoConfigService } from './config/DaoConfigService.js';

const daoService = createDaoConfigService();

// 加载完整配置
const settings = await daoService.loadSettings();

// 保存配置
await daoService.saveSettings(updatedSettings);

3. 迁移管理

import { migrateToDao, switchToDao, switchToLegacy } from './config/configManager.js';

// 迁移到DAO层
const success = await migrateToDao();

// 运行时切换
switchToDao();      // 切换到DAO层
switchToLegacy();   // 切换回传统方式

配置选项

可以通过环境变量控制使用哪种数据访问方式:

# 使用DAO层 (推荐)
USE_DAO_LAYER=true

# 使用传统文件方式 (默认,向后兼容)
USE_DAO_LAYER=false

未来扩展

数据库支持

DAO层的设计使得切换到数据库变得容易只需要

  1. 实现新的DAO实现类如DatabaseUserDao
  2. 创建新的DaoFactory
  3. 更新配置以使用新的工厂
// 未来的数据库实现示例
class DatabaseUserDao implements UserDao {
  constructor(private db: Database) {}
  
  async findAll(): Promise<IUser[]> {
    return this.db.query('SELECT * FROM users');
  }
  
  // ... 其他方法
}

新数据类型

添加新数据类型只需要:

  1. 定义数据接口
  2. 创建对应的DAO接口和实现
  3. 更新DaoFactory
  4. 更新配置服务

迁移指南

从传统方式迁移到DAO层

  1. 备份数据
cp mcp_settings.json mcp_settings.json.backup
  1. 运行迁移
import { performMigration } from './config/migrationUtils.js';
await performMigration();
  1. 验证迁移
import { validateMigration } from './config/migrationUtils.js';
const isValid = await validateMigration();
  1. 切换到DAO层
export USE_DAO_LAYER=true

性能对比

可以使用内置工具对比性能:

import { performanceComparison } from './config/migrationUtils.js';
await performanceComparison();

最佳实践

  1. 类型安全: 始终使用TypeScript接口确保类型安全
  2. 错误处理: 在DAO操作周围实现适当的错误处理
  3. 事务: 对于复杂操作,考虑使用事务(未来数据库实现)
  4. 缓存: DAO层包含内置缓存机制
  5. 测试: 使用DAO接口进行单元测试的模拟

示例代码

查看以下文件获取完整示例:

  • src/dao/examples.ts - 基本DAO操作示例
  • src/config/migrationUtils.ts - 迁移和验证工具
  • src/scripts/dao-demo.ts - 交互式演示脚本

总结

DAO层为MCPHub提供了

  • 🏗️ 模块化设计: 每种数据类型都有专门的访问层
  • 🔄 易于迁移: 为未来切换到数据库做好准备
  • 🧪 可测试性: 接口可以轻松模拟和测试
  • 🔒 类型安全: 完整的TypeScript类型支持
  • 性能优化: 内置缓存和批量操作支持
  • 🛡️ 数据完整性: 强制数据验证和约束

通过引入DAO层MCPHub的数据管理变得更加结构化、可维护和可扩展。