Skip to content

操作符

Sleet ORM 提供了完整的操作符集合,用于构建类型安全的查询条件。所有操作符都会自动处理参数绑定,防止 SQL 注入攻击。

比较操作符

基本比较

lua
local sl = Sleet
local db = sl.connect()

-- 等于
local player = db.select()
    .from(s.players)
    .where(sl.eq(s.players.id, 123))
    .execute()[1]

-- 不等于
local activePlayers = db.select()
    .from(s.players)
    .where(sl.ne(s.players.status, 'banned'))
    .execute()

-- 大于
local highLevelPlayers = db.select()
    .from(s.players)
    .where(sl.gt(s.players.level, 50))
    .execute()

-- 大于等于
local eligiblePlayers = db.select()
    .from(s.players)
    .where(sl.gte(s.players.age, 18))
    .execute()

-- 小于
local newPlayers = db.select()
    .from(s.players)
    .where(sl.lt(s.players.level, 10))
    .execute()

-- 小于等于
local moderateWarnings = db.select()
    .from(s.players)
    .where(sl.lte(s.players.warnings, 3))
    .execute()

操作符对照表

操作符SQL描述示例
sl.eq(col, val)=等于sl.eq(s.players.name, 'John')
sl.ne(col, val)!=不等于sl.ne(s.players.status, 'banned')
sl.gt(col, val)>大于sl.gt(s.players.level, 10)
sl.gte(col, val)>=大于等于sl.gte(s.players.money, 1000)
sl.lt(col, val)<小于sl.lt(s.players.age, 60)
sl.lte(col, val)<=小于等于sl.lte(s.players.warnings, 5)

字符串操作符

模糊匹配

lua
-- LIKE 模糊匹配
local playersWithJohn = db.select()
    .from(s.players)
    .where(sl.like(s.players.name, '%John%'))
    .execute()

-- 以特定字符串开头
local steamPlayers = db.select()
    .from(s.players)
    .where(sl.like(s.players.identifier, 'steam:%'))
    .execute()

-- 以特定字符串结尾
local gmailUsers = db.select()
    .from(s.players)
    .where(sl.like(s.players.email, '%@gmail.com'))
    .execute()

-- NOT LIKE 不匹配
local nonDiscordPlayers = db.select()
    .from(s.players)
    .where(sl.notLike(s.players.identifier, 'discord:%'))
    .execute()

-- ILIKE 大小写不敏感匹配(MySQL 默认不区分大小写)
local caseInsensitive = db.select()
    .from(s.players)
    .where(sl.ilike(s.players.name, '%JOHN%'))
    .execute()

字符串操作符对照表

操作符SQL描述示例
sl.like(col, pattern)LIKE模糊匹配sl.like(s.players.name, '%John%')
sl.notLike(col, pattern)NOT LIKE不匹配sl.notLike(s.players.email, '%spam%')
sl.ilike(col, pattern)LIKE大小写不敏感匹配sl.ilike(s.players.name, '%ADMIN%')

通配符说明

lua
-- % 匹配零个或多个字符
sl.like(s.players.name, 'John%')    -- 以 'John' 开头
sl.like(s.players.name, '%Smith')   -- 以 'Smith' 结尾
sl.like(s.players.name, '%John%')   -- 包含 'John'

-- _ 匹配单个字符
sl.like(s.players.code, 'A_B')      -- A 和 B 之间有一个字符
sl.like(s.players.phone, '138____1234') -- 特定格式的手机号

NULL 检查操作符

lua
-- 检查 NULL 值
local playersWithoutEmail = db.select()
    .from(s.players)
    .where(sl.isNull(s.players.email))
    .execute()

-- 检查非 NULL 值
local playersWithEmail = db.select()
    .from(s.players)
    .where(sl.isNotNull(s.players.email))
    .execute()

-- 查找未被封禁的玩家(banned_until 为 NULL)
local activePlayers = db.select()
    .from(s.players)
    .where(sl.isNull(s.players.banned_until))
    .execute()

-- 查找当前被封禁的玩家
local bannedPlayers = db.select()
    .from(s.players)
    .where(sl.isNotNull(s.players.banned_until))
    .execute()

NULL 操作符对照表

操作符SQL描述示例
sl.isNull(col)IS NULL值为空sl.isNull(s.players.deleted_at)
sl.isNotNull(col)IS NOT NULL值不为空sl.isNotNull(s.players.email)

范围操作符

IN 和 NOT IN

lua
-- IN 查询 - 值在指定列表中
local vipPlayers = db.select()
    .from(s.players)
    .where(sl.inArray(s.players.role, { 'admin', 'moderator', 'vip' }))
    .execute()

-- 查找特定等级的玩家
local specificLevels = db.select()
    .from(s.players)
    .where(sl.inArray(s.players.level, { 10, 20, 30, 40, 50 }))
    .execute()

-- NOT IN 查询 - 值不在指定列表中
local normalPlayers = db.select()
    .from(s.players)
    .where(sl.notInArray(s.players.status, { 'banned', 'suspended', 'deleted' }))
    .execute()

-- 排除特定 ID
local otherPlayers = db.select()
    .from(s.players)
    .where(sl.notInArray(s.players.id, { 1, 2, 3 }))
    .execute()

BETWEEN

lua
-- BETWEEN 范围查询
local middleAged = db.select()
    .from(s.players)
    .where(sl.between(s.players.age, 25, 65))
    .execute()

-- 特定时间范围
local recentPlayers = db.select()
    .from(s.players)
    .where(sl.between(s.players.created_at, '2024-01-01', '2024-12-31'))
    .execute()

-- 金钱范围
local middleClass = db.select()
    .from(s.players)
    .where(sl.between(s.players.money, 10000, 100000))
    .execute()

范围操作符对照表

操作符SQL描述示例
sl.inArray(col, values)IN (...)值在列表中sl.inArray(s.players.role, {'admin', 'user'})
sl.notInArray(col, values)NOT IN (...)值不在列表中sl.notInArray(s.players.status, {'banned'})
sl.between(col, min, max)BETWEEN ... AND ...值在范围内sl.between(s.players.level, 10, 50)

逻辑操作符

AND 逻辑

lua
-- AND - 所有条件都必须满足
local activeVipPlayers = db.select()
    .from(s.players)
    .where(sl.and_(
        sl.eq(s.players.is_active, true),
        sl.eq(s.players.is_vip, true),
        sl.gte(s.players.level, 10)
    ))
    .execute()

-- 复杂 AND 条件
local specificPlayers = db.select()
    .from(s.players)
    .where(sl.and_(
        sl.like(s.players.name, 'John%'),
        sl.gte(s.players.money, 5000),
        sl.lte(s.players.warnings, 2),
        sl.isNotNull(s.players.email)
    ))
    .execute()

OR 逻辑

lua
-- OR - 任一条件满足即可
local privilegedPlayers = db.select()
    .from(s.players)
    .where(sl.or_(
        sl.eq(s.players.is_admin, true),
        sl.eq(s.players.is_moderator, true),
        sl.gte(s.players.level, 100)
    ))
    .execute()

-- 多种状态查询
local availablePlayers = db.select()
    .from(s.players)
    .where(sl.or_(
        sl.eq(s.players.status, 'online'),
        sl.eq(s.players.status, 'idle'),
        sl.eq(s.players.status, 'away')
    ))
    .execute()

NOT 逻辑

lua
-- NOT - 条件取反
local notBannedPlayers = db.select()
    .from(s.players)
    .where(sl.not_(sl.eq(s.players.is_banned, true)))
    .execute()

-- 等价于
local notBannedPlayers2 = db.select()
    .from(s.players)
    .where(sl.eq(s.players.is_banned, false))
    .execute()

-- 复杂 NOT 条件
local exceptionalPlayers = db.select()
    .from(s.players)
    .where(sl.not_(sl.and_(
        sl.lt(s.players.level, 10),
        sl.eq(s.players.is_premium, false)
    )))
    .execute()

逻辑操作符对照表

操作符SQL描述示例
sl.and_(cond1, cond2, ...)AND所有条件都成立sl.and_(sl.eq(...), sl.gt(...))
sl.or_(cond1, cond2, ...)OR任一条件成立sl.or_(sl.eq(...), sl.eq(...))
sl.not_(condition)NOT条件取反sl.not_(sl.eq(s.players.active, false))

复杂条件组合

嵌套逻辑

lua
-- 复杂的条件组合
local targetPlayers = db.select()
    .from(s.players)
    .where(sl.and_(
        -- 基本活跃条件
        sl.eq(s.players.is_active, true),
        sl.isNull(s.players.deleted_at),
        
        -- 复杂的权限或等级条件
        sl.or_(
            -- 管理员或版主
            sl.or_(
                sl.eq(s.players.is_admin, true),
                sl.eq(s.players.is_moderator, true)
            ),
            -- 或者高等级VIP
            sl.and_(
                sl.eq(s.players.is_vip, true),
                sl.gte(s.players.level, 50)
            ),
            -- 或者富有的普通玩家
            sl.and_(
                sl.gte(s.players.money, 100000),
                sl.gte(s.players.bank, 500000)
            )
        )
    ))
    .execute()

动态条件构建

lua
-- 根据参数动态构建查询条件
function FindPlayers(filters)
    local conditions = {}
    
    -- 基础条件:非删除用户
    table.insert(conditions, sl.isNull(s.players.deleted_at))
    
    -- 可选条件
    if filters.name then
        table.insert(conditions, sl.like(s.players.name, '%' .. filters.name .. '%'))
    end
    
    if filters.minLevel then
        table.insert(conditions, sl.gte(s.players.level, filters.minLevel))
    end
    
    if filters.maxLevel then
        table.insert(conditions, sl.lte(s.players.level, filters.maxLevel))
    end
    
    if filters.roles and #filters.roles > 0 then
        table.insert(conditions, sl.inArray(s.players.role, filters.roles))
    end
    
    if filters.isActive ~= nil then
        table.insert(conditions, sl.eq(s.players.is_active, filters.isActive))
    end
    
    -- 组合所有条件
    local whereClause = (#conditions == 1) and conditions[1] or sl.and_(table.unpack(conditions))
    
    return db.select()
        .from(s.players)
        .where(whereClause)
        .execute()
end

-- 使用示例
local results = FindPlayers({
    name = 'John',
    minLevel = 10,
    roles = { 'admin', 'moderator' },
    isActive = true
})

实用示例

用户筛选系统

lua
-- 查找活跃的高等级用户
local elitePlayers = db.select()
    .from(s.players)
    .where(sl.and_(
        sl.eq(s.players.is_active, true),
        sl.gte(s.players.level, 80),
        sl.gte(s.players.playtime, 100), -- 游戏时间超过100小时
        sl.lte(s.players.warnings, 1)    -- 警告少于等于1次
    ))
    .execute()

-- 查找需要关注的用户
local concernUsers = db.select()
    .from(s.players)
    .where(sl.or_(
        sl.gte(s.players.warnings, 3),   -- 警告过多
        sl.like(s.players.last_action, '%suspicious%'), -- 可疑行为
        sl.and_(
            sl.lt(s.players.playtime, 5),    -- 游戏时间短
            sl.gte(s.players.money, 50000)   -- 但金钱很多
        )
    ))
    .execute()

商品查询系统

lua
-- 查找热门商品
local popularItems = db.select()
    .from(s.items)
    .where(sl.and_(
        sl.eq(s.items.is_available, true),
        sl.gte(s.items.sales_count, 100),
        sl.between(s.items.price, 10, 1000),
        sl.inArray(s.items.category, { 'weapons', 'vehicles', 'clothing' })
    ))
    .execute()

-- 查找促销商品
local saleItems = db.select()
    .from(s.items)
    .where(sl.and_(
        sl.eq(s.items.is_available, true),
        sl.or_(
            sl.isNotNull(s.items.discount_price),
            sl.like(s.items.name, '%Sale%'),
            sl.like(s.items.description, '%限时%')
        )
    ))
    .execute()

时间范围查询

lua
-- 查找最近登录的用户
local recentUsers = db.select()
    .from(s.players)
    .where(sl.and_(
        sl.gte(s.players.last_login, '2024-01-01'),
        sl.isNotNull(s.players.last_login)
    ))
    .execute()

-- 查找长期未登录用户
local inactiveUsers = db.select()
    .from(s.players)
    .where(sl.or_(
        sl.lt(s.players.last_login, '2023-01-01'),
        sl.isNull(s.players.last_login)
    ))
    .execute()

最佳实践

1. 合理使用索引

lua
-- 好的做法:在有索引的字段上使用精确匹配
db.select()
    .from(s.players)
    .where(sl.eq(s.players.identifier, identifier))  -- identifier 通常有唯一索引
    .execute()

-- 避免:在大表上使用 LIKE 开头通配符
-- db.select().from(s.players).where(sl.like(s.players.name, '%John%'))
-- 更好的做法是使用全文搜索或专门的搜索字段

2. 条件顺序优化

lua
-- 将最具选择性的条件放在前面
db.select()
    .from(s.players)
    .where(sl.and_(
        sl.eq(s.players.identifier, identifier),  -- 最具选择性(唯一)
        sl.eq(s.players.is_active, true),        -- 中等选择性
        sl.isNotNull(s.players.name)             -- 选择性最低
    ))
    .execute()

3. 避免复杂嵌套

lua
-- 复杂条件可以分解为多个查询或使用临时变量
local roleCondition = sl.inArray(s.players.role, { 'admin', 'moderator' })
local levelCondition = sl.gte(s.players.level, 50)
local moneyCondition = sl.gte(s.players.money, 100000)

local finalCondition = sl.and_(
    sl.eq(s.players.is_active, true),
    sl.or_(roleCondition, levelCondition, moneyCondition)
)

local results = db.select()
    .from(s.players)
    .where(finalCondition)
    .execute()

4. 参数安全

lua
-- 正确:使用参数绑定(自动防护)
local userInput = "John'; DROP TABLE users; --"
db.select()
    .from(s.players)
    .where(sl.eq(s.players.name, userInput))  -- 安全,自动转义
    .execute()

-- 错误:直接拼接 SQL
-- local sql = "SELECT * FROM players WHERE name = '" .. userInput .. "'"
-- 这样会导致 SQL 注入漏洞

下一步

Released under the MIT License.