Skip to content

Latest commit

 

History

History
405 lines (320 loc) · 9.93 KB

File metadata and controls

405 lines (320 loc) · 9.93 KB

v1.0.5 变更详情

发布日期: 2026-01-08
主题: Schema 验证默认启用 + Model 自动加载机制


核心改进 ⚡

本次更新专注于提升 Model 层的易用性和开发体验。

1. Schema 验证默认启用 🔴

变更内容:

  • Schema 验证从"需要显式启用"改为"默认启用"
  • 提升数据质量,减少脏数据写入
  • 符合业界最佳实践(Mongoose、Sequelize 等默认启用)

使用示例:

// ✅ v1.0.5: Schema 验证默认生效
Model.define('users', {
    schema: (dsl) => dsl({
        username: 'string:3-32!',
        email: 'email!'
    })
    // 无需配置 options.validate,验证自动生效
});

// 插入时自动验证
await User.insertOne({
    username: 'ab',  // ❌ 验证失败: username 太短
    email: 'invalid'  // ❌ 验证失败: 邮箱格式错误
});
// 抛出 VALIDATION_ERROR

// ✅ 正确数据通过验证
await User.insertOne({
    username: 'john',
    email: 'john@example.com'
});

禁用验证:

// 全局禁用
Model.define('users', {
    schema: ...,
    options: { validate: false }  // 全局禁用验证
});

// 单次操作跳过
await User.insertOne(doc, { skipValidation: true });

影响范围:

  • ✅ 现有未定义 schema 的 Model 不受影响
  • ✅ 已定义 schema 的 Model 自动启用验证
  • ⚠️ 如需禁用,需显式配置 validate: false

迁移指南:

// v1.0.4: 验证需要显式启用
Model.define('users', {
    schema: ...,
    options: { validate: true }  // 需要配置
});

// v1.0.5: 验证默认启用
Model.define('users', {
    schema: ...
    // 无需配置,自动启用
});

// 如需禁用(兼容旧版本行为)
Model.define('users', {
    schema: ...,
    options: { validate: false }  // 显式禁用
});

风险评估: 🟡 低风险

  • ✅ 未定义 schema 的 Model 不受影响
  • ✅ 验证失败会抛出明确的错误,易于调试
  • ✅ 可通过配置或单次操作跳过验证

2. Model 自动加载机制 🚀

功能说明:

  • 自动扫描指定目录,加载所有 Model 定义文件
  • 支持多种文件格式:jstsmjscjs
  • 支持递归扫描子目录
  • 支持自定义文件名模式(glob 语法)

使用方式:

简化配置

const msq = new MonSQLize({
    type: 'mongodb',
    databaseName: 'mydb',
    config: { uri: '...' },
    models: './models'  // ← 简化配置,自动加载
});

await msq.connect();  // 自动扫描 models/*.model.{js,ts,mjs,cjs}

// 直接使用(无需手动 Model.define)
const User = msq.model('users');

完整配置

const msq = new MonSQLize({
    type: 'mongodb',
    databaseName: 'mydb',
    config: { uri: '...' },
    models: {
        path: './models',               // Model 文件目录
        pattern: '*.model.js',          // 文件名模式(支持 glob)
        recursive: true                 // 递归扫描子目录
    }
});

await msq.connect();

Model 文件格式:

// models/user.model.js
module.exports = {
    name: 'users',  // 集合名称(必需)
    
    schema: (dsl) => dsl({
        username: 'string:3-32!',
        email: 'email!'
    }),
    
    methods: (model) => ({
        instance: {
            checkPassword(password) {
                return this.password === password;
            }
        },
        static: {
            async findByUsername(username) {
                return await model.findOne({ username });
            }
        }
    }),
    
    hooks: (model) => ({
        insert: {
            before: async (ctx, doc) => {
                doc.createdAt = new Date();
                return doc;
            }
        }
    }),
    
    indexes: [
        { key: { username: 1 }, unique: true }
    ]
};

目录结构示例:

models/
├── user.model.js
├── post.model.js
├── comment.model.js
└── admin/
    ├── role.model.js
    └── permission.model.js

支持的文件格式:

  • .js - CommonJS
  • .mjs - ES Module
  • .cjs - CommonJS(显式)
  • .ts - TypeScript(需要 ts-node)

配置选项:

选项 类型 默认值 说明
path string - Model 文件目录(必需)
pattern string *.model.{js,ts,mjs,cjs} 文件名模式(支持 glob)
recursive boolean false 是否递归扫描子目录

错误处理:

目录不存在:
[Model] Models directory not found: /path/to/models

文件格式错误:
[Model] ❌ Failed to load models/invalid.model.js: export is null
[Model] ❌ Failed to load models/no-name.model.js: missing 'name' property

重复注册:
[Model] Model 'users' already registered, skipping models/user2.model.js

最佳实践:

  1. 统一命名规范: 使用 {name}.model.js 格式
  2. 按功能分组: 使用子目录组织(如 admin/public/
  3. 导出格式: 始终使用 module.exports = { name, ... }
  4. 测试环境: 可以禁用自动加载,手动注册测试 Model

注意事项:

  • ⚠️ 文件必须包含 name 属性
  • ⚠️ 重复的 Model 名称只会注册第一个
  • ⚠️ 文件语法错误会导致加载失败(记录日志,不中断)
  • ⚠️ TypeScript 文件需要运行时支持(ts-node 或编译后)

与手动注册对比:

方式 优点 缺点
手动注册 精确控制、显式依赖 重复代码、维护成本高
自动加载 自动发现、代码简洁 隐式依赖、加载顺序不确定

推荐: 生产环境使用自动加载,测试环境可选择手动注册。


3. 类型定义完善 ✅

新增类型:

  • BaseOptions.models - Model 自动加载配置

    interface BaseOptions {
        models?: string | {
            path: string;
            pattern?: string;
            recursive?: boolean;
        };
    }
  • ModelDefinition.options.validate - Schema 验证配置

    interface ModelDefinition {
        options?: {
            validate?: boolean;  // 默认 true
        };
    }

更新类型:

  • ✅ 完善 Model.define() 类型定义
  • ✅ 完善 msq.model() 返回类型

测试覆盖 ✅

新增测试用例(35个,100%通过)

Model 自动加载测试 (19个):

  • ✅ 简化配置(字符串路径)
  • ✅ 默认 pattern 验证
  • ✅ 不递归扫描(默认)
  • ✅ 自定义 pattern
  • ✅ 递归扫描
  • ✅ 多种文件格式(js/mjs/cjs)
  • ✅ 文件格式验证(缺少 name、空 name、null export)
  • ✅ 目录不存在处理
  • ✅ 文件加载失败处理
  • ✅ 防止重复注册
  • ✅ 无效配置处理
  • ✅ connect() 后可用
  • ✅ Schema 验证集成
  • ✅ 自定义方法支持
  • ✅ Hooks 支持
  • ✅ 日志输出验证

Schema 验证测试 (16个):

  • ✅ 默认启用验证
  • ✅ insertOne 时验证
  • ✅ insertMany 时逐个验证
  • ✅ 返回详细错误信息
  • ✅ 指示错误字段名
  • ✅ 指示错误类型
  • ✅ 批量插入错误索引
  • ✅ 全局禁用验证
  • ✅ 单次操作跳过验证
  • ✅ 跳过验证时仍执行 hooks
  • ✅ 未定义 schema 的 Model 无影响
  • ✅ v1.0.4 风格配置兼容
  • ✅ 可选字段正确处理
  • ✅ 性能影响测试(验证开销 <30%)
  • ✅ 嵌套对象验证
  • ✅ 数组验证

测试覆盖率

功能模块 测试数量 通过率 覆盖率
Model 自动加载 19 100% ~95%
Schema 验证 16 100% ~90%
总计 35 100% ~92%

文档完善 📖

新增文档

  1. docs/model.md - 更新(新增 1,700 字)

    • Model 自动加载章节
    • Schema 验证章节
    • 配置选项详解
    • 最佳实践
  2. examples/model/auto-load.js - Model 自动加载示例

    • 简化配置示例
    • 完整配置示例
    • Schema 验证示例
  3. examples/model/schema-validation.js - Schema 验证示例

    • 基本验证
    • 验证错误详情
    • 可选字段
    • 跳过验证
    • 嵌套对象验证
  4. examples/model/models/ - Model 定义文件示例

    • user.model.js - User Model 定义
    • post.model.js - Post Model 定义
    • admin/role.model.js - Role Model 定义(子目录)

更新文档

  1. README.md - 更新特性列表和使用示例
  2. index.d.ts - 完善 TypeScript 类型定义

后续计划 🗺️

测试完善(已完成 ✅)

  • ✅ 编写 Model 自动加载测试用例(19个)
  • ✅ 编写 Schema 验证默认启用测试(16个)
  • ✅ 验证现有测试兼容性

文档完善(已完成 ✅)

  • ✅ 更新 docs/model.md - 添加 Schema 验证章节
  • ✅ 更新 docs/model.md - 添加自动加载章节
  • ✅ 添加迁移指南

功能增强(计划中,v1.1.0)

  • 支持跨数据库 Model 操作
  • Model 层性能优化
  • 更多示例和最佳实践

使用建议 💡

推荐升级

推荐升级: ✅ 强烈推荐

升级命令:

npm install monsqlize@1.0.5

注意事项

  1. ✅ 如果你的 Model 已定义 schema,升级后会自动启用验证
  2. ✅ 如果验证失败,会抛出 VALIDATION_ERROR 错误
  3. ✅ 可通过 validate: false 禁用验证(不推荐)
  4. ✅ 可通过 models 配置启用自动加载,减少手动注册代码

最佳实践

Schema 验证:

  • ✅ 始终定义 schema,保证数据质量
  • ✅ 合理使用可选字段,避免过度严格
  • ✅ 使用 hooks 添加复杂验证逻辑
  • ✅ 捕获 VALIDATION_ERROR 返回友好错误

Model 自动加载:

  • ✅ 使用统一的文件命名规范(*.model.js
  • ✅ 按功能模块组织目录结构
  • ✅ 测试环境可手动注册,保持灵活性

获取帮助 💬


最后更新: 2026-01-08