Skip to content

基础用法

本指南将带您了解 Sleet ORM 的基本用法,从定义表结构到执行数据库操作。

快速开始

定义 Schema

首先创建一个 schema 文件来定义您的表结构:

lua
-- server/schema.lua
local sl = Sleet

local players = sl.table('players', {
    id         = sl.serial().primaryKey().comment('玩家自增ID'),
    identifier = sl.varchar(64).notNull().unique().comment('Steam / Discord 标识符'),
    name       = sl.varchar(255).notNull().comment('玩家名称'),
    money      = sl.int().default(500).comment('现金'),
    bank       = sl.int().default(2500).comment('银行余额'),
    is_admin   = sl.boolean().default(false).comment('管理员标志'),
    metadata   = sl.json().comment('扩展数据'),
    last_seen  = sl.timestamp().defaultNow().comment('最后在线时间'),
})

-- 导出 schema 供其他脚本使用
return { players = players }

基本查询操作

在您的业务逻辑脚本中使用 schema:

lua
-- server/main.lua
local sl = Sleet
local s  = require 'server.schema'
local db = sl.connect()

-- SELECT 查询
local rows = db.select()
    .from(s.players)
    .where(sl.eq(s.players.identifier, identifier))
    .limit(1)
    .execute()

local player = rows[1]  -- 获取第一个结果

数据库操作

SELECT 查询

查询所有记录

lua
-- 查询所有玩家
local allPlayers = db.select().from(s.players).execute()

条件查询

lua
-- 根据 ID 查询单个玩家
local player = db.select()
    .from(s.players)
    .where(sl.eq(s.players.id, 123))
    .execute()[1]

-- 查询管理员
local admins = db.select()
    .from(s.players)
    .where(sl.eq(s.players.is_admin, true))
    .execute()

-- 复杂条件查询
local richPlayers = db.select()
    .from(s.players)
    .where(sl.and_(
        sl.gte(s.players.money, 10000),
        sl.gte(s.players.bank, 50000)
    ))
    .execute()

指定查询列

lua
-- 只查询特定字段
local playerNames = db.select({ s.players.id, s.players.name })
    .from(s.players)
    .execute()

排序和分页

lua
-- 按名称排序
local sortedPlayers = db.select()
    .from(s.players)
    .orderBy(s.players.name, 'asc')
    .execute()

-- 分页查询
local page2Players = db.select()
    .from(s.players)
    .limit(20)
    .offset(40)
    .execute()

INSERT 操作

插入单条记录

lua
-- 新建玩家
local newPlayerId = db.insert(s.players)
    .values({
        identifier = 'steam:110000103fa6cc0',
        name = GetPlayerName(source)
    })
    .execute()

print("新玩家 ID:", newPlayerId)

批量插入(如果支持)

lua
-- 批量插入多个玩家
local playerIds = db.insert(s.players)
    .values({
        { identifier = 'steam:001', name = '玩家1' },
        { identifier = 'steam:002', name = '玩家2' },
        { identifier = 'steam:003', name = '玩家3' }
    })
    .execute()

UPDATE 操作

基本更新

lua
-- 更新玩家金钱
local affected = db.update(s.players)
    .set({ money = 5000, bank = 10000 })
    .where(sl.eq(s.players.identifier, identifier))
    .execute()

print("更新了", affected, "行记录")

原子操作

lua
-- 安全地增加金钱(防止并发问题)
db.update(s.players)
    .set({ 
        money = sl.sql('`money` + ?', { 1000 }),
        bank = sl.sql('`bank` + ?', { 500 })
    })
    .where(sl.eq(s.players.id, playerId))
    .execute()

更新 JSON 字段

lua
-- 更新玩家元数据
db.update(s.players)
    .set({ 
        metadata = {
            last_position = { x = 100, y = 200, z = 30 },
            playtime = 3600,
            achievements = { 'first_login', 'tutorial_complete' }
        }
    })
    .where(sl.eq(s.players.id, playerId))
    .execute()

DELETE 操作

删除记录

lua
-- 删除玩家
local deleted = db.delete(s.players)
    .where(sl.eq(s.players.id, playerId))
    .execute()

print("删除了", deleted, "行记录")

批量删除

lua
-- 删除长时间未登录的玩家
db.delete(s.players)
    .where(sl.lt(s.players.last_seen, '2024-01-01'))
    .execute()

常用操作符

比较操作符

lua
-- 等于
sl.eq(s.players.name, '张三')

-- 不等于
sl.ne(s.players.status, 'banned')

-- 大于/小于
sl.gt(s.players.money, 1000)
sl.gte(s.players.level, 5)
sl.lt(s.players.age, 60)
sl.lte(s.players.warnings, 3)

字符串操作符

lua
-- 模糊匹配
sl.like(s.players.name, '%张%')

-- 不匹配
sl.notLike(s.players.identifier, 'discord:%')

NULL 检查

lua
-- 检查 NULL
sl.isNull(s.players.banned_until)

-- 检查非 NULL
sl.isNotNull(s.players.last_seen)

范围操作符

lua
-- IN 查询
sl.inArray(s.players.role, { 'admin', 'moderator', 'vip' })

-- NOT IN
sl.notInArray(s.players.status, { 'banned', 'suspended' })

-- BETWEEN
sl.between(s.players.money, 1000, 10000)

逻辑操作符

lua
-- AND 条件
sl.and_(
    sl.eq(s.players.is_active, true),
    sl.gte(s.players.level, 10)
)

-- OR 条件
sl.or_(
    sl.eq(s.players.is_admin, true),
    sl.eq(s.players.is_moderator, true)
)

-- NOT 条件
sl.not_(sl.eq(s.players.is_banned, true))

高级功能

JOIN 查询

lua
-- 假设有订单表
local orders = sl.table('orders', {
    id = sl.serial().primaryKey(),
    player_id = sl.int().references(s.players.id),
    item_name = sl.varchar(255),
    price = sl.decimal(10, 2)
})

-- JOIN 查询
local playerOrders = db.select()
    .from(s.orders)
    .leftJoin(s.players, sl.eq(s.orders.player_id, s.players.id))
    .where(sl.eq(s.players.identifier, identifier))
    .execute()

聚合查询

lua
-- 统计查询(需要手动类型注解)
---@type { total: integer, avg_money: number }[]
local stats = db.select({
    sl.sql('COUNT(*) AS total'),
    sl.sql('AVG(`money`) AS avg_money')
}).from(s.players).execute()

local playerCount = stats[1].total
local averageMoney = stats[1].avg_money

调试查询

lua
-- 查看生成的 SQL
local sql, params = db.select()
    .from(s.players)
    .where(sl.eq(s.players.id, 123))
    .toSQL()

print("SQL:", sql)
print("参数:", json.encode(params))
-- 输出: SQL: SELECT * FROM `players` WHERE `players`.`id` = ?
--       参数: [123]

实用示例

玩家系统

lua
-- 获取或创建玩家
function GetOrCreatePlayer(identifier, name)
    -- 先尝试查找现有玩家
    local existing = db.select()
        .from(s.players)
        .where(sl.eq(s.players.identifier, identifier))
        .limit(1)
        .execute()[1]
    
    if existing then
        -- 更新最后登录时间
        db.update(s.players)
            .set({ last_seen = sl.sql('NOW()') })
            .where(sl.eq(s.players.id, existing.id))
            .execute()
        return existing
    else
        -- 创建新玩家
        local newId = db.insert(s.players)
            .values({
                identifier = identifier,
                name = name,
                last_seen = sl.sql('NOW()')
            })
            .execute()
        
        -- 返回新创建的玩家
        return db.select()
            .from(s.players)
            .where(sl.eq(s.players.id, newId))
            .execute()[1]
    end
end

金钱转账

lua
function TransferMoney(fromId, toId, amount)
    -- 开始事务(需要 oxmysql 支持)
    MySQL.transaction({
        -- 扣除发送方金钱
        {
            query = db.update(s.players)
                .set({ money = sl.sql('`money` - ?', { amount }) })
                .where(sl.and_(
                    sl.eq(s.players.id, fromId),
                    sl.gte(s.players.money, amount)
                ))
                .toSQL()
        },
        -- 增加接收方金钱
        {
            query = db.update(s.players)
                .set({ money = sl.sql('`money` + ?', { amount }) })
                .where(sl.eq(s.players.id, toId))
                .toSQL()
        }
    }, function(success)
        if success then
            print("转账成功")
        else
            print("转账失败")
        end
    end)
end

下一步

现在您已经掌握了基础用法:

Released under the MIT License.