Schema 定义
Schema 是 Sleet ORM 的核心概念,它定义了数据库表的结构。本节将详细介绍如何定义和使用 Schema。
基本概念
在 Sleet 中,Schema 使用 sl.table() 函数定义,它接受表名和列定义对象:
lua
local sl = Sleet
local tableName = sl.table('table_name', {
-- 列定义
column1 = sl.columnType().modifiers(),
column2 = sl.columnType().modifiers(),
-- ...
})表定义
基本表定义
lua
-- server/schema.lua
local sl = Sleet
-- 定义玩家表
local players = sl.table('players', {
id = sl.serial().primaryKey().comment('主键ID'),
name = sl.varchar(255).notNull().comment('玩家名称'),
email = sl.varchar(100).unique().comment('邮箱地址')
})
-- 导出供其他模块使用
return { players = players }复杂表定义
lua
local players = sl.table('players', {
-- 主键
id = sl.serial().primaryKey().comment('玩家唯一标识'),
-- 标识符
identifier = sl.varchar(64).notNull().unique().comment('Steam/Discord ID'),
license = sl.char(40).unique().comment('FiveM License'),
-- 基本信息
name = sl.varchar(255).notNull().comment('显示名称'),
age = sl.tinyint().comment('年龄'),
gender = sl.varchar(10).default('unknown').comment('性别'),
-- 金钱系统
money = sl.decimal(10, 2).default(1000.00).comment('现金'),
bank = sl.decimal(12, 2).default(5000.00).comment('银行余额'),
-- 状态标志
is_active = sl.boolean().default(true).comment('账户激活状态'),
is_admin = sl.boolean().default(false).comment('管理员权限'),
is_banned = sl.boolean().default(false).comment('封禁状态'),
-- 扩展数据
metadata = sl.json().comment('扩展元数据'),
settings = sl.json().comment('用户设置'),
-- 时间戳
created_at = sl.timestamp().defaultNow().comment('创建时间'),
updated_at = sl.timestamp().defaultNow().onUpdate(sl.sql('NOW()')).comment('更新时间'),
last_seen = sl.timestamp().comment('最后登录时间'),
-- 软删除
deleted_at = sl.timestamp().softDelete().comment('删除时间戳')
})列类型
数值类型
lua
-- 整数类型
id = sl.serial().primaryKey() -- 自增主键
user_id = sl.int().notNull() -- 标准整数
experience = sl.bigint().default(0) -- 大整数
level = sl.smallint().default(1) -- 小整数
status = sl.tinyint().default(0) -- 微整数
-- 浮点类型
rating = sl.float() -- 单精度浮点
coordinates_x = sl.double() -- 双精度浮点
price = sl.decimal(10, 2) -- 定点数(推荐用于货币)字符串类型
lua
-- 变长字符串
name = sl.varchar(255).notNull() -- 变长字符串
title = sl.varchar(100) -- 较短的变长字符串
-- 定长字符串
country_code = sl.char(2) -- 定长字符串
license_plate = sl.char(8) -- 车牌号等
-- 文本类型
description = sl.text() -- 文本
bio = sl.mediumtext() -- 中等文本
log_content = sl.longtext() -- 长文本时间类型
lua
-- 时间戳(推荐)
created_at = sl.timestamp().defaultNow()
updated_at = sl.timestamp().onUpdate(sl.sql('NOW()'))
-- 日期时间
scheduled_at = sl.datetime() -- 不带时区的日期时间
meeting_date = sl.date() -- 仅日期其他类型
lua
-- 布尔值
is_active = sl.boolean().default(true)
-- JSON 数据
metadata = sl.json() -- 存储复杂数据结构列修饰符
约束修饰符
lua
-- 主键约束
id = sl.serial().primaryKey()
-- 非空约束
name = sl.varchar(255).notNull()
-- 唯一约束
email = sl.varchar(100).unique()
identifier = sl.varchar(64).notNull().unique() -- 组合使用默认值
lua
-- 静态默认值
money = sl.int().default(1000)
is_active = sl.boolean().default(true)
role = sl.varchar(20).default('user')
-- 动态默认值
created_at = sl.timestamp().defaultNow() -- 当前时间戳
uuid = sl.varchar(36).default(sl.sql('UUID()')) -- MySQL UUID 函数自动更新
lua
-- 更新时自动设置值
updated_at = sl.timestamp().defaultNow().onUpdate(sl.sql('NOW()'))
version = sl.int().default(1).onUpdate(sl.sql('`version` + 1'))
last_modified_by = sl.varchar(64).onUpdate('system')软删除
lua
-- 软删除字段
deleted_at = sl.timestamp().softDelete()
-- 使用软删除的表会在 DELETE 操作时自动转为 UPDATE
-- 查询时会自动过滤已删除记录外键关系
lua
-- 定义外键引用
player_id = sl.int().notNull().references(players.id)
category_id = sl.int().references(categories.id)
-- 注意:这主要用于 CLI 工具生成 SQL 时的参考注释
lua
-- 添加列注释(会传播到 IDE 和生成的 SQL)
id = sl.serial().primaryKey().comment('玩家唯一标识符')
money = sl.decimal(10, 2).default(1000.00).comment('玩家现金余额')Schema 模式
单文件 Schema
lua
-- server/schema.lua
local sl = Sleet
-- 定义所有表
local players = sl.table('players', { /* ... */ })
local items = sl.table('items', { /* ... */ })
local transactions = sl.table('transactions', { /* ... */ })
-- 统一导出
return {
players = players,
items = items,
transactions = transactions
}分模块 Schema
lua
-- server/schemas/players.lua
local sl = Sleet
return sl.table('players', {
id = sl.serial().primaryKey(),
identifier = sl.varchar(64).notNull().unique(),
name = sl.varchar(255).notNull(),
-- ... 其他字段
})lua
-- server/schemas/items.lua
local sl = Sleet
return sl.table('items', {
id = sl.serial().primaryKey(),
name = sl.varchar(100).notNull(),
price = sl.decimal(8, 2),
-- ... 其他字段
})lua
-- server/schema.lua(主文件)
return {
players = require 'server.schemas.players',
items = require 'server.schemas.items'
}类型推断
当使用 sleet generate CLI 工具后,Sleet 会为每个表生成对应的类型定义:
lua
-- 生成的类型(.sleet/types.lua)
---@class PlayersRecord
---@field id integer 玩家唯一标识符
---@field identifier string Steam/Discord ID
---@field name string 显示名称
---@field money number 现金
---@field is_active boolean 账户激活状态
---@field created_at string 创建时间
---@class PlayersTable
---@field id ColumnDef<integer>
---@field identifier ColumnDef<string>
---@field name ColumnDef<string>
-- ... 其他字段使用时自动获得类型推断:
lua
local sl = Sleet
local s = require 'server.schema'
local db = sl.connect()
-- 自动推断返回 PlayersRecord[]
local players = db.select().from(s.players).execute()
local player = players[1] -- player: PlayersRecord
-- 字段访问有类型检查
print(player.name) -- string
print(player.money) -- number
print(player.is_active) -- boolean高级特性
条件字段
lua
-- 根据环境使用不同的字段定义
local function createUserTable(isProd)
local fields = {
id = sl.serial().primaryKey(),
name = sl.varchar(255).notNull()
}
if not isProd then
-- 开发环境添加调试字段
fields.debug_info = sl.json()
end
return sl.table('users', fields)
end表继承模式
lua
-- 基础字段
local function baseFields()
return {
id = sl.serial().primaryKey(),
created_at = sl.timestamp().defaultNow(),
updated_at = sl.timestamp().defaultNow().onUpdate(sl.sql('NOW()'))
}
end
-- 继承基础字段
local players = sl.table('players', vim.tbl_extend('force', baseFields(), {
identifier = sl.varchar(64).notNull().unique(),
name = sl.varchar(255).notNull()
}))