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关联关系hasOnehasMany
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 定义,核心是理解 keyforeign 字段:

  • 关联条件关联模型.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
});