Skip to content

列类型

Sleet ORM 提供了丰富的列类型定义,支持 MySQL 的所有常用数据类型,并提供了类型安全的 Lua 接口。

整数类型

自增整数

lua
-- 自增主键(常用于 ID 字段)
local users = sl.table('users', {
    id = sl.serial().primaryKey(),        -- INT AUTO_INCREMENT PRIMARY KEY
    big_id = sl.bigserial().primaryKey()  -- BIGINT AUTO_INCREMENT PRIMARY KEY
})

普通整数

lua
local products = sl.table('products', {
    id = sl.serial().primaryKey(),
    price = sl.int().notNull(),           -- INT NOT NULL
    stock = sl.bigint().default(0),       -- BIGINT DEFAULT 0
    category_id = sl.smallint(),          -- SMALLINT
    is_featured = sl.tinyint().default(0) -- TINYINT DEFAULT 0
})
类型MySQL 类型范围用途
serial()INT AUTO_INCREMENT-2,147,483,648 到 2,147,483,647主键 ID
bigserial()BIGINT AUTO_INCREMENT-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807大表主键
int()INT-2,147,483,648 到 2,147,483,647常规整数
bigint()BIGINT-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807大整数
smallint()SMALLINT-32,768 到 32,767小整数
tinyint()TINYINT-128 到 127微整数

浮点类型

lua
local measurements = sl.table('measurements', {
    id = sl.serial().primaryKey(),
    temperature = sl.float(),                    -- FLOAT
    precision_value = sl.double(),               -- DOUBLE
    price = sl.decimal(10, 2).notNull(),         -- DECIMAL(10,2) NOT NULL
    percentage = sl.decimal(5, 4).default(0.0)   -- DECIMAL(5,4) DEFAULT 0.0
})
类型MySQL 类型精度用途
float()FLOAT单精度一般浮点数
double()DOUBLE双精度高精度浮点数
decimal(p, s)DECIMAL(p,s)精确金钱、精确计算

decimal() 参数说明

lua
-- decimal(precision, scale)
-- precision: 总位数(包括小数点前后)
-- scale: 小数点后位数

sl.decimal(10, 2)  -- 最大 99999999.99
sl.decimal(5, 4)   -- 最大 9.9999
sl.decimal()       -- 默认 DECIMAL(10,2)

字符串类型

lua
local users = sl.table('users', {
    id = sl.serial().primaryKey(),
    username = sl.varchar(50).notNull().unique(),    -- VARCHAR(50) NOT NULL UNIQUE
    password_hash = sl.varchar(255).notNull(),       -- VARCHAR(255) NOT NULL
    status = sl.char(1).default('A'),                -- CHAR(1) DEFAULT 'A'
    bio = sl.text(),                                 -- TEXT
    description = sl.mediumtext(),                   -- MEDIUMTEXT
    content = sl.longtext()                          -- LONGTEXT
})
类型MySQL 类型最大长度用途
varchar(len)VARCHAR(len)65,535 字节变长字符串
char(len)CHAR(len)255 字符定长字符串
text()TEXT65,535 字符短文本
mediumtext()MEDIUMTEXT16,777,215 字符中等文本
longtext()LONGTEXT4,294,967,295 字符长文本

字符串类型选择建议

lua
-- 短字符串,长度固定或变化不大
sl.varchar(50)    -- 用户名、邮箱等
sl.char(2)        -- 国家代码、状态码等

-- 长文本内容
sl.text()         -- 评论、简短描述
sl.mediumtext()   -- 文章内容
sl.longtext()     -- 大型文档、JSON 数据

布尔类型

lua
local players = sl.table('players', {
    id = sl.serial().primaryKey(),
    is_admin = sl.boolean().default(false),      -- TINYINT(1) DEFAULT 0
    is_active = sl.boolean().notNull(),          -- TINYINT(1) NOT NULL
    is_banned = sl.boolean().default(false)      -- TINYINT(1) DEFAULT 0
})

注意:MySQL 没有原生的 BOOLEAN 类型,sl.boolean() 会转换为 TINYINT(1),其中 0 表示 false,1 表示 true。

时间类型

lua
local events = sl.table('events', {
    id = sl.serial().primaryKey(),
    created_at = sl.timestamp().defaultNow(),           -- TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    updated_at = sl.timestamp().onUpdate(sl.sql('NOW()')), -- TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
    scheduled_at = sl.datetime().notNull(),             -- DATETIME NOT NULL
    event_date = sl.date(),                             -- DATE
    deleted_at = sl.timestamp().softDelete()            -- 软删除时间戳
})
类型MySQL 类型格式用途
timestamp()TIMESTAMPYYYY-MM-DD HH:MM:SS时间戳,自动时区转换
datetime()DATETIMEYYYY-MM-DD HH:MM:SS日期时间,不转换时区
date()DATEYYYY-MM-DD仅日期

时间类型使用示例

lua
-- 自动时间戳
local posts = sl.table('posts', {
    id = sl.serial().primaryKey(),
    title = sl.varchar(255).notNull(),
    created_at = sl.timestamp().defaultNow(),
    updated_at = sl.timestamp()
        .defaultNow()
        .onUpdate(sl.sql('CURRENT_TIMESTAMP'))
})

-- 软删除支持
local users = sl.table('users', {
    id = sl.serial().primaryKey(),
    name = sl.varchar(255).notNull(),
    deleted_at = sl.timestamp().softDelete()
})

JSON 类型

lua
local players = sl.table('players', {
    id = sl.serial().primaryKey(),
    metadata = sl.json(),                    -- JSON 或 LONGTEXT(根据 MySQL 版本)
    settings = sl.json().default('{}'),      -- JSON DEFAULT '{}'
    inventory = sl.json().notNull()          -- JSON NOT NULL
})

JSON 数据操作

lua
-- 插入 JSON 数据
db.insert(s.players)
    .values({
        name = 'Player1',
        metadata = {
            level = 10,
            achievements = { 'first_login', 'tutorial_complete' },
            position = { x = 100, y = 200, z = 30 }
        }
    })
    .execute()

-- 更新 JSON 数据
db.update(s.players)
    .set({
        metadata = {
            level = 15,
            last_position = { x = 150, y = 250, z = 35 }
        }
    })
    .where(sl.eq(s.players.id, playerId))
    .execute()

注意:如果 MySQL 版本不支持 JSON 类型,会自动降级为 LONGTEXT 类型。

列修饰符

所有列类型都支持以下修饰符方法:

基本约束

lua
local users = sl.table('users', {
    id = sl.serial().primaryKey(),              -- 主键
    email = sl.varchar(255)
        .notNull()                              -- 非空
        .unique(),                              -- 唯一
    name = sl.varchar(255)
        .notNull()
        .comment('用户姓名'),                    -- 注释
    status = sl.varchar(20)
        .default('active')                      -- 默认值
})

外键关系

lua
local orders = sl.table('orders', {
    id = sl.serial().primaryKey(),
    user_id = sl.int()
        .notNull()
        .references(s.users.id),                -- 外键引用
    total = sl.decimal(10, 2).notNull()
})

时间相关

lua
local posts = sl.table('posts', {
    id = sl.serial().primaryKey(),
    created_at = sl.timestamp().defaultNow(),   -- 默认当前时间
    updated_at = sl.timestamp()
        .defaultNow()
        .onUpdate(sl.sql('NOW()'))             -- 更新时自动设置
})

软删除

lua
local users = sl.table('users', {
    id = sl.serial().primaryKey(),
    name = sl.varchar(255).notNull(),
    deleted_at = sl.timestamp().softDelete()    -- 软删除标记
})

修饰符方法参考

方法参数描述
primaryKey()设置为主键(自动添加 NOT NULL)
notNull()非空约束
unique()唯一约束
default(value)value: any设置默认值
defaultNow()默认当前时间(仅时间类型)
autoIncrement()自动递增
references(column)column: 列定义外键引用
onUpdate(value)value: any更新时的值
softDelete()标记为软删除字段
comment(text)text: string添加列注释

完整示例

lua
local sl = Sleet

-- 用户表
local users = sl.table('users', {
    id = sl.serial().primaryKey().comment('用户ID'),
    identifier = sl.varchar(64).notNull().unique().comment('Steam/Discord标识符'),
    name = sl.varchar(255).notNull().comment('用户名'),
    email = sl.varchar(255).unique().comment('邮箱地址'),
    password_hash = sl.varchar(255).comment('密码哈希'),
    is_admin = sl.boolean().default(false).comment('管理员标志'),
    is_active = sl.boolean().default(true).comment('激活状态'),
    level = sl.int().default(1).comment('用户等级'),
    experience = sl.bigint().default(0).comment('经验值'),
    balance = sl.decimal(15, 2).default(0.00).comment('账户余额'),
    metadata = sl.json().comment('扩展数据'),
    last_login = sl.timestamp().comment('最后登录时间'),
    created_at = sl.timestamp().defaultNow().comment('创建时间'),
    updated_at = sl.timestamp().defaultNow().onUpdate(sl.sql('NOW()')).comment('更新时间'),
    deleted_at = sl.timestamp().softDelete().comment('软删除时间')
})

-- 订单表(展示外键关系)
local orders = sl.table('orders', {
    id = sl.serial().primaryKey(),
    user_id = sl.int().notNull().references(users.id),
    order_number = sl.varchar(50).notNull().unique(),
    total_amount = sl.decimal(10, 2).notNull(),
    status = sl.varchar(20).default('pending'),
    items = sl.json(),
    created_at = sl.timestamp().defaultNow(),
    updated_at = sl.timestamp().defaultNow().onUpdate(sl.sql('NOW()'))
})

return { users = users, orders = orders }

最佳实践

1. 选择合适的数据类型

lua
-- 好的实践
local users = sl.table('users', {
    id = sl.serial().primaryKey(),              -- 自增主键
    status = sl.varchar(20),                    -- 状态用短字符串
    age = sl.tinyint(),                        -- 年龄用小整数
    balance = sl.decimal(15, 2),               -- 金钱用精确小数
    settings = sl.json()                       -- 配置用 JSON
})

-- 避免的做法
local bad_users = sl.table('bad_users', {
    id = sl.varchar(255).primaryKey(),         -- 避免:字符串主键性能差
    status = sl.text(),                        -- 避免:短字符串用TEXT浪费空间
    age = sl.bigint(),                         -- 避免:小数值用大整数浪费空间
    balance = sl.float(),                      -- 避免:金钱计算用浮点数不精确
})

2. 合理使用索引

lua
local users = sl.table('users', {
    id = sl.serial().primaryKey(),             -- 自动创建主键索引
    identifier = sl.varchar(64).unique(),      -- 自动创建唯一索引
    email = sl.varchar(255).unique(),          -- 经常查询的字段创建唯一索引
    name = sl.varchar(255),                    -- 如果经常按名称搜索,考虑添加索引
    created_at = sl.timestamp().defaultNow()   -- 如果按时间排序,考虑添加索引
})

3. 使用适当的默认值

lua
local users = sl.table('users', {
    id = sl.serial().primaryKey(),
    is_active = sl.boolean().default(true),     -- 新用户默认激活
    level = sl.int().default(1),               -- 新用户从等级1开始
    balance = sl.decimal(15, 2).default(0.00), -- 初始余额为0
    created_at = sl.timestamp().defaultNow(),  -- 自动设置创建时间
    metadata = sl.json().default('{}')         -- 空JSON对象
})

下一步

Released under the MIT License.