Skip to content

Yao 模型定义指南 ​

概述 ​

Yao 模型是定义业务数据结构的基础组件,支持数据结构描述、验证规则、数据库表配置、模型关系和业务规则设置。

文件结构与命名 ​

文件位置:models/ 目录下 文件格式:.mod.yao、.mod.jsonc、.mod.json(推荐 .mod.yao) 命名规则:

  • 使用小写字母,复杂名称用目录分层
  • user.mod.yao → 模型标识:user
  • my/name.mod.yao → 模型标识:my.name
  • auto/car.mod.yao → 模型标识:auto.car

文件格式:JSON 格式,.jsonc 和 .yao 支持注释

模型结构示例 ​

json
{
  "name": "用户",
  "table": { "name": "admin_user", "comment": "用户表", "engine": "InnoDB" },
  "columns": [
    { "label": "ID", "name": "id", "type": "ID" },
    {
      "label": "类型",
      "name": "type",
      "type": "enum",
      "option": ["super", "admin", "staff", "user", "robot"],
      "default": "user",
      "validations": [
        {
          "method": "typeof",
          "args": ["string"],
          "message": "{{input}}类型错误"
        },
        {
          "method": "enum",
          "args": ["super", "admin", "staff", "user", "robot"],
          "message": "{{input}}不在许可范围"
        }
      ]
    }
  ],
  "relations": {},
  "values": [],
  "option": { "timestamps": true, "soft_deletes": true }
}

模型组成部分 ​

部分说明示例
name模型名称"用户"
table数据表配置{"name": "users", "engine": "InnoDB"}
columns字段定义字段类型、验证规则、索引等
indexes索引定义提高查询效率
relations关联关系hasOne、hasMany 等
values默认数据初始化数据记录
option配置选项时间戳、软删除等

字段定义 ​

字段属性配置 ​

字段名类型必填说明示例
namestring✓数据库列名"username"
labelstring✓显示名称"用户名"
typestring✓字段类型"string"
commentstring-数据库注释"用户名,唯一标识"
lengthnumber-字段长度255
precisionnumber-数字精度10
scalenumber-小数位数2
nullableboolean-允许为空true
defaultany-默认值"guest"
default_rawstring-数据库函数默认值"NOW()"
generatestring-自动生成类型"UUID"
cryptstring-加密方式"AES"
indexboolean-创建索引true
uniqueboolean-唯一约束true
primaryboolean-主键true
optionarray-枚举选项["A", "B", "C"]

字段类型 ​

分类类型说明示例
字符串string可变长度字符串(默认200){"type": "string", "length": 100}
char固定长度字符串{"type": "char", "length": 2}
text普通文本(65KB){"type": "text"}
mediumText中等文本(16MB){"type": "mediumText"}
longText长文本(4GB){"type": "longText"}
数字tinyInteger-128到127{"type": "tinyInteger"}
integer-2B到2B{"type": "integer"}
bigInteger-9E到9E{"type": "bigInteger"}
decimal高精度小数{"type": "decimal", "precision": 10, "scale": 2}
日期时间date日期(YYYY-MM-DD){"type": "date"}
datetime日期时间{"type": "datetime"}
timestamp时间戳{"type": "timestamp"}
其他boolean布尔值{"type": "boolean"}
jsonJSON数据{"type": "json"}
uuid唯一标识符{"type": "uuid"}
enum枚举类型{"type": "enum", "option": ["A", "B"]}

高级字段配置 ​

默认值设置 ​

json
// 静态默认值
{"name": "status", "type": "string", "default": "active"}

// 数据库函数默认值
{"name": "created_at", "type": "datetime", "default_raw": "NOW()"}

// 自动生成值
{"name": "uuid", "type": "string", "generate": "UUID"}

字段加密 ​

json
{
  "name": "password",
  "type": "string",
  "crypt": "AES", // AES(仅MySQL) 或 PASSWORD(哈希)
  "comment": "加密存储的密码"
}

索引配置 ​

json
// 普通索引
{"name": "email", "type": "string", "index": true}

// 唯一索引
{"name": "username", "type": "string", "unique": true}

// 复合索引(在模型根级配置)
{
  "indexes": [
    {
      "name": "idx_user_status",
      "columns": ["user_id", "status"],
      "unique": false
    }
  ]
}

字段验证 ​

验证方法 ​

方法说明参数示例
typeof类型验证类型名{"method": "typeof", "args": ["string"]}
min/max数值范围数值{"method": "min", "args": [18]}
minLength/maxLength长度范围长度{"method": "minLength", "args": [6]}
enum枚举验证选项数组{"method": "enum", "args": ["A", "B"]}
pattern正则匹配正则表达式{"method": "pattern", "args": ["[A-Z]+"]}
email邮箱格式无{"method": "email"}
mobile手机号格式无{"method": "mobile"}

验证示例 ​

json
{
  "name": "password",
  "type": "string",
  "validations": [
    { "method": "minLength", "args": [8], "message": "密码至少8个字符" },
    { "method": "pattern", "args": ["[A-Z]+"], "message": "必须包含大写字母" }
  ]
}

常用验证规则示例 ​

json
// 用户名验证
{
  "name": "name", "type": "string", "length": 80,
  "validations": [
    {"method": "typeof", "args": ["string"], "message": "{{label}}应该为字符串"},
    {"method": "minLength", "args": [2], "message": "{{label}}至少需要2个字"},
    {"method": "maxLength", "args": [40], "message": "{{label}}不能超过20个字"}
  ]
}

// 密码验证
{
  "name": "password", "type": "string", "crypt": "PASSWORD",
  "validations": [
    {"method": "minLength", "args": [6], "message": "密码6-18位"},
    {"method": "maxLength", "args": [18], "message": "密码6-18位"},
    {"method": "pattern", "args": ["[0-9]+"], "message": "至少包含一个数字"},
    {"method": "pattern", "args": ["[A-Z]+"], "message": "至少包含一个大写字母"},
    {"method": "pattern", "args": ["[a-z]+"], "message": "至少包含一个小写字母"}
  ]
}

// 常用正则模式
{"method": "pattern", "args": ["^(\\d{18})|(\\d{14}X)$"], "message": "身份证格式错误"}
{"method": "pattern", "args": ["^[0-9A-Za-z@#$&*]{8}$"], "message": "8位字母数字符号组合"}

模型关联关系 ​

关联关系原理 ​

关联关系通过 relations 定义,核心是理解 key 和 foreign 字段:

  • 关联条件:关联模型.key = 当前模型.foreign

关联类型 ​

类型说明示例场景
hasOne一对一用户 → 个人资料
hasMany一对多用户 → 多个订单
belongsTo属于订单 → 用户
hasOneThrough通过中间表的一对一用户 → 通过订单 → 最新地址

关联定义示例 ​

json
// User 模型
{
  "relations": {
    "profile": {
      "key": "user_id", // profile表的user_id字段
      "foreign": "id", // 当前user表的id字段
      "model": "profile",
      "type": "hasOne" // user.id = profile.user_id
    },
    "orders": {
      "key": "user_id", // order表的user_id字段
      "foreign": "id", // 当前user表的id字段
      "model": "order",
      "type": "hasMany" // user.id = order.user_id (多条)
    }
  }
}

关联查询使用 ​

bash
# 查询用户及其关联数据
yao run models.user.Find 1 '::{"withs":{"profile":{}, "orders":{}}}'

关联关系实例 ​

json
// 一对一:用户 → 个人资料
{
  "profile": {
    "key": "user_id",        // profile.user_id
    "foreign": "id",         // user.id
    "model": "profile",
    "type": "hasOne"         // user.id = profile.user_id
  }
}

// 一对多:用户 → 订单
{
  "orders": {
    "key": "user_id",        // order.user_id
    "foreign": "id",         // user.id
    "model": "order",
    "type": "hasMany"        // user.id = order.user_id (多条)
  }
}

// 非主键关联:通过app_id关联
{
  "apps": {
    "key": "app_id",         // supplier.app_id
    "foreign": "app_id",     // user.app_id
    "model": "supplier",
    "type": "hasMany"        // user.app_id = supplier.app_id
  }
}

模型迁移与配置 ​

迁移命令 ​

命令说明
yao migrate执行所有未应用的迁移
yao migrate --reset重置所有表后再执行
yao migrate -n model --reset指定模型进行变更

配置选项 ​

选项说明示例
timestamps自动时间戳"timestamps": true
soft_deletes软删除"soft_deletes": true
engine数据库引擎"engine": "InnoDB"
charset字符集"charset": "utf8mb4"

最佳实践 ​

命名规范 ​

  • 使用小写字母和下划线
  • 保持命名一致性(如 created_at)
  • 避免使用数据库保留字

字段设计 ​

  • 为字段添加注释(comment)
  • 合理设置字段长度
  • 使用合适的字段类型(enum 代替字符串)
  • 为常用查询字段添加索引

安全性 ​

  • 敏感字段使用加密(crypt)
  • 设置强验证规则
  • 限制字段长度防止溢出

性能优化 ​

  • 避免过度索引
  • 合理使用默认值
  • 考虑数据分区

模型处理器 ​

模型定义后,Yao 自动生成 CRUD 处理器,命名规则:models.<模型ID>.<方法名>

处理器列表 ​

处理器参数返回值说明
查询
Find主键值, 查询条件单条记录根据主键查询
Get查询条件记录数组条件查询,不分页
Paginate查询条件, 页码, 每页数量分页对象条件查询,分页
创建
Create记录对象主键值创建单条记录
Insert字段数组, 值数组插入行数批量插入
更新
Update主键值, 记录对象null更新单条记录
UpdateWhere查询条件, 记录对象更新行数条件更新
Save记录对象主键值创建或更新
EachSave记录数组, 共有字段主键数组批量保存
删除
Delete主键值null软删除单条
DeleteWhere查询条件删除行数条件软删除
Destroy主键值null真删除单条
DestroyWhere查询条件删除行数条件真删除

查询条件参数 ​

QueryParam 主要参数 ​

参数类型说明
selectstring[]选择字段列表
wheresQueryWhere[]查询条件
ordersQueryOrder[]排序条件
limitnumber限制记录数
pagenumber当前页码
pagesizenumber每页记录数
withsobject关联查询

QueryWhere 查询条件 ​

参数说明示例
column字段名"name"
value匹配值"张三"
method查询方法"where", "orwhere"
op匹配关系"eq", "like", "gt", "in"

匹配关系说明 ​

op说明SQL示例
eq等于WHERE field = value
like模糊匹配WHERE field LIKE value
gt/ge大于/大于等于WHERE field > value
lt/le小于/小于等于WHERE field < value
in包含WHERE field IN (values)
null/notnull空值判断WHERE field IS NULL

CRUD 操作示例 ​

创建数据 ​

js
// 创建单条记录
const id = Process('models.user.create', {
  name: '张三',
  email: 'zhang@example.com'
});

// 批量插入
const data = [
  { name: '李四', email: 'li@example.com' },
  { name: '王五', email: 'wang@example.com' }
];
const { columns, values } = Process('utils.arr.split', data);
const count = Process('models.user.insert', columns, values);

更新数据 ​

js
// 根据主键更新
Process('models.user.update', 1, { name: '张三三' });

// 条件更新
const count = Process(
  'models.user.updatewhere',
  { wheres: [{ column: 'status', value: 'inactive' }] },
  { status: 'active' }
);

// 保存(创建或更新)
const id = Process('models.user.save', {
  id: 1, // 有id则更新,无id则创建
  name: '张三'
});

// 批量保存
const ids = Process(
  'models.user.EachSave',
  [{ id: 1, name: '张三' }, { name: '李四' }], // 数据数组
  { status: 'active' } // 共有字段
);

删除数据 ​

js
// 软删除(如果启用了 soft_deletes)
Process('models.user.delete', 1);

// 条件软删除
const count = Process('models.user.deletewhere', {
  wheres: [{ column: 'status', value: 'inactive' }]
});

// 真删除
Process('models.user.destroy', 1);

// 条件真删除
const count = Process('models.user.destroywhere', {
  wheres: [{ column: 'created_at', op: 'lt', value: '2023-01-01' }]
});

查询数据 ​

js
// 根据主键查询单条记录
const user = Process('models.user.find', 1, {
  withs: { profile: {}, orders: {} } // 关联查询
});

// 条件查询(返回数组)
const users = Process('models.user.get', {
  select: ['id', 'name', 'email'],
  wheres: [
    { column: 'status', value: 'active' },
    { column: 'created_at', op: 'ge', value: '2024-01-01' }
  ],
  orders: [{ column: 'created_at', option: 'desc' }],
  limit: 10
});

// 分页查询
const result = Process(
  'models.user.paginate',
  {
    wheres: [{ column: 'status', value: 'active' }],
    orders: [{ column: 'id', option: 'desc' }]
  },
  1, // 页码
  20 // 每页数量
);
// 返回: { data: [], total: 100, page: 1, pagesize: 20, ... }

// 获取单条记录的简便方法
const [user] = Process('models.user.get', {
  wheres: [{ column: 'email', value: 'user@example.com' }],
  limit: 1
});